From c2ce914541e694c7d1c8853b88936095e8b9ede4 Mon Sep 17 00:00:00 2001 From: miriame Date: Wed, 13 Feb 2019 15:17:26 +0200 Subject: Add 'Service Dependencies' tab in composition page Issue-ID: SDC-1987 Change-Id: Ib5b688c12234c81fe6f89b2b5d37dd16a75b0db9 Signed-off-by: miriame --- catalog-ui/src/app/ng2/app.module.ts | 6 +- .../service-dependencies.component.html | 35 +++ .../service-dependencies.component.less | 70 +++++ .../service-dependencies.component.ts | 325 +++++++++++++++++++++ .../service-dependencies.module.ts | 24 ++ .../dynamic-element/dynamic-element.component.ts | 8 +- .../checkbox/checkbox.component.less | 13 +- .../service-dependencies-editor.component.html | 56 ++++ .../service-dependencies-editor.component.less | 43 +++ .../service-dependencies-editor.component.ts | 192 ++++++++++++ .../service-dependencies-editor.module.ts | 25 ++ .../component-services/component.service.ts | 44 ++- .../responses/component-generic-response.ts | 4 + 13 files changed, 835 insertions(+), 10 deletions(-) create mode 100644 catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.component.html create mode 100644 catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.component.less create mode 100644 catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.component.ts create mode 100644 catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.module.ts create mode 100644 catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component.html create mode 100644 catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component.less create mode 100644 catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component.ts create mode 100644 catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.module.ts (limited to 'catalog-ui/src/app/ng2') diff --git a/catalog-ui/src/app/ng2/app.module.ts b/catalog-ui/src/app/ng2/app.module.ts index 750563b092..1ae2df2d82 100644 --- a/catalog-ui/src/app/ng2/app.module.ts +++ b/catalog-ui/src/app/ng2/app.module.ts @@ -60,6 +60,8 @@ import { ServicePathCreatorModule } from './pages/service-path-creator/service-p import { ServicePathsListModule } from './pages/service-paths-list/service-paths-list.module'; import { ServicePathModule } from 'app/ng2/components/logic/service-path/service-path.module'; import { ServicePathSelectorModule } from 'app/ng2/components/logic/service-path-selector/service-path-selector.module'; +import {ServiceDependenciesModule} from 'app/ng2/components/logic/service-dependencies/service-dependencies.module'; +import {ServiceDependenciesEditorModule} from './pages/service-dependencies-editor/service-dependencies-editor.module'; import { CompositionPanelModule } from 'app/ng2/pages/composition/panel/panel.module'; import { WindowRef } from "./services/window.service"; import {ArchiveService} from "./services/archive.service"; @@ -110,7 +112,9 @@ export function configServiceFactory(config: ConfigService) { ServicePathCreatorModule, ServicePathsListModule, ServicePathModule, - ServicePathSelectorModule + ServicePathSelectorModule, + ServiceDependenciesModule, + ServiceDependenciesEditorModule ], exports: [], entryComponents: [ diff --git a/catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.component.html b/catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.component.html new file mode 100644 index 0000000000..d71a4fbecb --- /dev/null +++ b/catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.component.html @@ -0,0 +1,35 @@ +
+ +
+ + +
+
+ +
+
+
+ {{rule.servicePropertyName + ' ' + getSymbol(rule.constraintOperator) + ' ' + (rule.sourceName ? rule.sourceName + ':' : '') + rule.value}} +
+ +
+
+ + +
+
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.component.less b/catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.component.less new file mode 100644 index 0000000000..ae990dc85f --- /dev/null +++ b/catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.component.less @@ -0,0 +1,70 @@ +@import './../../../../../assets/styles/variables.less'; +@import './../../../../../assets/styles/variables-old.less'; +@import './../../../../../assets/styles/mixins_old.less'; +@import './../../../../../assets/styles/mixins.less'; + +.service-dependencies { + + /deep/ .checkbox-label-mark-as-dependent { + padding: 7px 18px; + position: relative; + height: 61px; + color: @main_color_a; + box-shadow: 0 2px 7px @main_color_o; + border-bottom: 1px solid @main_color_o; + .checkbox-label { + margin-top: 14px; + .checkbox-label-content { + font-size: 14px; + } + } + .checkbox-container input[type=checkbox].checkbox-hidden[disabled] ~ .checkbox-label-content { + opacity: 0.5; + } + + loader { + top: 20px; + } + } + + .i-sdc-designer-sidebar-section-content-item-rules-section { + .i-sdc-designer-sidebar-section-content-item-rule { + border-bottom: 1px solid @main_color_o; + padding: 5px 10px 5px 18px; + position: relative; + height: 61px; + display: flex; + align-items: center; + justify-content: space-between; + + .rule-details { + .s_1; + display: flex; + flex: 1; + align-items: center; + justify-content: space-between; + margin-left: 5px; + width: 180px; + .delete-icon { + visibility: hidden; + } + &:not(.readonly):hover { + .a_1; + } + &:hover .delete-icon{ + visibility: visible; + } + &.readonly { + opacity: 0.5; + } + } + .rule-desc { + .sdc-ellipsis; + width: 220px; + position: relative; + padding-right: 1em; + } + + } + } +} \ No newline at end of file diff --git a/catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.component.ts b/catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.component.ts new file mode 100644 index 0000000000..ac87576540 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.component.ts @@ -0,0 +1,325 @@ +/*! + * Copyright © 2016-2018 European Support Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +import {Component, Input, Output, EventEmitter, ComponentRef} from '@angular/core'; +import {ModalService} from 'app/ng2/services/modal.service'; +import {Service, ComponentInstance, ModalModel, ButtonModel, PropertyBEModel, ServiceInstanceObject} from 'app/models'; +import {ServiceDependenciesEditorComponent} from 'app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component'; +import {ModalComponent} from 'app/ng2/components/ui/modal/modal.component'; +import {ComponentServiceNg2} from 'app/ng2/services/component-services/component.service'; +import {TranslateService} from 'app/ng2/shared/translator/translate.service'; + +export class ConstraintObject { + servicePropertyName: string; + constraintOperator: string; + sourceType: string; + sourceName: string; + value: string; + + constructor(input?: any) { + if (input) { + this.servicePropertyName = input.servicePropertyName; + this.constraintOperator = input.constraintOperator; + this.sourceType = input.sourceType; + this.sourceName = input.sourceName; + this.value = input.value; + } + } +} + +export class ConstraintObjectUI extends ConstraintObject{ + isValidValue: boolean; + + constructor(input?: any) { + super(input); + if(input) { + this.isValidValue = input.isValidValue ? input.isValidValue : input.value !== ''; + } + } + + public updateValidity(isValidValue: boolean) { + this.isValidValue = isValidValue; + } + + public isValidRule(isStatic) { + let isValidValue = isStatic ? this.isValidValue : true; + return this.servicePropertyName != null && this.servicePropertyName !== '' + && this.value != null && this.value !== '' && isValidValue; + } +} + +export const OPERATOR_TYPES = { + EQUAL: 'equal', + GREATER_THAN: 'greater_than', + LESS_THAN: 'less_than' +}; + +class I18nTexts { + static uncheckModalTitle: string; + static uncheckModalText: string; + static modalApprove: string; + static modalCancel: string; + static modalCreate: string; + static modalSave: string; + static modalDelete: string; + static addRuleTxt: string; + static updateRuleTxt: string; + static deleteRuleTxt: string; + static deleteRuleMsg: string; + + public static translateTexts(translateService) { + I18nTexts.uncheckModalTitle = translateService.translate("SERVICE_DEPENDENCY_UNCHECK_TITLE"); + I18nTexts.uncheckModalText = translateService.translate("SERVICE_DEPENDENCY_UNCHECK_TEXT"); + I18nTexts.modalApprove = translateService.translate("MODAL_APPROVE"); + I18nTexts.modalCancel = translateService.translate("MODAL_CANCEL"); + I18nTexts.modalCreate = translateService.translate("MODAL_CREATE"); + I18nTexts.modalSave = translateService.translate("MODAL_SAVE"); + I18nTexts.modalDelete = translateService.translate("MODAL_DELETE"); + I18nTexts.addRuleTxt = translateService.translate("SERVICE_DEPENDENCY_ADD_RULE"); + I18nTexts.updateRuleTxt = translateService.translate("SERVICE_DEPENDENCY_UPDATE_RULE"); + I18nTexts.deleteRuleTxt = translateService.translate("SERVICE_DEPENDENCY_DELETE_RULE"); + I18nTexts.deleteRuleMsg = translateService.translate("SERVICE_DEPENDENCY_DELETE_RULE_MSG"); + } +} + + +@Component({ + selector: 'service-dependencies', + templateUrl: './service-dependencies.component.html', + styleUrls: ['service-dependencies.component.less'], + providers: [ModalService, TranslateService] +}) + +export class ServiceDependenciesComponent { + modalInstance: ComponentRef; + isDependent: boolean; + isLoading: boolean; + compositeServiceProperties: Array = []; + rulesList: Array = []; + operatorTypes: Array; + + @Input() readonly: boolean; + @Input() compositeService: Service; + @Input() currentServiceInstance: ComponentInstance; + @Input() selectedInstanceSiblings: Array; + @Input() selectedInstanceConstraints: Array = []; + @Input() selectedInstanceProperties: Array = []; + @Output() updateRulesListEvent:EventEmitter> = new EventEmitter>(); + @Output() loadRulesListEvent:EventEmitter = new EventEmitter(); + @Output() dependencyStatus = new EventEmitter(); + + + constructor(private componentServiceNg2: ComponentServiceNg2, private ModalServiceNg2: ModalService, private translateService: TranslateService) { + } + + ngOnInit() { + this.isLoading = false; + this.operatorTypes = [ + {label: ">", value: OPERATOR_TYPES.GREATER_THAN}, + {label: "<", value: OPERATOR_TYPES.LESS_THAN}, + {label: "=", value: OPERATOR_TYPES.EQUAL} + ]; + this.componentServiceNg2.getServiceProperties(this.compositeService).subscribe((properties: Array) => { + this.compositeServiceProperties = properties; + }); + this.loadRules(); + this.translateService.languageChangedObservable.subscribe(lang => { + I18nTexts.translateTexts(this.translateService); + }); + } + + ngOnChanges(changes) { + if(changes.currentServiceInstance) { + this.currentServiceInstance = changes.currentServiceInstance.currentValue; + this.isDependent = this.currentServiceInstance.isDependent(); + } + if(changes.selectedInstanceConstraints && changes.selectedInstanceConstraints.currentValue !== changes.selectedInstanceConstraints.previousValue) { + this.selectedInstanceConstraints = changes.selectedInstanceConstraints.currentValue; + this.loadRules(); + } + } + + public openRemoveDependencyModal = (): ComponentRef => { + let actionButton: ButtonModel = new ButtonModel(I18nTexts.modalApprove, 'blue', this.onUncheckDependency); + let cancelButton: ButtonModel = new ButtonModel(I18nTexts.modalCancel, 'grey', this.onCloseRemoveDependencyModal); + let modalModel: ModalModel = new ModalModel('sm', I18nTexts.uncheckModalTitle, I18nTexts.uncheckModalText, [actionButton, cancelButton]); + return this.ModalServiceNg2.createCustomModal(modalModel); + } + + loadRules() { + this.rulesList = this.selectedInstanceConstraints && this.selectedInstanceConstraints.map((co: ConstraintObject) => ({ + servicePropertyName: co.servicePropertyName, + constraintOperator: co.constraintOperator, + sourceType: co.sourceType, + sourceName: co.sourceName !== 'SELF' ? co.sourceName : this.compositeService.name, + value: co.value, + })); + } + + onUncheckDependency = () => { + this.ModalServiceNg2.closeCurrentModal(); + this.isLoading = true; + let isDepOrig = this.isDependent; + let rulesListOrig = this.rulesList; + this.currentServiceInstance.unmarkAsDependent(); + this.updateComponentInstance(isDepOrig, rulesListOrig); + } + + onCloseRemoveDependencyModal = () => { + this.isDependent = true; + this.ModalServiceNg2.closeCurrentModal(); + } + + onCheckDependency = () => { + let isDepOrig = this.isDependent; + let rulesListOrig = this.rulesList; + this.currentServiceInstance.markAsDependent(); + this.rulesList = []; + this.updateComponentInstance(isDepOrig, rulesListOrig); + } + + onMarkAsDependent() { + if(!this.currentServiceInstance.isDependent()) { + this.onCheckDependency(); + } + else { + this.openRemoveDependencyModal().instance.open(); + } + } + + updateComponentInstance(isDependent_origVal : boolean, rulesList_orig: Array) { + this.isLoading = true; + this.componentServiceNg2.updateComponentInstance(this.compositeService, this.currentServiceInstance).subscribe((updatedServiceIns: ComponentInstance) => { + this.currentServiceInstance = new ComponentInstance(updatedServiceIns); + this.isDependent = this.currentServiceInstance.isDependent(); + this.dependencyStatus.emit(this.isDependent); + if(this.isDependent) { + this.loadRulesListEvent.emit(); + } + this.isLoading = false; + }, err=> { + this.isDependent = isDependent_origVal; + this.rulesList = rulesList_orig; + this.isLoading = false; + console.log('An error has occurred.'); + }); + } + + onAddRule () { + let cancelButton: ButtonModel = new ButtonModel(I18nTexts.modalCancel, 'outline white', this.ModalServiceNg2.closeCurrentModal); + let saveButton: ButtonModel = new ButtonModel(I18nTexts.modalCreate, 'blue', this.createRule, this.getDisabled); + let modalModel: ModalModel = new ModalModel('l', I18nTexts.addRuleTxt, '', [saveButton, cancelButton], 'standard'); + this.modalInstance = this.ModalServiceNg2.createCustomModal(modalModel); + this.ModalServiceNg2.addDynamicContentToModal( + this.modalInstance, + ServiceDependenciesEditorComponent, + { + currentServiceName: this.currentServiceInstance.name, + operatorTypes: this.operatorTypes, + compositeServiceName: this.compositeService.name, + compositeServiceProperties: this.compositeServiceProperties, + selectedInstanceProperties: this.selectedInstanceProperties, + selectedInstanceSiblings: this.selectedInstanceSiblings + } + ); + this.modalInstance.instance.open(); + } + + onSelectRule(index: number) { + let cancelButton: ButtonModel = new ButtonModel(I18nTexts.modalCancel, 'outline white', this.ModalServiceNg2.closeCurrentModal); + let saveButton: ButtonModel = new ButtonModel(I18nTexts.modalSave, 'blue', () => this.updateRules(), this.getDisabled); + let modalModel: ModalModel = new ModalModel('l', I18nTexts.updateRuleTxt, '', [saveButton, cancelButton], 'standard'); + this.modalInstance = this.ModalServiceNg2.createCustomModal(modalModel); + this.ModalServiceNg2.addDynamicContentToModal( + this.modalInstance, + ServiceDependenciesEditorComponent, + { + serviceRuleIndex: index, + serviceRules: _.map(this.rulesList, rule => new ConstraintObjectUI(rule)), + currentServiceName: this.currentServiceInstance.name, + operatorTypes: this.operatorTypes, + compositeServiceName: this.compositeService.name, + compositeServiceProperties: this.compositeServiceProperties, + selectedInstanceProperties: this.selectedInstanceProperties, + selectedInstanceSiblings: this.selectedInstanceSiblings + } + ); + this.modalInstance.instance.open(); + } + + getDisabled = ():boolean => { + return !this.modalInstance.instance.dynamicContent.instance.checkFormValidForSubmit(); + }; + + createRule = ():void => { + let newRuleToCreate: ConstraintObject = new ConstraintObject(this.modalInstance.instance.dynamicContent.instance.currentRule); + this.isLoading = true; + this.componentServiceNg2.createServiceFilterConstraints( + this.compositeService, + this.currentServiceInstance, + newRuleToCreate + ).subscribe( (response) => { + this.updateRulesListEvent.emit(response.properties); + this.isLoading = false; + }, err=> { + this.isLoading = false; + }); + this.ModalServiceNg2.closeCurrentModal(); + }; + + updateRules = ():void => { + let allRulesToUpdate: Array = this.modalInstance.instance.dynamicContent.instance.serviceRulesList.map(rule => new ConstraintObject(rule)); + this.isLoading = true; + this.componentServiceNg2.updateServiceFilterConstraints( + this.compositeService, + this.currentServiceInstance, + allRulesToUpdate + ).subscribe((response) => { + this.updateRulesListEvent.emit(response.properties); + this.isLoading = false; + }, err => { + this.isLoading = false; + }); + this.ModalServiceNg2.closeCurrentModal(); + } + + getSymbol(constraintOperator) { + switch (constraintOperator) { + case OPERATOR_TYPES.LESS_THAN: return '<'; + case OPERATOR_TYPES.EQUAL: return '='; + case OPERATOR_TYPES.GREATER_THAN: return '>'; + } + } + + onDeleteRule = (index:number) => { + this.isLoading = true; + this.componentServiceNg2.deleteServiceFilterConstraints( + this.compositeService, + this.currentServiceInstance, + index + ).subscribe( (response) => { + this.updateRulesListEvent.emit(response.properties); + this.isLoading = false; + }, err=> { + this.isLoading = false; + }); + this.ModalServiceNg2.closeCurrentModal(); + }; + + openDeleteModal = (index:number) => { + this.ModalServiceNg2.createActionModal(I18nTexts.deleteRuleTxt, I18nTexts.deleteRuleMsg, + I18nTexts.modalDelete, () => this.onDeleteRule(index), I18nTexts.modalCancel).instance.open(); + } +} \ No newline at end of file diff --git a/catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.module.ts b/catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.module.ts new file mode 100644 index 0000000000..7e66ed99c7 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.module.ts @@ -0,0 +1,24 @@ + +import { NgModule } from "@angular/core"; +import {CommonModule} from "@angular/common"; +import {ServiceDependenciesComponent} from "./service-dependencies.component"; +import {UiElementsModule} from "app/ng2/components/ui/ui-elements.module"; +import {TranslateModule} from 'app/ng2/shared/translator/translate.module'; + +@NgModule({ + declarations: [ + ServiceDependenciesComponent + ], + imports: [ + CommonModule, + UiElementsModule, + TranslateModule + ], + exports: [], + entryComponents: [ + ServiceDependenciesComponent + ], + providers: [] +}) +export class ServiceDependenciesModule { +} \ No newline at end of file diff --git a/catalog-ui/src/app/ng2/components/ui/dynamic-element/dynamic-element.component.ts b/catalog-ui/src/app/ng2/components/ui/dynamic-element/dynamic-element.component.ts index 76b0b9ec2b..4f283fb3f1 100644 --- a/catalog-ui/src/app/ng2/components/ui/dynamic-element/dynamic-element.component.ts +++ b/catalog-ui/src/app/ng2/components/ui/dynamic-element/dynamic-element.component.ts @@ -175,8 +175,12 @@ export class DynamicElementComponent { tmp.push(new DropdownValue(true,'TRUE')); tmp.push(new DropdownValue(false,'FALSE')); this.cmpRef.instance.values = tmp; - if(!_.isUndefined(this.value)){//contains the real value (and not a string) - this.value = JSON.parse(this.value); + try { + if (typeof this.value === 'string') { + this.value = JSON.parse(this.value); + } + } catch(err) { + this.value = null; } break; diff --git a/catalog-ui/src/app/ng2/components/ui/form-components/checkbox/checkbox.component.less b/catalog-ui/src/app/ng2/components/ui/form-components/checkbox/checkbox.component.less index 9df2680b6f..5c061a4b5e 100644 --- a/catalog-ui/src/app/ng2/components/ui/form-components/checkbox/checkbox.component.less +++ b/catalog-ui/src/app/ng2/components/ui/form-components/checkbox/checkbox.component.less @@ -38,11 +38,16 @@ width:0; height:0; display:none; - &:checked ~ .checkbox-icon::before{ - .sprite-new; - .filled-checkbox-icon + &:checked { + ~ .checkbox-icon::before{ + .sprite-new; + .filled-checkbox-icon + } + &[disabled] ~ .checkbox-icon::before { + opacity: 0.5; + } } - &[disabled] ~ .checkbox-icon::before { + &[disabled]:not(:checked) ~ .checkbox-icon::before { /* TODO: add disabled styles here */ background-image: none; background-color: #EFEFEF; diff --git a/catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component.html b/catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component.html new file mode 100644 index 0000000000..f22e454332 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component.html @@ -0,0 +1,56 @@ +
+
+ +
+
+ + +
+
+ + + +
+
+
+ + + +
+ +
+ +
+ +
+ + +
+ +
+ + + + + +
+
+
+
+ +
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component.less b/catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component.less new file mode 100644 index 0000000000..e03b73c8c0 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component.less @@ -0,0 +1,43 @@ +@import './../../../../assets/styles/variables.less'; + +.sdc-modal-top-bar { + display: flex; + justify-content: flex-end; +} + +.i-sdc-form-content { + display: flex; + flex-direction: column; + margin-top: 10px; + padding-bottom: 20px; + + .i-sdc-form-item { + width: 250px; + &.operation { + width: 60px; + } + } + + .rule-builder-content { + display: flex; + align-items: flex-end; + .rule-input-field { + flex: 1; + &:not(:last-of-type) { + margin-right: 20px; + } + &.operator{ + width: 55px; + flex: 0 1 auto; + } + &.assigned-value-field { + margin-bottom: 10px; + } + /deep/ ui-element-dropdown select, + /deep/ ui-element-input input { + height: 30px; + } + } + + } +} \ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component.ts b/catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component.ts new file mode 100644 index 0000000000..db5e7a9a31 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component.ts @@ -0,0 +1,192 @@ +/*! + * Copyright © 2016-2018 European Support Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +import { Component } from '@angular/core'; +import {ServiceServiceNg2} from "app/ng2/services/component-services/service.service"; +import {ConstraintObjectUI, OPERATOR_TYPES} from 'app/ng2/components/logic/service-dependencies/service-dependencies.component'; +import {ServiceInstanceObject, PropertyBEModel} from 'app/models'; +import { PROPERTY_DATA } from 'app/utils'; +import {DropdownValue} from 'app/ng2/components/ui/form-components/dropdown/ui-element-dropdown.component'; + +export class UIDropDownSourceTypesElement extends DropdownValue{ + options: Array; + assignedLabel: string; + type: string; + constructor(input?: any){ + if(input) { + let value = input.value || ''; + let label = input.label || ''; + super(value, label); + this.options = input.options; + this.assignedLabel = input.assignedLabel; + this.type = input.type; + } + } +} + +@Component({ + selector: 'service-dependencies-editor', + templateUrl: './service-dependencies-editor.component.html', + styleUrls:['./service-dependencies-editor.component.less'], + providers: [ServiceServiceNg2] +}) + +export class ServiceDependenciesEditorComponent { + + input: { + serviceRuleIndex: number, + serviceRules: Array, + compositeServiceName: string, + currentServiceName: string, + compositeServiceProperties: Array, + selectedInstanceProperties: Array, + operatorTypes: Array, + selectedInstanceSiblings: Array + }; + currentServiceName: string; + selectedServiceProperties: Array; + selectedPropertyObj: PropertyBEModel; + ddValueSelectedServicePropertiesNames: Array; + operatorTypes: Array; + sourceTypes: Array = []; + currentRule: ConstraintObjectUI; + currentIndex: number; + listOfValuesToAssign: Array; + listOfSourceOptions: Array; + assignedValueLabel: string; + serviceRulesList: Array; + + + SOURCE_TYPES = { + STATIC: {label: 'Static', value: 'static'}, + SERVICE_PROPERTY: {label: 'Service Property', value: 'property'} + }; + + + ngOnInit() { + this.currentIndex = this.input.serviceRuleIndex; + this.serviceRulesList = this.input.serviceRules; + this.currentRule = this.serviceRulesList && this.input.serviceRuleIndex >= 0 ? + this.serviceRulesList[this.input.serviceRuleIndex]: + new ConstraintObjectUI({sourceName: this.SOURCE_TYPES.STATIC.value, sourceType: this.SOURCE_TYPES.STATIC.value, value: "", constraintOperator: OPERATOR_TYPES.EQUAL}); + this.currentServiceName = this.input.currentServiceName; + this.operatorTypes = this.input.operatorTypes; + this.selectedServiceProperties = this.input.selectedInstanceProperties; + this.ddValueSelectedServicePropertiesNames = _.map(this.input.selectedInstanceProperties, prop => new DropdownValue(prop.name, prop.name)); + this.initSourceTypes(); + this.syncRuleData(); + this.updateSourceTypesRelatedValues(); + } + + initSourceTypes() { + this.sourceTypes.push({label: this.SOURCE_TYPES.STATIC.label, value: this.SOURCE_TYPES.STATIC.value, + options: [], assignedLabel: this.SOURCE_TYPES.STATIC.label, type: this.SOURCE_TYPES.STATIC.value}); + this.sourceTypes.push({ + label: this.input.compositeServiceName, + value: this.input.compositeServiceName, + assignedLabel: this.SOURCE_TYPES.SERVICE_PROPERTY.label, + type: this.SOURCE_TYPES.SERVICE_PROPERTY.value, + options: this.input.compositeServiceProperties + }); + _.forEach(this.input.selectedInstanceSiblings, sib => + this.sourceTypes.push({ + label: sib.name, + value: sib.name, + options: sib.properties || [], + assignedLabel: this.SOURCE_TYPES.SERVICE_PROPERTY.label, + type: this.SOURCE_TYPES.SERVICE_PROPERTY.value + }) + ); + } + + syncRuleData() { + if(!this.currentRule.sourceName && this.currentRule.sourceType === this.SOURCE_TYPES.STATIC.value) { + this.currentRule.sourceName = this.SOURCE_TYPES.STATIC.value; + } + this.selectedPropertyObj = _.find(this.selectedServiceProperties, prop => prop.name === this.currentRule.servicePropertyName); + this.updateOperatorTypesList(); + this.updateSourceTypesRelatedValues(); + } + + updateOperatorTypesList() { + if (this.selectedPropertyObj && PROPERTY_DATA.SIMPLE_TYPES_COMPARABLE.indexOf(this.selectedPropertyObj.type) === -1) { + this.operatorTypes = [{label: "=", value: OPERATOR_TYPES.EQUAL}]; + this.currentRule.constraintOperator = OPERATOR_TYPES.EQUAL; + } + else { + this.operatorTypes = this.input.operatorTypes; + } + } + + updateSourceTypesRelatedValues() { + if(this.currentRule.sourceName) { + let selectedSourceType: UIDropDownSourceTypesElement = this.sourceTypes.find( + t => t.value === this.currentRule.sourceName && t.type === this.currentRule.sourceType + ); + this.listOfSourceOptions = selectedSourceType.options || []; + this.assignedValueLabel = selectedSourceType.assignedLabel || this.SOURCE_TYPES.STATIC.label; + this.filterOptionsByType(); + } + } + + onChangePage(newIndex) { + if (newIndex >= 0 && newIndex < this.input.serviceRules.length) { + this.currentIndex = newIndex; + this.currentRule = this.serviceRulesList[newIndex]; + this.syncRuleData(); + } + } + + onServicePropertyChanged() { + this.selectedPropertyObj = _.find(this.selectedServiceProperties, prop => prop.name === this.currentRule.servicePropertyName); + this.updateOperatorTypesList(); + this.filterOptionsByType(); + this.currentRule.value = ''; + } + + onSelectSourceType() { + this.currentRule.sourceType = this.currentRule.sourceName === this.SOURCE_TYPES.STATIC.value ? + this.SOURCE_TYPES.STATIC.value : + this.SOURCE_TYPES.SERVICE_PROPERTY.value; + this.updateSourceTypesRelatedValues(); + this.currentRule.value = ''; + } + + filterOptionsByType() { + if(!this.selectedPropertyObj) { + this.listOfValuesToAssign = []; + return; + } + this.listOfValuesToAssign = this.listOfSourceOptions.reduce((result, op:PropertyBEModel) => { + if(op.type === this.selectedPropertyObj.type && op.schemaType === this.selectedPropertyObj.schemaType) { + result.push(new DropdownValue(op.name, op.name)); + } + return result; + }, []); + } + + onValueChange(isValidValue) { + this.currentRule.updateValidity(isValidValue); + } + + checkFormValidForSubmit() { + if(!this.serviceRulesList) { //for create modal + let isStatic = this.currentRule.sourceName === this.SOURCE_TYPES.STATIC.value; + return this.currentRule.isValidRule(isStatic); + } + //for update all rules + return this.serviceRulesList.every(rule => rule.isValidRule(rule.sourceName === this.SOURCE_TYPES.STATIC.value)); + } +} \ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.module.ts b/catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.module.ts new file mode 100644 index 0000000000..98ac997bf7 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.module.ts @@ -0,0 +1,25 @@ +import { NgModule } from "@angular/core"; +import {CommonModule} from "@angular/common"; +import {ServiceDependenciesEditorComponent} from "./service-dependencies-editor.component"; +import {FormsModule} from "@angular/forms"; +import {FormElementsModule} from "app/ng2/components/ui/form-components/form-elements.module"; +import {UiElementsModule} from "app/ng2/components/ui/ui-elements.module"; + +@NgModule({ + declarations: [ + ServiceDependenciesEditorComponent + ], + imports: [ + CommonModule, + FormsModule, + FormElementsModule, + UiElementsModule + ], + exports: [], + entryComponents: [ + ServiceDependenciesEditorComponent + ], + providers: [] +}) +export class ServiceDependenciesEditorModule { +} \ No newline at end of file diff --git a/catalog-ui/src/app/ng2/services/component-services/component.service.ts b/catalog-ui/src/app/ng2/services/component-services/component.service.ts index 69871abe04..e9036a805d 100644 --- a/catalog-ui/src/app/ng2/services/component-services/component.service.ts +++ b/catalog-ui/src/app/ng2/services/component-services/component.service.ts @@ -24,15 +24,17 @@ import {Observable} from 'rxjs/Observable'; import 'rxjs/add/operator/map'; import 'rxjs/add/operator/toPromise'; import {Response, URLSearchParams} from '@angular/http'; -import { Component, InputBEModel, InstancePropertiesAPIMap, FilterPropertiesAssignmentData, PropertyBEModel, OperationModel, BEOperationModel, CreateOperationResponse} from "app/models"; +import { Component, ComponentInstance, InputBEModel, InstancePropertiesAPIMap, FilterPropertiesAssignmentData, + PropertyBEModel, OperationModel, BEOperationModel, CreateOperationResponse} from "app/models"; import {downgradeInjectable} from '@angular/upgrade/static'; -import {COMPONENT_FIELDS, CommonUtils} from "app/utils"; +import {COMPONENT_FIELDS, CommonUtils, SERVICE_FIELDS} from "app/utils"; import {ComponentGenericResponse} from "../responses/component-generic-response"; import {InstanceBePropertiesMap} from "../../../models/properties-inputs/property-fe-map"; import {API_QUERY_PARAMS} from "app/utils"; import { ComponentType, ServerTypeUrl } from "../../../utils/constants"; import { HttpService } from '../http.service'; import {SdcConfigToken, ISdcConfig} from "../../config/sdc-config.config"; +import {ConstraintObject} from 'app/ng2/components/logic/service-dependencies/service-dependencies.component'; import {IDependenciesServerResponse} from "../responses/dependencies-server-response"; import {AutomatedUpgradeGenericResponse} from "../responses/automated-upgrade-response"; import {IAutomatedUpgradeRequestObj} from "../../pages/automated-upgrade/automated-upgrade.service"; @@ -82,6 +84,10 @@ export class ComponentServiceNg2 { return this.getComponentDataByFieldsName(component.componentType, component.uniqueId, [COMPONENT_FIELDS.COMPONENT_INSTANCES_PROPERTIES, COMPONENT_FIELDS.COMPONENT_INSTANCES_ATTRIBUTES]); } + getComponentInstanceProperties(component:Component):Observable { + return this.getComponentDataByFieldsName(component.componentType, component.uniqueId, [COMPONENT_FIELDS.COMPONENT_INSTANCES_PROPERTIES]); + } + getComponentAttributes(component:Component):Observable { return this.getComponentDataByFieldsName(component.componentType, component.uniqueId, [COMPONENT_FIELDS.COMPONENT_ATTRIBUTES]); } @@ -226,7 +232,7 @@ export class ComponentServiceNg2 { return this.http.delete(this.baseUrl + component.getTypeUrl() + component.uniqueId + '/delete/' + input.uniqueId + '/input') .map((res:Response) => { return new InputBEModel(res.json()); - }) + }); } updateComponentInputs(component:Component, inputs:InputBEModel[]):Observable { @@ -297,5 +303,37 @@ export class ComponentServiceNg2 { return res.json(); }); } + + updateComponentInstance(component:Component, componentInstance:ComponentInstance):Observable { + return this.http.post(this.baseUrl + component.getTypeUrl() + component.uniqueId + '/resourceInstance/' + componentInstance.uniqueId, componentInstance) + .map((res:Response) => { + return res.json(); + }); + } + + getServiceFilterConstraints(component:Component):Observable { + return this.getComponentDataByFieldsName(component.componentType, component.uniqueId, [SERVICE_FIELDS.NODE_FILTER]); + } + + createServiceFilterConstraints(component:Component, componentInstance:ComponentInstance, constraint:ConstraintObject):Observable { + return this.http.post(this.baseUrl + component.getTypeUrl() + component.uniqueId + '/resourceInstances/' + componentInstance.uniqueId + '/nodeFilter', constraint) + .map((res:Response) => { + return res.json(); + }); + } + + updateServiceFilterConstraints(component:Component, componentInstance:ComponentInstance, constraints:Array):Observable { + return this.http.put(this.baseUrl + component.getTypeUrl() + component.uniqueId + '/resourceInstances/' + componentInstance.uniqueId + '/nodeFilter/', constraints) + .map((res:Response) => { + return res.json(); + }); + } + + deleteServiceFilterConstraints(component:Component, componentInstance:ComponentInstance, constraintIndex:number) { + return this.http.delete(this.baseUrl + component.getTypeUrl() + component.uniqueId + '/resourceInstances/' + componentInstance.uniqueId + '/nodeFilter/' + constraintIndex) + .map((res:Response) => { + return res.json(); + }); + } } diff --git a/catalog-ui/src/app/ng2/services/responses/component-generic-response.ts b/catalog-ui/src/app/ng2/services/responses/component-generic-response.ts index 647cc927f7..37ccf381c9 100644 --- a/catalog-ui/src/app/ng2/services/responses/component-generic-response.ts +++ b/catalog-ui/src/app/ng2/services/responses/component-generic-response.ts @@ -52,6 +52,7 @@ export class ComponentGenericResponse implements Serializable; public additionalInformation:any; public derivedList:Array; + public nodeFilterData: Array; deserialize (response): ComponentGenericResponse { @@ -105,6 +106,9 @@ export class ComponentGenericResponse implements Serializable