diff options
author | KrupaNagabhushan <krupa.nagabhushan@est.tech> | 2020-11-19 14:28:00 +0000 |
---|---|---|
committer | Christophe Closset <christophe.closset@intl.att.com> | 2021-01-14 13:56:39 +0000 |
commit | 3849231a17930b1bb2ba09af15673bfd07538b9d (patch) | |
tree | 9ca26d4457093bbb30924d6731b5615e795ed238 | |
parent | 0d38c9a8ed4701b860901f67049920e9b1ca72f2 (diff) |
Create inputs independent of properties
Issue-ID: SDC-3431
Signed-off-by: KrupaNagabhushan <krupa.nagabhushan@est.tech>
Change-Id: I4f29d0e490a14292fd1aa9f96ca6621b37f325d8
13 files changed, 353 insertions, 20 deletions
diff --git a/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml b/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml index 4aa93cb268..ecaf852a16 100644 --- a/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml +++ b/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml @@ -2410,10 +2410,23 @@ errors: message: 'Error: Invalid Content. %1 has invalid format.', messageId: "SVC4723" } -#---------SVC4732------------------------------ +#---------SVC4734------------------------------ # %1 - list of validation errors INVALID_PM_DICTIONARY_FILE: { code: 400, message: 'Error: Invalid PM Dictionary File. %1', - messageId: "SVC4732" + messageId: "SVC4734" + } +#-----------SVC4735--------------------------- + #%1 - input name + INPUT_ALREADY_EXIST: { + code: 409, + message: "Error: Input with '%1' name already exists.", + messageId: "SVC4735" + } +#---------SVC4736------------------------------ + INVALID_INPUT_NAME: { + code: 400, + message: "Error: Input name contains invalid characters. It should have only letters, numbers and underscores.", + messageId: "SVC4736" } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java index 69adb90493..5b197de183 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java @@ -23,6 +23,7 @@ package org.openecomp.sdc.be.components.impl; import fj.data.Either; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections4.ListUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang.BooleanUtils; @@ -33,6 +34,7 @@ import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponent import org.openecomp.sdc.be.components.impl.exceptions.ComponentException; import org.openecomp.sdc.be.components.property.PropertyDeclarationOrchestrator; import org.openecomp.sdc.be.components.validation.ComponentValidations; +import org.openecomp.sdc.be.config.BeEcompErrorManager; import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus; import org.openecomp.sdc.be.dao.utils.MapUtil; @@ -40,7 +42,9 @@ import org.openecomp.sdc.be.datamodel.utils.PropertyValueConstraintValidationUti import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition; +import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.ComponentInstInputsMap; import org.openecomp.sdc.be.model.ComponentInstListInput; import org.openecomp.sdc.be.model.ComponentInstance; @@ -61,15 +65,16 @@ import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter; import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation; import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; +import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils; import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; import org.openecomp.sdc.be.model.tosca.converters.PropertyValueConverter; +import org.openecomp.sdc.be.resources.data.EntryData; import org.openecomp.sdc.common.log.elements.LoggerSupportability; import org.openecomp.sdc.common.log.enums.LoggerSupportabilityActions; import org.openecomp.sdc.common.log.enums.StatusCode; import org.openecomp.sdc.common.log.wrappers.Logger; import org.openecomp.sdc.exception.ResponseFormat; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.Arrays; @@ -81,7 +86,7 @@ import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; -@Component("inputsBusinessLogic") +@org.springframework.stereotype.Component("inputsBusinessLogic") public class InputsBusinessLogic extends BaseBusinessLogic { private static final String CREATE_INPUT = "CreateInput"; @@ -874,4 +879,105 @@ public class InputsBusinessLogic extends BaseBusinessLogic { } + public Either<EntryData<String, InputDefinition>, ResponseFormat> addInputToComponent(String componentId, + String inputName, + InputDefinition newInputDefinition, + String userId) { + Either<EntryData<String, InputDefinition>, ResponseFormat> result = null; + + validateUserExists(userId); + + Either<Component, StorageOperationStatus> serviceElement = + toscaOperationFacade.getToscaElement(componentId); + if (serviceElement.isRight()) { + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, "")); + return result; + } + + Component component = serviceElement.left().value(); + NodeTypeEnum nodeType = component.getComponentType().getNodeType(); + + StorageOperationStatus lockResult = graphLockOperation.lockComponent(componentId, nodeType); + if (!lockResult.equals(StorageOperationStatus.OK)) { + BeEcompErrorManager.getInstance() + .logBeFailedLockObjectError(CREATE_INPUT, nodeType.name().toLowerCase(), componentId); + log.info("Failed to lock component {}. Error - {}", componentId, lockResult); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + return result; + } + + try { + if (!ComponentValidationUtils.canWorkOnComponent(component, userId)) { + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); + return result; + } + + List<InputDefinition> inputs = component.getInputs(); + + if (CollectionUtils.isEmpty(inputs)) { + inputs = new ArrayList<>(); + } + + if (isInputExistInComponent(inputs, inputName)) { + + result = Either.right(componentsUtils.getResponseFormat(ActionStatus + .INPUT_ALREADY_EXIST, inputName)); + return result; + } + + Map<String, DataTypeDefinition> allDataTypes = getAllDataTypes(applicationDataTypeCache); + + // validate input default values + Either<Boolean, ResponseFormat> defaultValuesValidation = validatePropertyDefaultValue( + newInputDefinition, allDataTypes); + if (defaultValuesValidation.isRight()) { + result = Either.right(defaultValuesValidation.right().value()); + return result; + } + + // convert Input + ToscaPropertyType type = getType(newInputDefinition.getType()); + if (type != null) { + PropertyValueConverter converter = type.getConverter(); + // get inner type + String innerType = null; + SchemaDefinition schema = newInputDefinition.getSchema(); + if (schema != null) { + PropertyDataDefinition prop = schema.getProperty(); + if (prop != null) { + innerType = prop.getType(); + } + } + if (newInputDefinition.getDefaultValue() != null) { + String convertedValue = converter + .convert(newInputDefinition.getDefaultValue(), innerType, allDataTypes); + newInputDefinition.setDefaultValue(convertedValue); + } + } + + Either<InputDefinition, StorageOperationStatus> addInputEither = + toscaOperationFacade.addInputToComponent(inputName, newInputDefinition, component); + + if (addInputEither.isRight()) { + log.info("Failed to add new input {}. Error - {}", componentId, + addInputEither.right().value()); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus + .GENERAL_ERROR)); + return result; + } + + result = Either.left(new EntryData<>(inputName, newInputDefinition)); + return result; + } finally { + commitOrRollback(result); + // unlock component + graphLockOperation.unlockComponent(componentId, nodeType); + } + } + + private boolean isInputExistInComponent(List<InputDefinition> inputs, String inputName) { + return CollectionUtils.isNotEmpty(inputs) && + inputs.stream().anyMatch(input -> input.getName().equals(inputName)); + } + } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java index b497b702c3..1a8a305d2a 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java @@ -68,6 +68,7 @@ import org.openecomp.sdc.be.impl.WebAppContextWrapper; import org.openecomp.sdc.be.model.ComponentInstInputsMap; import org.openecomp.sdc.be.model.PropertyConstraint; import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.InputDefinition; import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.be.model.operations.impl.PropertyOperation; import org.openecomp.sdc.be.model.operations.impl.PropertyOperation.PropertyConstraintJacksonDeserializer; @@ -393,6 +394,19 @@ public class BeGenericServlet extends BasicServlet { return Either.left(propertyDefinition); } + private Either<InputDefinition, ActionStatus> getInputDefinitionFromJson(String componentId, String inputName, JSONObject value) { + String jsonString = value.toJSONString(); + Either<InputDefinition, ActionStatus> convertJsonToObject = convertJsonToObject(jsonString, InputDefinition.class); + if (convertJsonToObject.isRight()) { + return Either.right(convertJsonToObject.right().value()); + } + InputDefinition inputDefinition = convertJsonToObject.left().value(); + String uniqueId = UniqueIdBuilder.buildPropertyUniqueId(componentId, inputName); + inputDefinition.setUniqueId(uniqueId); + + return Either.left(inputDefinition); + } + protected Either<Map<String, PropertyDefinition>, ActionStatus> getPropertiesListForUpdate(String data) { Map<String, PropertyDefinition> properties = new HashMap<>(); @@ -421,7 +435,6 @@ public class BeGenericServlet extends BasicServlet { } - protected String propertyToJson(Map.Entry<String, PropertyDefinition> property) { JSONObject root = new JSONObject(); String propertyName = property.getKey(); @@ -565,4 +578,45 @@ public class BeGenericServlet extends BasicServlet { return getInputBL(context); } + + protected Either<Map<String, InputDefinition>, ActionStatus> getInputModel(String componentId, String data) { + JSONParser parser = new JSONParser(); + JSONObject root; + try { + Map<String, InputDefinition> inputs = new HashMap<>(); + root = (JSONObject) parser.parse(data); + + Set entrySet = root.entrySet(); + Iterator iterator = entrySet.iterator(); + while (iterator.hasNext()) { + Entry next = (Entry) iterator.next(); + String inputName = (String) next.getKey(); + + if(!isInputNameValid(inputName)) { + return Either.right(ActionStatus.INVALID_INPUT_NAME); + } + + JSONObject value = (JSONObject) next.getValue(); + Either<InputDefinition, ActionStatus> inputDefinitionEither = + getInputDefinitionFromJson(componentId, inputName, value); + + if(inputDefinitionEither.isRight()) { + return Either.right(inputDefinitionEither.right().value()); + } + + inputs.put(inputName, inputDefinitionEither.left().value()); + } + + return Either.left(inputs); + } catch (ParseException e) { + log.warn("Input content is invalid - {}", data, e); + return Either.right(ActionStatus.INVALID_CONTENT); + } + } + + protected boolean isInputNameValid(String inputName) { + return Objects.nonNull(inputName) + && inputName.matches(PROPERTY_NAME_REGEX); + + } } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/InputsServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/InputsServlet.java index bff8436fa4..1f80b4be87 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/InputsServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/InputsServlet.java @@ -57,6 +57,7 @@ import org.openecomp.sdc.be.model.InputDefinition; import org.openecomp.sdc.be.model.Resource; import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.resources.data.EntryData; import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; import org.openecomp.sdc.be.user.UserBusinessLogic; import org.openecomp.sdc.common.api.Constants; @@ -84,6 +85,7 @@ import javax.ws.rs.core.Response; import java.io.IOException; import java.util.Arrays; import java.util.List; +import java.util.Map; @Loggable(prepend = true, value = Loggable.DEBUG, trim = false) @Tags({@Tag(name = "SDC Internal APIs")}) @@ -97,6 +99,7 @@ public class InputsServlet extends AbstractValidationsServlet { private static final Logger log = Logger.getLogger(InputsServlet.class); private static final LoggerSupportability loggerSupportability = LoggerSupportability.getLogger(InputsServlet.class.getName()); private static final String START_HANDLE_REQUEST_OF = "(get) Start handle request of {}"; + private static final String CREATE_INPUT = "CreateInput"; private final DataTypeBusinessLogic businessLogic; private final InputsBusinessLogic inputsBusinessLogic; @@ -334,6 +337,21 @@ public class InputsServlet extends AbstractValidationsServlet { DeclarationTypeEnum.INPUT, request); } + @POST + @Path("/{componentType}/{componentId}/create/input") + @Operation(description = "Create inputs on service", method = "POST", summary = "Return inputs list", responses = { + @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Resource.class)))), + @ApiResponse(responseCode = "200", description = "Component found"), + @ApiResponse(responseCode = "403", description = "Restricted operation"), + @ApiResponse(responseCode = "404", description = "Component not found")}) + public Response createInput(@PathParam("componentType") final String componentType, + @PathParam("componentId") final String componentId, @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId, + @Parameter(description = "ComponentIns Inputs Object to be created", + required = true) String componentInstInputsMapObj) { + + return createInput(componentId, componentInstInputsMapObj, request, userId); + } /** * Creates a "list input" and updates given list of properties to get value from the input. @@ -566,4 +584,48 @@ public class InputsServlet extends AbstractValidationsServlet { return response; } } + + private Response createInput(String componentId, String data, HttpServletRequest request,String userId) { + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {} modifier id is {} data is {}", url, userId, data); + loggerSupportability.log(LoggerSupportabilityActions.CREATE_INPUTS, StatusCode.STARTED,"CREATE_INPUTS by user {} ", userId); + + try{ + Either<Map<String, InputDefinition>, ActionStatus> inputDefinition = + getInputModel(componentId, data); + if (inputDefinition.isRight()) { + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(inputDefinition.right().value()); + return buildErrorResponse(responseFormat); + } + + Map<String, InputDefinition> inputs = inputDefinition.left().value(); + if (inputs == null || inputs.size() != 1) { + log.info("Input content is invalid - {}", data); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT); + return buildErrorResponse(responseFormat); + } + + Map.Entry<String, InputDefinition> entry = inputs.entrySet().iterator().next(); + InputDefinition newInputDefinition = entry.getValue(); + newInputDefinition.setParentUniqueId(componentId); + String inputName = newInputDefinition.getName(); + + Either<EntryData<String, InputDefinition>, ResponseFormat> addInputEither = + inputsBusinessLogic.addInputToComponent(componentId, inputName, newInputDefinition, userId); + + if(addInputEither.isRight()) { + return buildErrorResponse(addInputEither.right().value()); + } + + loggerSupportability.log(LoggerSupportabilityActions.CREATE_INPUTS, StatusCode.COMPLETE,"CREATE_INPUTS by user {} ", userId); + return buildOkResponse(newInputDefinition); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError(CREATE_INPUT); + log.debug("create input failed with exception", e); + ResponseFormat responseFormat = + getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + } + } } diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java index 09a941347c..1d0c54b747 100644 --- a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java @@ -100,6 +100,8 @@ public enum ActionStatus { // Inputs INPUT_IS_NOT_CHILD_OF_COMPONENT, CFVC_LOOP_DETECTED, + INPUT_ALREADY_EXIST, + //Forwarding Path related FORWARDING_PATH_NAME_MAXIMUM_LENGTH, FORWARDING_PATH_NAME_ALREADY_IN_USE, FORWARDING_PATH_NAME_EMPTY, FORWARDING_PATH_PROTOCOL_MAXIMUM_LENGTH, FORWARDING_PATH_DESTINATION_PORT_MAXIMUM_LENGTH, @@ -158,6 +160,7 @@ public enum ActionStatus { INTERFACE_LIFECYCLE_TYPES_NOT_FOUND, INVALID_PROPERTY_NAME, + INVALID_INPUT_NAME, //Property Constraints INVALID_PROPERTY_CONSTRAINTS, INVALID_PROPERTY_CONSTRAINTS_FORMAT, CANNOT_DELETE_VALID_VALUES, diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java index 957c5f9d66..532a641e2f 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java @@ -2482,6 +2482,46 @@ public class ToscaOperationFacade { return Either.left(newProperty); } + public Either<InputDefinition, StorageOperationStatus> addInputToComponent(String inputName, + InputDefinition newInputDefinition, + Component component) { + newInputDefinition.setName(inputName); + + StorageOperationStatus status = getToscaElementOperation(component) + .addToscaDataToToscaElement(component.getUniqueId(), EdgeLabelEnum.INPUTS, VertexTypeEnum.INPUTS, newInputDefinition, JsonPresentationFields.NAME); + if (status != StorageOperationStatus.OK) { + CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to add the input {} to the component {}. Status is {}. ", inputName, component.getName(), status); + return Either.right(status); + } + + ComponentParametersView filter = new ComponentParametersView(true); + filter.setIgnoreProperties(false); + filter.setIgnoreInputs(false); + Either<Component, StorageOperationStatus> getUpdatedComponentRes = getToscaElement(component.getUniqueId(), filter); + if (getUpdatedComponentRes.isRight()) { + CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to get updated component {}. Status is {}. ", component.getUniqueId(), getUpdatedComponentRes.right().value()); + return Either.right(status); + } + + InputDefinition newInput = null; + List<InputDefinition> inputs = + (getUpdatedComponentRes.left().value()).getInputs(); + if (CollectionUtils.isNotEmpty(inputs)) { + Optional<InputDefinition> inputOptional = inputs.stream().filter( + inputEntry -> inputEntry.getName().equals(inputName)).findAny(); + if (inputOptional.isPresent()) { + newInput = inputOptional.get(); + } + } + if (newInput == null) { + CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to find recently added input {} " + + "on the component {}. Status is {}. ", inputs, component.getUniqueId(), StorageOperationStatus.NOT_FOUND); + return Either.right(StorageOperationStatus.NOT_FOUND); + } + + return Either.left(newInput); + } + public StorageOperationStatus deletePropertyOfComponent(Component component, String propertyName) { return getToscaElementOperation(component).deleteToscaDataElement(component.getUniqueId(), EdgeLabelEnum.PROPERTIES, VertexTypeEnum.PROPERTIES, propertyName, JsonPresentationFields.NAME); } @@ -2536,8 +2576,7 @@ public class ToscaOperationFacade { return result; } - - public Either<AttributeDataDefinition, StorageOperationStatus> addAttributeOfResource(Component component, AttributeDataDefinition newAttributeDef) { + public Either<AttributeDataDefinition, StorageOperationStatus> addAttributeOfResource(Component component, AttributeDataDefinition newAttributeDef) { Either<Component, StorageOperationStatus> getUpdatedComponentRes = null; Either<AttributeDataDefinition, StorageOperationStatus> result = null; diff --git a/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.html b/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.html index ee090245f0..e1638fb00f 100644 --- a/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.html +++ b/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.html @@ -49,6 +49,9 @@ <span *ngIf="input.description" class="property-description-icon sprite-new show-desc" tooltip="{{input.description}}" tooltipDelay="0"></span> + <div class="delete-button-container"> + <span *ngIf="showDelete" class="sprite-new delete-btn" (click)="openDeleteModal(input)" data-tests-id="delete-input-button"></span> + </div> </div> <!-- From Instance --> <div class="table-cell col3"> @@ -124,9 +127,6 @@ [testId]="'input-' + input.name" [constraints] = "getConstraints(input)"> </dynamic-element> - <div class="delete-button-container"> - <span *ngIf="input.instanceUniqueId && !readonly" class="sprite-new delete-btn" (click)="openDeleteModal(input)" data-tests-id="delete-input-button"></span> - </div> </div> </div> </div> diff --git a/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.less b/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.less index 74520b6314..ae6d58e72e 100644 --- a/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.less +++ b/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.less @@ -182,7 +182,8 @@ // Column: Property Name &.col1 { flex: 1 0 130px; - max-width: 250px; + max-width: 300px; + display: flex; justify-content: space-between; diff --git a/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.ts b/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.ts index 3fa7ab4a80..5ca119c075 100644 --- a/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.ts +++ b/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.ts @@ -43,14 +43,14 @@ export class InputsTableComponent { @Input() readonly: boolean; @Input() isLoading: boolean; @Input() componentType: string; - + @Input() showDelete:boolean; @Output() inputChanged: EventEmitter<any> = new EventEmitter<any>(); @Output() deleteInput: EventEmitter<any> = new EventEmitter<any>(); @Input() fePropertiesMap: InstanceFePropertiesMap; @ViewChildren('metadataViewChildren') public metadataViewChildren: QueryList<DynamicElementComponent>; - + sortBy: String; reverse: boolean; selectedInputToDelete: InputFEModel; @@ -107,15 +107,15 @@ export class InputsTableComponent { var mapKeyError = input.metadataMapKeyError; if(input.metadataMapKeyError){ dynamicElementComponent.cmpRef.instance.control.setErrors({mapKeyError}); - } + } }; onMetadataValueChanged = (input: InputFEModel, event, metadataEntry: MetadataEntry) => { input.updateMetadataValue(metadataEntry, event.value); this.inputChanged.emit(input); }; - - + + createNewMetadataEntry = (input: InputFEModel): void => { let metadataEntry = new MetadataEntry("", ""); input.addMetadataEntry(metadataEntry); @@ -126,7 +126,7 @@ export class InputsTableComponent { input.deleteMetadataEntry(metadataEntry); this.inputChanged.emit(input); } - + onDeleteInput = () => { this.deleteInput.emit(this.selectedInputToDelete); this.modalService.closeCurrentModal(); diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.html b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.html index 6856ae8358..6b3e92adfd 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.html +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.html @@ -44,6 +44,7 @@ <inputs-table class="properties-table" [fePropertiesMap]="instanceFePropertiesMap" [readonly]="isReadonly" + [showDelete]="!isReadOnly && isSelf()" [inputs]="inputs | searchFilter:'name':searchQuery" [instanceNamesMap]="componentInstanceNamesMap" [isLoading]="loadingInputs" @@ -80,8 +81,10 @@ </div> </div> <div class="right-column"> - <div *ngIf="!isReadonly" class="add-btn" + <div *ngIf="!isReadonly && !isInputsTabSelected" class="add-btn" (click)="addProperty()" [ngClass]="{'disabled': !isSelf()}">Add Property</div> + <div *ngIf="!isReadonly && isInputsTabSelected" class="add-btn" + (click)="addInput()" [ngClass]="{'disabled': !isSelf()}">Add Input</div> <tabs #hierarchyNavTabs tabStyle="simple-tabs" class="gray-border"> <tab tabTitle="Composition"> <div class="hierarchy-nav-container"> diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts index e4a8749386..74e2680b80 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts @@ -1052,6 +1052,41 @@ export class PropertiesAssignmentComponent { modal.instance.open(); } + /*** addInput ***/ + addInput = () => { + let modalTitle = 'Add Input'; + let modal = this.ModalService.createCustomModal(new ModalModel( + 'sm', + modalTitle, + null, + [ + new ButtonModel('Save', 'blue', () => { + modal.instance.dynamicContent.instance.isLoading = true; + const newInput: InputBEModel = modal.instance.dynamicContent.instance.propertyModel; + this.topologyTemplateService.createServiceInput(this.component.uniqueId, newInput) + .subscribe((response) => { + modal.instance.dynamicContent.instance.isLoading = false; + const newInputProp: InputFEModel = this.inputsUtils.convertInputBEToInputFE(response); + this.inputs.push(newInputProp); + modal.instance.close(); + }, (error) => { + modal.instance.dynamicContent.instance.isLoading = false; + this.Notification.error({ + message: 'Failed to add input:' + error, + title: 'Failure' + }); + }); + }, () => !modal.instance.dynamicContent.instance.checkFormValidForSubmit()), + new ButtonModel('Cancel', 'outline grey', () => { + modal.instance.close(); + }), + ], + null + )); + this.ModalService.addDynamicContentToModal(modal, PropertyCreatorComponent, {}); + modal.instance.open(); + } + /*** SEARCH RELATED FUNCTIONS ***/ searchPropertiesInstances = (filterData:FilterPropertiesAssignmentData) => { let instanceBePropertiesMap:InstanceBePropertiesMap; diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/services/inputs.utils.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/services/inputs.utils.ts index 408a00e7b4..948c9032bf 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/services/inputs.utils.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/services/inputs.utils.ts @@ -19,12 +19,13 @@ */ import { Injectable } from '@angular/core'; -import { InputFEModel} from "app/models"; +import { InputBEModel, InputFEModel } from "app/models"; +import { DataTypeService } from "app/ng2/services/data-type.service"; @Injectable() export class InputsUtils { - constructor() {} + constructor(private dataTypeService:DataTypeService) {} public initDefaultValueObject = (input: InputFEModel): void => { input.resetDefaultValueObjValidation(); @@ -37,4 +38,10 @@ export class InputsUtils { this.initDefaultValueObject(input); } + public convertInputBEToInputFE = (input: InputBEModel): InputFEModel => { + const newFEInput: InputFEModel = new InputFEModel(input); //Convert input to FE + this.initDefaultValueObject(newFEInput); + return newFEInput; + } + } diff --git a/catalog-ui/src/app/ng2/services/component-services/topology-template.service.ts b/catalog-ui/src/app/ng2/services/component-services/topology-template.service.ts index 14bf84599c..492acdc1d6 100644 --- a/catalog-ui/src/app/ng2/services/component-services/topology-template.service.ts +++ b/catalog-ui/src/app/ng2/services/component-services/topology-template.service.ts @@ -227,6 +227,16 @@ export class TopologyTemplateService { }); } + createServiceInput(componentId: string, inputModel: InputBEModel): Observable<InputBEModel> { + const serverObject = {}; + serverObject[inputModel.name] = inputModel; + return this.http.post<InputBEModel>(this.baseUrl + 'services/' + componentId + '/create/input', serverObject) + .map((res) => { + const input: InputBEModel = new InputBEModel(res); + return input; + }); + } + getDependencies(componentType: string, componentId: string): Observable<IDependenciesServerResponse[]> { return this.http.get<IDependenciesServerResponse[]>(this.baseUrl + this.getServerTypeUrl(componentType) + componentId + '/dependencies'); } |