diff options
9 files changed, 179 insertions, 6 deletions
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java index ca4002f26a..2f712e1e7b 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java @@ -1263,6 +1263,8 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic { oldComponentInstance.setModificationTime(System.currentTimeMillis()); oldComponentInstance.setCustomizationUUID(UUID.randomUUID().toString()); oldComponentInstance.setDirectives(newComponentInstance.getDirectives()); + oldComponentInstance.setMaxOccurrences(newComponentInstance.getMaxOccurrences()); + oldComponentInstance.setMinOccurrences(newComponentInstance.getMinOccurrences()); if (oldComponentInstance.getGroupInstances() != null) { oldComponentInstance.getGroupInstances().forEach(group -> group.setName(getNewGroupName(oldComponentInstance.getNormalizedName(), ValidationUtils.normalizeComponentInstanceName(newComponentInstance.getName()), group.getName()))); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java index ef63a86d39..5c30d0977c 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java @@ -46,6 +46,7 @@ import java.util.Optional; import java.util.Set; import java.util.function.Supplier; import java.util.stream.Collectors; +import com.google.common.primitives.Ints; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.io.FilenameUtils; @@ -912,6 +913,12 @@ public class ToscaExportHandler { if (MapUtils.isNotEmpty(componentInstance.getToscaArtifacts())) { nodeTemplate.setArtifacts(convertToNodeTemplateArtifacts(componentInstance.getToscaArtifacts())); } + if (componentInstance.getMinOccurrences() != null && componentInstance.getMaxOccurrences()!= null){ + List<Object> occur = new ArrayList<Object>(); + occur.add(parseToIntIfPossible(componentInstance.getMinOccurrences())); + occur.add(parseToIntIfPossible(componentInstance.getMaxOccurrences())); + nodeTemplate.setOccurrences(occur); + } nodeTemplate.setType(componentInstance.getToscaComponentName()); nodeTemplate.setDirectives(componentInstance.getDirectives()); nodeTemplate.setNode_filter(convertToNodeTemplateNodeFilterComponent(componentInstance.getNodeFilter())); @@ -1015,7 +1022,12 @@ public class ToscaExportHandler { log.debug("finish convert topology template for {} for type {}", component.getUniqueId(), component.getComponentType()); return convertNodeTemplatesRes; } - + + private Object parseToIntIfPossible(final String value) { + final Integer intValue = Ints.tryParse(value); + return intValue == null ? value : intValue; + } + private void handleInstanceInterfaces( Map<String, List<ComponentInstanceInterface>> componentInstanceInterfaces, ComponentInstance componentInstance, Map<String, DataTypeDefinition> dataTypes, ToscaNodeTemplate nodeTemplate, diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaNodeTemplate.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaNodeTemplate.java index f909a9c7b1..0a75870502 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaNodeTemplate.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaNodeTemplate.java @@ -34,6 +34,7 @@ import org.apache.commons.collections.MapUtils; public class ToscaNodeTemplate { private String type; + private List<Object> occurrences; private List<String> directives; private Map<String, String> metadata; private String description; diff --git a/catalog-ui/src/app/models/componentsInstances/componentInstance.ts b/catalog-ui/src/app/models/componentsInstances/componentInstance.ts index c3188baa47..86411b2dd5 100644 --- a/catalog-ui/src/app/models/componentsInstances/componentInstance.ts +++ b/catalog-ui/src/app/models/componentsInstances/componentInstance.ts @@ -94,6 +94,8 @@ export class ComponentInstance implements IComponentInstance{ public sourceModelName:string; public sourceModelUid:string; public sourceModelUuid:string; + public minOccurrences: string; + public maxOccurrences: string; //custom properties public certified:boolean; public iconSprite:string; @@ -137,6 +139,8 @@ export class ComponentInstance implements IComponentInstance{ this.originArchived = componentInstance.originArchived; this.directives = componentInstance.directives; this.interfaces = componentInstance.interfaces; + this.minOccurrences = componentInstance.minOccurrences; + this.maxOccurrences = componentInstance.maxOccurrences; } } diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/properties-tab/properties-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/properties-tab/properties-tab.component.html index 86c6fea1ef..358c910c2b 100644 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/properties-tab/properties-tab.component.html +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/properties-tab/properties-tab.component.html @@ -92,6 +92,69 @@ </sdc-accordion> </ng-container> </div> - </div> + + </div> + </content> +</ng2-expand-collapse> + +<ng2-expand-collapse state="0"> + <header sdc-tooltip tooltip-text="Occurrences">OCCURRENCES</header> + <content> + <div class="w-sdc-designer-sidebar-section"> + <div *ngIf="isUnboundedChecked != null"> + <ng-container> + <sdc-accordion [title]="component.name + ' Occurrences'" [arrow-direction]="'right'" [testId]="'Occurrences'" [css-class]="'occurrences-accordion'"> + <div class="i-sdc-designer-sidebar-section-content-item"> + <div class="i-sdc-designer-sidebar-section-content-item-property-and-attribute"> + <checkbox [(checked)]="isOccurrencesEnabled" (change)="enableOccurrences()" [disabled]="isViewOnly"></checkbox> + <div> + <span class="i-sdc-designer-sidebar-section-content-item-property-and-attribute-label" + [ngClass]="{'hand enabled': !isViewOnly}">Enable Occurrences</span> + </div> + </div> + <div *ngIf="isOccurrencesEnabled" class="i-sdc-designer-sidebar-section-content-item-property-and-attribute"> + <div class="sdc-input"> + <span class="i-sdc-designer-sidebar-section-content-item-property-and-attribute-label">Min Occurrences</span> + <div class="min-occurrences-value"> + <sdc-input + label="" + testId="reqOccurrencesMin" + [disabled]="isViewOnly" + [(value)]="component.minOccurrences" + type="number"> + </sdc-input> + </div> + </div> + </div> + <div *ngIf="isOccurrencesEnabled" class="i-sdc-designer-sidebar-section-content-item-property-and-attribute"> + <div class="sdc-input"> + <span class="i-sdc-designer-sidebar-section-content-item-property-and-attribute-label">Max Occurrences</span> + <div class="max-occurrences-value"> + <sdc-checkbox + class="checkbox-label unbounded-value" + testId="reqOccurrencesMaxUnbounded" + label="Unbounded" + (checkedChange)="onUnboundedChanged(component)" + [checked]="isUnboundedChecked" + [disabled]="isViewOnly"> + </sdc-checkbox> + <sdc-input + *ngIf="!isUnboundedChecked" + testId="reqOccurrencesMax" + [disabled]="isViewOnly" + [(value)]="component.maxOccurrences" + type="number"> + </sdc-input> + </div> + </div> + </div> + <div *ngIf="!isViewOnly && isOccurrencesEnabled" class="i-sdc-designer-sidebar-section-content-item-property-and-attribute"> + <button class="tlv-btn blue" (click)="saveOccurrences()" [disabled]="!isOccurrencesFormValid(component)">Save</button> + </div> + </div> + </sdc-accordion> + </ng-container> + </div> + </div> </content> </ng2-expand-collapse> diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/properties-tab/properties-tab.component.less b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/properties-tab/properties-tab.component.less index 5cb0697da1..ac0d1707e7 100644 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/properties-tab/properties-tab.component.less +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/properties-tab/properties-tab.component.less @@ -21,6 +21,10 @@ flex: 0 0 auto; align-self: center; } + + /deep/ .checkbox-container { + margin-right: 10px; + } } .i-sdc-designer-sidebar-section-content-item-property-and-attribute-label { @@ -39,14 +43,12 @@ display: block; } - - /deep/ .expand-collapse-content { max-height: max-content; padding: 10px 0; .sdc-accordion .sdc-accordion-header { - + background-color: #e6f6fb; border-left: solid #009fdb 4px; box-shadow: 0 0px 3px -1px rgba(0, 0, 0, 0.3); diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/properties-tab/properties-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/properties-tab/properties-tab.component.ts index b4b8248ed0..99bd5e882d 100644 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/properties-tab/properties-tab.component.ts +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/properties-tab/properties-tab.component.ts @@ -4,6 +4,7 @@ import { AttributeModel, AttributesGroup, Component as TopologyTemplate, + ComponentInstance, ComponentMetadata, FullComponentInstance, PropertiesGroup, @@ -14,6 +15,7 @@ import { WorkspaceService } from 'app/ng2/pages/workspace/workspace.service'; import { GroupByPipe } from 'app/ng2/pipes/groupBy.pipe'; import { ResourceNamePipe } from 'app/ng2/pipes/resource-name.pipe'; import { TopologyTemplateService } from 'app/ng2/services/component-services/topology-template.service'; +import { ComponentInstanceServiceNg2 } from "app/ng2/services/component-instance-services/component-instance.service"; import { ComponentGenericResponse } from 'app/ng2/services/responses/component-generic-response'; import { TranslateService } from 'app/ng2/shared/translator/translate.service'; import { ModalsHandler } from 'app/utils'; @@ -33,6 +35,9 @@ export class PropertiesTabComponent implements OnInit { propertiesMessage: string; metadata: ComponentMetadata; objectKeys = Object.keys; + isUnboundedChecked: boolean; + isOccurrencesEnabled: boolean = false; + isLoading: boolean; @Input() isViewOnly: boolean; @Input() componentType: SelectedComponentType; @@ -44,6 +49,7 @@ export class PropertiesTabComponent implements OnInit { private compositionService: CompositionService, private modalsHandler: ModalsHandler, private topologyTemplateService: TopologyTemplateService, + private componentInstanceService: ComponentInstanceServiceNg2, private modalService: SdcUiServices.ModalService, private translateService: TranslateService, private groupByPipe: GroupByPipe) { @@ -176,6 +182,15 @@ export class PropertiesTabComponent implements OnInit { } } + private initComponentOccurrences = (): void => { + if (this.component instanceof FullComponentInstance) { + if(this.component.minOccurrences != null && this.component.maxOccurrences != null){ + this.isOccurrencesEnabled = true; + } + this.isUnboundedChecked = this.component.maxOccurrences == "UNBOUNDED" ? true: false; + } + } + /** * This function is checking if the component is the value owner of the current property * in order to notify the edit property modal which fields to disable @@ -208,5 +223,58 @@ export class PropertiesTabComponent implements OnInit { private initPropertiesAndAttributes = (): void => { this.initComponentProperties(); this.initComponentAttributes(); + this.initComponentOccurrences(); + } + + onUnboundedChanged(component: ComponentInstance) { + this.isUnboundedChecked = !this.isUnboundedChecked; + component.maxOccurrences = this.isUnboundedChecked ? "UNBOUNDED" : "1"; + } + + private updateComponentInstance(component: ComponentInstance) { + this.store.dispatch(new TogglePanelLoadingAction({isLoading: true})); + + this.componentInstanceService.updateComponentInstance(this.workspaceService.metadata.componentType, + this.workspaceService.metadata.uniqueId, component) + .subscribe((updatedComponentInstance: ComponentInstance) => { + component = new ComponentInstance(updatedComponentInstance); + this.compositionService.getComponentInstances().find((item) => item.uniqueId === component.uniqueId).maxOccurrences = component.maxOccurrences; + this.compositionService.getComponentInstances().find((item) => item.uniqueId === component.uniqueId).minOccurrences = component.minOccurrences; + this.store.dispatch(new TogglePanelLoadingAction({isLoading: false})); + }, (error:any) => { + this.store.dispatch(new TogglePanelLoadingAction({isLoading: false})); + if (error) { + console.log(error); + }}); + } + + private enableOccurrences = () => { + if(this.component instanceof FullComponentInstance){ + if(!this.isOccurrencesEnabled){ + this.component.minOccurrences = null; + this.component.maxOccurrences = null; + } else { + this.component.minOccurrences = "1"; + this.component.maxOccurrences = "1"; + } + this.updateComponentInstance(this.component); + } + } + + private isOccurrencesFormValid(component: FullComponentInstance) { + if( + component.minOccurrences && parseInt(component.minOccurrences) >= 0 && + component.maxOccurrences && (parseInt(component.maxOccurrences) >= parseInt(component.minOccurrences) || component.maxOccurrences === "UNBOUNDED") + ) { + return true; + } else { + return false; + } + } + + private saveOccurrences = () => { + if(this.component instanceof FullComponentInstance && this.isOccurrencesFormValid(this.component)) { + this.updateComponentInstance(this.component); + } } } diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ComponentInstanceDataDefinition.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ComponentInstanceDataDefinition.java index afcc0e6d9f..ce8dda0b39 100644 --- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ComponentInstanceDataDefinition.java +++ b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ComponentInstanceDataDefinition.java @@ -53,6 +53,8 @@ public class ComponentInstanceDataDefinition extends ToscaDataDefinition { setDescription(dataDefinition.getDescription()); setPosX(dataDefinition.getPosX()); setPosY(dataDefinition.getPosY()); + setMinOccurrences(dataDefinition.getMinOccurrences()); + setMaxOccurrences(dataDefinition.getMaxOccurrences()); setPropertyValueCounter(dataDefinition.getPropertyValueCounter()); setNormalizedName(dataDefinition.getNormalizedName()); setOriginType(dataDefinition.getOriginType()); @@ -138,6 +140,22 @@ public class ComponentInstanceDataDefinition extends ToscaDataDefinition { setToscaPresentationValue(JsonPresentationFields.CI_POS_Y, posY); } + public String getMinOccurrences() { + return (String) getToscaPresentationValue(JsonPresentationFields.CI_MIN_OCCURRENCES); + } + + public void setMinOccurrences(String minOccurrences) { + setToscaPresentationValue(JsonPresentationFields.CI_MIN_OCCURRENCES, minOccurrences); + } + + public String getMaxOccurrences() { + return (String) getToscaPresentationValue(JsonPresentationFields.CI_MAX_OCCURRENCES); + } + + public void setMaxOccurrences(String maxOccurrences) { + setToscaPresentationValue(JsonPresentationFields.CI_MAX_OCCURRENCES, maxOccurrences); + } + public String getComponentUid() { return (String) getToscaPresentationValue(JsonPresentationFields.CI_COMPONENT_UID); } @@ -346,7 +364,8 @@ public class ComponentInstanceDataDefinition extends ToscaDataDefinition { + getAttributeValueCounter() + ", inputValueCounter=" + getInputValueCounter() + ", originType=" + getOriginType() + ", customizationUUID=" + getCustomizationUUID() + ", componentName=" + getComponentName() + ", componentVersion=" + getComponentVersion() + ", toscaComponentName=" - + getToscaComponentName() + ", directives =" + getDirectivesString() + "]"; + + getToscaComponentName() + ", directives =" + getDirectivesString() + ", minOccurrences =" + + getMinOccurrences() + ", maxOccurrences =" + getMaxOccurrences() +"]"; } } diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/JsonPresentationFields.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/JsonPresentationFields.java index 8fce664686..e36e4ef734 100644 --- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/JsonPresentationFields.java +++ b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/JsonPresentationFields.java @@ -200,6 +200,8 @@ public enum JsonPresentationFields { CI_IS_PROXY("isProxy", null), CI_DIRECTIVES("directives", null), CI_ARTIFACTS("artifacts", null), + CI_MAX_OCCURRENCES("maxOccurrences", null), + CI_MIN_OCCURRENCES("minOccurrences", null), //path FORWARDING_PATH("forwardingPath", null), |