diff options
author | davsad <david.sadlier@est.tech> | 2021-06-08 07:17:07 +0100 |
---|---|---|
committer | Michael Morris <michael.morris@est.tech> | 2021-10-06 11:31:51 +0000 |
commit | a03a1059f8e4b8b46ab662e9a865b3ae6bb77b53 (patch) | |
tree | 13f488a090b3ec57c07ee04584aa24b9a47080c7 | |
parent | 7b60bd7a745d38fd9e51630b6245c2f227abe830 (diff) |
Adding type safety to the service dependency editor.
Issue-ID: SDC-3725
Signed-off-by: davsad <david.sadlier@est.tech>
Change-Id: I63d77837fb0df24f5ee12baa5b852a76ce5f55e3
8 files changed, 143 insertions, 33 deletions
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 index 4b23568a06..f84214e4ce 100644 --- 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 @@ -24,18 +24,29 @@ <label class="i-sdc-form-label required" >Source</label> <ui-element-dropdown class="i-sdc-form-select" data-tests-id="sourceType" [values]="sourceTypes" [(value)]="currentRule.sourceName" (change)="onSelectSourceType($event)"></ui-element-dropdown> </div> - - <div class="rule-input-field assigned-value-field"> + <div [ngClass]="isComplexListMapType() && isStaticSource() ? 'complex-input-field' : ''" + class="rule-input-field assigned-value-field"> <label class="i-sdc-form-label required" >{{assignedValueLabel}}</label> + <dynamic-property + *ngIf="isStaticSource() && isComplexListMapType()" + [selectedPropertyId]="selectedPropertyObj.uniqueId" + [property]="selectedPropertyObj" + [expandedChildId]="selectedPropertyObj.expandedChildPropertyId ? + selectedPropertyObj.expandedChildPropertyId : selectedPropertyObj.name" + [canBeDeclared]="true" + (propertyChanged)="updateComplexListMapTypeRuleValue()" + [rootProperty]="selectedPropertyObj" + (expandChild)="selectedPropertyObj.updateExpandedChildPropertyId($event)"> + </dynamic-property> <dynamic-element - *ngIf="currentRule.sourceType === SOURCE_TYPES.STATIC.value" + *ngIf="isStaticSource() && !isComplexListMapType()" [(value)]="currentRule.value" class="rule-assigned-value" data-tests-id="ruleAssignedValue" (elementChanged)="onValueChange($event.isValid)" [type]="selectedPropertyObj ? selectedPropertyObj.type : 'string'"> </dynamic-element> - <ui-element-dropdown *ngIf="currentRule.sourceType !== SOURCE_TYPES.STATIC.value" + <ui-element-dropdown *ngIf="!isStaticSource()" class="rule-assigned-value" data-tests-id="ruleAssignedValue" [(value)]="currentRule.value" 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 index e03b73c8c0..b475ed2847 100644 --- 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 @@ -21,6 +21,7 @@ .rule-builder-content { display: flex; align-items: flex-end; + flex-wrap: wrap; .rule-input-field { flex: 1; &:not(:last-of-type) { @@ -38,6 +39,9 @@ height: 30px; } } - + .complex-input-field { + flex-basis: 100%; + display: block; + } } }
\ 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 index 084ab32b5c..cb3e87c8d1 100644 --- 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 @@ -14,7 +14,7 @@ * permissions and limitations under the License. */ import {Component} from '@angular/core'; -import {InputBEModel, PropertyBEModel} from 'app/models'; +import {InputBEModel, PropertyBEModel, PropertyFEModel} from 'app/models'; import { ConstraintObjectUI, OPERATOR_TYPES @@ -23,6 +23,7 @@ import {DropdownValue} from 'app/ng2/components/ui/form-components/dropdown/ui-e import {ServiceServiceNg2} from 'app/ng2/services/component-services/service.service'; import {PROPERTY_DATA} from 'app/utils'; import {ServiceInstanceObject} from '../../../models/service-instance-properties-and-interfaces'; +import { PropertiesUtils } from '../properties-assignment/services/properties.utils'; export class UIDropDownSourceTypesElement extends DropdownValue { options: any[]; @@ -61,7 +62,7 @@ export class ServiceDependenciesEditorComponent { }; currentServiceName: string; selectedServiceProperties: PropertyBEModel[]; - selectedPropertyObj: PropertyBEModel; + selectedPropertyObj: PropertyFEModel; ddValueSelectedServicePropertiesNames: DropdownValue[]; operatorTypes: DropdownValue[]; sourceTypes: UIDropDownSourceTypesElement[] = []; @@ -77,6 +78,8 @@ export class ServiceDependenciesEditorComponent { SERVICE_PROPERTY: {label: 'Service Property', value: 'property'} }; + constructor(private propertiesUtils: PropertiesUtils) {} + ngOnInit() { this.currentIndex = this.input.serviceRuleIndex; this.serviceRulesList = this.input.serviceRules; @@ -124,10 +127,11 @@ export class ServiceDependenciesEditorComponent { } syncRuleData() { - if (!this.currentRule.sourceName && this.currentRule.sourceType === this.SOURCE_TYPES.STATIC.value) { + if (!this.currentRule.sourceName || this.currentRule.sourceType === this.SOURCE_TYPES.STATIC.value) { this.currentRule.sourceName = this.SOURCE_TYPES.STATIC.value; + this.currentRule.sourceType = this.SOURCE_TYPES.STATIC.value; } - this.selectedPropertyObj = _.find(this.selectedServiceProperties, (prop) => prop.name === this.currentRule.servicePropertyName); + this.updateSelectedPropertyObj(); this.updateOperatorTypesList(); this.updateSourceTypesRelatedValues(); } @@ -154,7 +158,7 @@ export class ServiceDependenciesEditorComponent { } } - onChangePage(newIndex) { + onChangePage(newIndex:any) { if (newIndex >= 0 && newIndex < this.input.serviceRules.length) { this.currentIndex = newIndex; this.currentRule = this.serviceRulesList[newIndex]; @@ -163,18 +167,18 @@ export class ServiceDependenciesEditorComponent { } onServicePropertyChanged() { - this.selectedPropertyObj = _.find(this.selectedServiceProperties, (prop) => prop.name === this.currentRule.servicePropertyName); + this.currentRule.value = ''; + this.updateSelectedPropertyObj(); this.updateOperatorTypesList(); this.filterOptionsByType(); - this.currentRule.value = ''; } onSelectSourceType() { + this.currentRule.value = ''; 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() { @@ -190,7 +194,7 @@ export class ServiceDependenciesEditorComponent { }, []); } - onValueChange(isValidValue) { + onValueChange(isValidValue:any) { this.currentRule.updateValidity(isValidValue); } @@ -202,4 +206,29 @@ export class ServiceDependenciesEditorComponent { // for update all rules return this.serviceRulesList.every((rule) => rule.isValidRule(rule.sourceName === this.SOURCE_TYPES.STATIC.value)); } + + updateSelectedPropertyObj(): void { + this.selectedPropertyObj = null; + if (this.currentRule.servicePropertyName) { + let newProp = new PropertyFEModel(_.find(this.selectedServiceProperties, (prop) => prop.name === this.currentRule.servicePropertyName)); + newProp.value = JSON.stringify(this.currentRule.value); + this.propertiesUtils.initValueObjectRef(newProp); + console.log("TEST" + newProp.value); + setTimeout(() => {this.selectedPropertyObj = newProp}) + } + } + + isStaticSource(): boolean { + return this.currentRule.sourceType === this.SOURCE_TYPES.STATIC.value + } + + isComplexListMapType(): boolean { + return this.selectedPropertyObj && this.selectedPropertyObj.derivedDataType > 0; + } + + updateComplexListMapTypeRuleValue(): void { + let value = PropertyFEModel.cleanValueObj(this.selectedPropertyObj.valueObj); + this.currentRule.value = JSON.stringify(value); + this.onValueChange(this.selectedPropertyObj.valueObjIsValid); + } } 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 index 7b128f4468..cfa466ffa3 100644 --- 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 @@ -4,6 +4,7 @@ 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'; import { ServiceDependenciesEditorComponent } from './service-dependencies-editor.component'; +import { PropertyTableModule } from 'app/ng2/components/logic/properties-table/property-table.module'; @NgModule({ declarations: [ @@ -13,7 +14,8 @@ import { ServiceDependenciesEditorComponent } from './service-dependencies-edito CommonModule, FormsModule, FormElementsModule, - UiElementsModule + UiElementsModule, + PropertyTableModule ], exports: [], entryComponents: [ diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/datatypes/ServiceDependencyProperty.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/datatypes/ServiceDependencyProperty.java index 6afbdc244a..47b8df26ad 100644 --- a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/datatypes/ServiceDependencyProperty.java +++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/datatypes/ServiceDependencyProperty.java @@ -32,12 +32,14 @@ public class ServiceDependencyProperty { private final String name; private final String value; private final String source; + private final String type; private final LogicalOperator logicalOperator; - public ServiceDependencyProperty(String name, String value, LogicalOperator logicalOperator) { + public ServiceDependencyProperty(String name, String type, String value, LogicalOperator logicalOperator) { this.name = name; this.value = value; this.source = "Static"; + this.type = type; this.logicalOperator = logicalOperator; } } diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/ServiceTemplateDesignUiTests.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/ServiceTemplateDesignUiTests.java index e944ab329a..8bec8353ef 100644 --- a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/ServiceTemplateDesignUiTests.java +++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/execute/sanity/ServiceTemplateDesignUiTests.java @@ -284,8 +284,10 @@ public class ServiceTemplateDesignUiTests extends SetupCDTest { componentPage.isLoaded(); final ResourcePropertiesPage vfcPropertiesPage = componentPage.goToProperties(); vfcPropertiesPage.isLoaded(); - final List<String> propertyNames = vfcPropertiesPage.getPropertyNames(); - final ServiceDependencyProperty serviceDependencyProperty = new ServiceDependencyProperty(propertyNames.get(0), value, operator); + final Map<String, String> propertyNamesAndTypes = vfcPropertiesPage.getPropertyNamesAndTypes(); + final List<String> propertyNames = propertyNamesAndTypes.keySet().stream().collect(Collectors.toList()); + final ServiceDependencyProperty serviceDependencyProperty = + new ServiceDependencyProperty(propertyNames.get(0), propertyNamesAndTypes.get(propertyNames.get(0)), value, operator); homePage.getTopNavComponent().clickOnHome(); homePage.isLoaded(); @@ -881,7 +883,7 @@ public class ServiceTemplateDesignUiTests extends SetupCDTest { assertThat(String.format("The Component '%s' should have properties", vfResourceCreateData.getName()), propertyNamesAndTypes, not(anEmptyMap())); propertyNamesAndTypes.forEach((name, type) - -> substitutionFilterProperties.add(new ServiceDependencyProperty(name, getPropertyValueByType(type), LogicalOperator.EQUALS))); + -> substitutionFilterProperties.add(new ServiceDependencyProperty(name, type, getPropertyValueByType(type), LogicalOperator.EQUALS))); } private String getPropertyValueByType(final String type) { @@ -895,9 +897,9 @@ public class ServiceTemplateDesignUiTests extends SetupCDTest { case "boolean": return "TRUE"; case "list": - return "[value1, value2]"; + return "[\"value1\", \"value2\"]"; case "map": - return "MyKey: MyValue"; + return "{\"MyKey\": \"MyValue\"}"; default: throw new UnsupportedOperationException("Not yet implemented for " + type); } @@ -925,7 +927,7 @@ public class ServiceTemplateDesignUiTests extends SetupCDTest { substitutionFilterMap.containsKey(substitutionFilterProperty.getName())); final Map<?, ?> substitutionFilterValue = (Map<?, ?>) ((List<?>) substitutionFilterMap.get(substitutionFilterProperty.getName())).get(0); assertThat("Substitution Filter Value should not be empty", substitutionFilterMap, not(anEmptyMap())); - final String expectedSubstitutionPropertyValue = substitutionFilterProperty.getValue(); + final String expectedSubstitutionPropertyValue = substitutionFilterProperty.getValue().replaceAll("[\"{}]", ""); final String actualSubstitutionPropertyValue = substitutionFilterValue.values().stream().findFirst().get() instanceof Map ? substitutionFilterValue.values().stream().findFirst().get().toString().replace("=", ": ") .replaceAll("\\{(.*?)\\}", "$1").trim() diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/ResourcePropertiesPage.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/ResourcePropertiesPage.java index ace3041577..2d45c7c22a 100644 --- a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/ResourcePropertiesPage.java +++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/ResourcePropertiesPage.java @@ -19,11 +19,13 @@ package org.onap.sdc.frontend.ci.tests.pages; +import java.util.HashMap; import java.util.List; -import java.util.stream.Collectors; +import java.util.Map; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; import lombok.AllArgsConstructor; import lombok.Getter; @@ -52,13 +54,19 @@ public class ResourcePropertiesPage extends AbstractPageObject { } /** - * Returns a list based on property names - * @return list of names from the properties table + * Creates a map based on property names and data types */ - public List<String> getPropertyNames() { + public Map<String, String> getPropertyNamesAndTypes() { waitPropertiesToLoad(); - return findElements(By.xpath(XpathSelector.PROPERTY_NAMES.getXpath())).stream() - .map(ele -> ele.getAttribute("innerText")).collect(Collectors.toList()); + final Map<String, String> namesAndTypes = new HashMap<>(); + final List<WebElement> names = findElements(By.xpath(XpathSelector.PROPERTY_NAMES.getXpath())); + final List<WebElement> types = findElements(By.xpath(XpathSelector.PROPERTY_TYPES.getXpath())); + + for (int i = 0;i < names.size();i++) { + namesAndTypes.put(names.get(i).getAttribute("innerText"), types.get(i).getAttribute("innerText")); + } + + return namesAndTypes; } @AllArgsConstructor diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/ServiceDependenciesEditor.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/ServiceDependenciesEditor.java index cc3e28448c..969854b214 100644 --- a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/ServiceDependenciesEditor.java +++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/ServiceDependenciesEditor.java @@ -19,7 +19,11 @@ package org.onap.sdc.frontend.ci.tests.pages; +import static org.junit.jupiter.api.Assertions.fail; + import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import java.util.stream.Collectors; import org.onap.sdc.frontend.ci.tests.datatypes.ServiceDependencyProperty; @@ -28,6 +32,8 @@ import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.Select; +import com.fasterxml.jackson.databind.json.JsonMapper; + import lombok.AllArgsConstructor; import lombok.Getter; @@ -61,16 +67,56 @@ public class ServiceDependenciesEditor extends AbstractPageObject { logicalOperator.selectByVisibleText(property.getLogicalOperator().getOperator()); final Select sourceType = new Select(webDriver.findElement(By.xpath(XpathSelector.SOURCE_TYPE.xPath))); sourceType.selectByVisibleText(property.getSource()); - addRuleAssignedValue(webDriver.findElement( - By.xpath(XpathSelector.RULE_ASSIGNED_VALUE.xPath)), property.getValue()); + try { + addRuleAssignedValue(property); + } catch (Exception e) { + fail("Failed to add property due to exception while adding rule value :: {}", e); + } webDriver.findElement(By.xpath(XpathSelector.CREATE_BUTTON.xPath)).click(); } - private void addRuleAssignedValue(final WebElement element, final String value) { + private void addRuleAssignedValue(final ServiceDependencyProperty property) throws Exception { + final var type = property.getType(); + final var value = property.getValue(); + switch (type) { + case "list": + addListInput(property.getName(), value); + break; + case "map": + addMapInput(property.getName(), value); + break; + default: + addStringInput(waitForElementVisibility(By.xpath(XpathSelector.RULE_ASSIGNED_VALUE.xPath)), value); + break; + } + } + + private void addStringInput(WebElement element, Object value) { if ("select".equals(element.getTagName())) { - new Select(element).selectByVisibleText(value); + new Select(element).selectByVisibleText(value.toString()); } else { - element.sendKeys(value); + element.sendKeys(value.toString()); + } + } + + private void addListInput(final String name, final String value) throws Exception { + final List<?> values = new JsonMapper().readValue(value, List.class); + final WebElement addToListElement = waitForElementVisibility(By.xpath(XpathSelector.RULE_ASSIGNED_VALUE_ADD_TO_LIST.formatXpath(name))); + for (int i=0;i<values.size();i++) { + addToListElement.click(); + addStringInput(waitForElementVisibility(By.xpath(XpathSelector.RULE_ASSIGNED_LIST_VALUE.formatXpath(name, i))), values.get((i))); + } + } + + private void addMapInput(final String name, final String value) throws Exception { + final Map<?, ?> values = new JsonMapper().readValue(value, Map.class); + int i = 0; + final WebElement addToListElement = waitForElementVisibility(By.xpath(XpathSelector.RULE_ASSIGNED_VALUE_ADD_TO_LIST.formatXpath(name))); + for(Entry<?, ?> entry : values.entrySet()) { + addToListElement.click(); + final List<WebElement> KeyValueInputs = waitForAllElementsVisibility(By.xpath(XpathSelector.RULE_ASSIGNED_MAP_KEY_VALUE.formatXpath(name, i++))); + addStringInput(KeyValueInputs.get(0), entry.getKey()); + addStringInput(KeyValueInputs.get(1), entry.getValue()); } } @@ -82,9 +128,15 @@ public class ServiceDependenciesEditor extends AbstractPageObject { CONSTRAINT_OPERATOR("//*[@data-tests-id='constraintOperator']/select"), SOURCE_TYPE("//*[@data-tests-id='sourceType']/select"), RULE_ASSIGNED_VALUE("//*[@data-tests-id='ruleAssignedValue']//*[self::input or self::select]"), + RULE_ASSIGNED_VALUE_ADD_TO_LIST("//a[@data-tests-id = 'add-to-list-%s']"), + RULE_ASSIGNED_LIST_VALUE("//*[@data-tests-id='value-prop-%s.%d']"), + RULE_ASSIGNED_MAP_KEY_VALUE("//*[contains(@data-tests-id, 'value-prop') and contains(@data-tests-id, '%s.%d')]"), CREATE_BUTTON("//button[text()='Create']"); private final String xPath; + public String formatXpath(Object... values) { + return String.format(xPath, values); + } } } |