Add 'required in runtime' for service inputs 67/102367/4
authorSatoshi Fujii <fujii-satoshi@jp.fujitsu.com>
Wed, 26 Feb 2020 06:39:38 +0000 (15:39 +0900)
committerOfir Sonsino <ofir.sonsino@intl.att.com>
Tue, 31 Mar 2020 05:19:29 +0000 (05:19 +0000)
User may want to set required to true for some inputs
so that make sure those input values are given at service
instantiation time.

By this change 'required in runtime' column is introduced into
service inputs table in Properties Assignment screen
and user can select required true/false for each input.

Change-Id: I0d676d2d20e02c975d51c7f4d2bb63c699743d66
Issue-ID: SDC-2659
Signed-off-by: Satoshi Fujii <fujii-satoshi@jp.fujitsu.com>
17 files changed:
catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java
catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogicTest.java
catalog-ui/cypress/fixtures/properties-assignment/service-update-inputs.json [new file with mode: 0644]
catalog-ui/cypress/integration/property-assignment.spec.js
catalog-ui/src/app/models/properties-inputs/input-fe-model.ts
catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.html
catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.less
catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.ts
catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.html
catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.less
catalog-ui/src/app/ng2/components/ui/forms/unsaved-changes/unsaved-changes.component.ts
catalog-ui/src/app/ng2/pages/properties-assignment/declare-list/declare-list.component.html
catalog-ui/src/app/ng2/pages/properties-assignment/declare-list/declare-list.component.ts
catalog-ui/src/app/ng2/pages/properties-assignment/declare-list/declare-list.module.ts
catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.module.ts
catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.html
catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts

index 02d6e0b..6b5878e 100644 (file)
@@ -93,6 +93,8 @@ public class InputsBusinessLogic extends BaseBusinessLogic {
     private static final String FAILED_TO_FOUND_INPUT_UNDER_COMPONENT_ERROR = "Failed to found input {} under component {}, error: {}";
     private static final String GOING_TO_EXECUTE_ROLLBACK_ON_CREATE_GROUP = "Going to execute rollback on create group.";
     private static final String GOING_TO_EXECUTE_COMMIT_ON_CREATE_GROUP = "Going to execute commit on create group.";
+    private static final String GOING_TO_EXECUTE_ROLLBACK_ON_UPDATE_INPUT = "Going to execute rollback on update input.";
+    private static final String GOING_TO_EXECUTE_COMMIT_ON_UPDATE_INPUT = "Going to execute commit on update input.";
     public LoggerSupportability loggerSupportability=LoggerSupportability.getLogger(InputsBusinessLogic.class.getName());
 
     private final PropertyDeclarationOrchestrator propertyDeclarationOrchestrator;
@@ -307,7 +309,8 @@ public class InputsBusinessLogic extends BaseBusinessLogic {
             if (shouldLockComp) {
                 try {
                     lockComponent(component, UPDATE_INPUT);
-                }catch (ComponentException e){
+                } catch (ComponentException e) {
+                    log.error("Failed to lock component", e);
                     result = Either.right(e.getResponseFormat());
                     return result;
                 }
@@ -337,6 +340,9 @@ public class InputsBusinessLogic extends BaseBusinessLogic {
                 String updateInputObjectValue = updateInputObjectValue(currInput, newInput, dataTypes);
                 currInput.setDefaultValue(updateInputObjectValue);
                 currInput.setOwnerId(userId);
+                if (newInput.isRequired() != null) {
+                    currInput.setRequired(newInput.isRequired());
+                }
                 Either<InputDefinition, StorageOperationStatus> status = toscaOperationFacade.updateInputOfComponent(component, currInput);
                 if(status.isRight()){
                     ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForResourceInstanceProperty(status.right().value());
@@ -347,13 +353,14 @@ public class InputsBusinessLogic extends BaseBusinessLogic {
                 }
             }
             result = Either.left(returnInputs);
-        }catch (ComponentException e) {
-            log.debug(GOING_TO_EXECUTE_ROLLBACK_ON_CREATE_GROUP);
+        } catch (ComponentException e) {
+            log.debug(GOING_TO_EXECUTE_ROLLBACK_ON_UPDATE_INPUT);
             unlockRollbackWithException(component, e);
         } catch (Exception e){
+            log.debug(GOING_TO_EXECUTE_ROLLBACK_ON_UPDATE_INPUT);
             unlockRollbackWithException(component, new ByActionStatusComponentException(ActionStatus.GENERAL_ERROR));
         }
-        log.debug(GOING_TO_EXECUTE_COMMIT_ON_CREATE_GROUP);
+        log.debug(GOING_TO_EXECUTE_COMMIT_ON_UPDATE_INPUT);
         unlockWithCommit(component);
         return result;
 
index 66e6cd3..337ea77 100644 (file)
@@ -91,13 +91,16 @@ public class InputsBusinessLogicTest {
     private static final String COMPONENT_INSTANCE_ID = "instanceId";
     private static final String COMPONENT_ID = "componentId";
     private static final String USER_ID = "userId";
-    public static final String INSTANCE_INPUT_ID = "inputId";
+    private static final String INPUT_ID = "inputId";
+    private static final String INPUT_TYPE = "string";
     private static final String LISTINPUT_NAME = "listInput";
     private static final String LISTINPUT_SCHEMA_TYPE = "org.onap.datatypes.listinput";
     private static final String LISTINPUT_PROP1_NAME = "prop1";
     private static final String LISTINPUT_PROP1_TYPE = "string";
     private static final String LISTINPUT_PROP2_NAME = "prop2";
     private static final String LISTINPUT_PROP2_TYPE = "integer";
+    private static final String OLD_VALUE = "old value";
+    private static final String NEW_VALUE = "new value";
     static ConfigurationSource configurationSource = new FSConfigurationSource(ExternalConfiguration.getChangeListener(), "src/test/resources/config/catalog-be");
     static ConfigurationManager configurationManager = new ConfigurationManager(configurationSource);
 
@@ -169,8 +172,8 @@ public class InputsBusinessLogicTest {
 
         instanceInputMap = new HashMap<>();
         ComponentInstanceInput componentInstanceInput = new ComponentInstanceInput();
-        componentInstanceInput.setInputId(INSTANCE_INPUT_ID);
-        componentInstanceInput.setName(INSTANCE_INPUT_ID);
+        componentInstanceInput.setInputId(INPUT_ID);
+        componentInstanceInput.setName(INPUT_ID);
         inputsList = Collections.singletonList(componentInstanceInput);
         instanceInputMap.put(COMPONENT_INSTANCE_ID, inputsList);
         instanceInputMap.put("someInputId", Collections.singletonList(new ComponentInstanceInput()));
@@ -752,4 +755,45 @@ public class InputsBusinessLogicTest {
         verify(propertyDeclarationOrchestrator, times(1)).unDeclarePropertiesAsInputs(service, listInput);
     }
 
+
+    @Test
+    public void test_updateInputsValue() throws Exception {
+        List<InputDefinition> oldInputDefs = new ArrayList<>();
+        InputDefinition oldInputDef = new InputDefinition();
+        oldInputDef.setUniqueId(INPUT_ID);
+        oldInputDef.setType(INPUT_TYPE);
+        oldInputDef.setDefaultValue(OLD_VALUE);
+        oldInputDef.setRequired(Boolean.FALSE);
+        oldInputDefs.add(oldInputDef);
+        service.setInputs(oldInputDefs);
+
+        List<InputDefinition> newInputDefs = new ArrayList<>();
+        InputDefinition inputDef = new InputDefinition();
+        inputDef.setUniqueId(INPUT_ID);
+        inputDef.setType(INPUT_TYPE);
+        inputDef.setDefaultValue(NEW_VALUE); // update value
+        inputDef.setRequired(Boolean.TRUE); // update value
+        newInputDefs.add(inputDef);
+
+        // used in validateComponentExists
+        when(toscaOperationFacadeMock.getToscaElement(eq(COMPONENT_ID), any(ComponentParametersView.class))).thenReturn(Either.left(service));
+        // used in lockComponent
+        when(graphLockOperation.lockComponent(COMPONENT_ID, NodeTypeEnum.Service)).thenReturn(StorageOperationStatus.OK);
+        // used in validateInputValueConstraint
+        Map<String, DataTypeDefinition> dataTypeMap = new HashMap<>();
+        when(applicationDataTypeCache.getAll()).thenReturn(Either.left(dataTypeMap)); // don't use Collections.emptyMap
+        // used in updateInputObjectValue
+        when(propertyOperation.validateAndUpdatePropertyValue(INPUT_TYPE, NEW_VALUE, true, null, dataTypeMap))
+            .thenReturn(Either.left(NEW_VALUE));
+        when(toscaOperationFacadeMock.updateInputOfComponent(service, oldInputDef))
+            .thenReturn(Either.left(inputDef));
+
+        Either<List<InputDefinition>, ResponseFormat> result =
+            testInstance.updateInputsValue(service.getComponentType(), COMPONENT_ID, newInputDefs, USER_ID, true, false);
+        assertTrue(result.isLeft());
+        // check if values are updated
+        assertEquals(service.getInputs().get(0).getDefaultValue(), NEW_VALUE);
+        assertEquals(service.getInputs().get(0).isRequired(), Boolean.TRUE);
+    }
+
 }
diff --git a/catalog-ui/cypress/fixtures/properties-assignment/service-update-inputs.json b/catalog-ui/cypress/fixtures/properties-assignment/service-update-inputs.json
new file mode 100644 (file)
index 0000000..fc0c8df
--- /dev/null
@@ -0,0 +1,221 @@
+[
+  {
+    "uniqueId": "39be5200-143f-4962-a0ad-52882c2df138.mac_requirements",
+    "type": "string",
+    "required": true,
+    "definition": false,
+    "defaultValue": "new value",
+    "description": "ddd",
+    "schema": {
+      "derivedFrom": null,
+      "constraints": null,
+      "properties": null,
+      "property": {
+        "uniqueId": null,
+        "type": "",
+        "required": false,
+        "definition": true,
+        "defaultValue": null,
+        "description": null,
+        "schema": null,
+        "password": false,
+        "name": null,
+        "value": null,
+        "label": null,
+        "hidden": false,
+        "immutable": false,
+        "inputPath": null,
+        "status": null,
+        "inputId": null,
+        "instanceUniqueId": null,
+        "propertyId": null,
+        "parentPropertyType": null,
+        "subPropertyInputPath": null,
+        "annotations": null,
+        "parentUniqueId": null,
+        "getInputValues": null,
+        "isDeclaredListInput": false,
+        "getPolicyValues": null,
+        "getInputProperty": false,
+        "schemaType": null,
+        "schemaProperty": null,
+        "version": null,
+        "ownerId": null,
+        "empty": false
+      },
+      "version": null,
+      "ownerId": null,
+      "empty": false,
+      "type": null
+    },
+    "password": false,
+    "name": "mac_requirements",
+    "value": null,
+    "label": null,
+    "hidden": false,
+    "immutable": false,
+    "inputPath": null,
+    "status": null,
+    "inputId": null,
+    "instanceUniqueId": "39be5200-143f-4962-a0ad-52882c2df138",
+    "propertyId": "39be5200-143f-4962-a0ad-52882c2df138.mac_requirements",
+    "parentPropertyType": "string",
+    "subPropertyInputPath": null,
+    "annotations": null,
+    "parentUniqueId": "cs0008",
+    "getInputValues": null,
+    "isDeclaredListInput": false,
+    "getPolicyValues": null,
+    "constraints": [],
+    "inputs": null,
+    "properties": null,
+    "getInputProperty": false,
+    "schemaType": "",
+    "schemaProperty": {
+      "uniqueId": null,
+      "type": "",
+      "required": false,
+      "definition": true,
+      "defaultValue": null,
+      "description": null,
+      "schema": null,
+      "password": false,
+      "name": null,
+      "value": null,
+      "label": null,
+      "hidden": false,
+      "immutable": false,
+      "inputPath": null,
+      "status": null,
+      "inputId": null,
+      "instanceUniqueId": null,
+      "propertyId": null,
+      "parentPropertyType": null,
+      "subPropertyInputPath": null,
+      "annotations": null,
+      "parentUniqueId": null,
+      "getInputValues": null,
+      "isDeclaredListInput": false,
+      "getPolicyValues": null,
+      "getInputProperty": false,
+      "schemaType": null,
+      "schemaProperty": null,
+      "version": null,
+      "ownerId": null,
+      "empty": false
+    },
+    "version": null,
+    "ownerId": "cs0008",
+    "empty": false
+  },
+  {
+    "uniqueId": "693b08c5-bd20-41f4-8d10-81a8d8351944.vl0_segmentation_id",
+    "type": "string",
+    "required": false,
+    "definition": false,
+    "defaultValue": null,
+    "description": null,
+    "schema": {
+      "derivedFrom": null,
+      "constraints": null,
+      "properties": null,
+      "property": {
+        "uniqueId": null,
+        "type": null,
+        "required": false,
+        "definition": true,
+        "defaultValue": null,
+        "description": null,
+        "schema": null,
+        "password": false,
+        "name": null,
+        "value": null,
+        "label": null,
+        "hidden": false,
+        "immutable": false,
+        "inputPath": null,
+        "status": null,
+        "inputId": null,
+        "instanceUniqueId": null,
+        "propertyId": null,
+        "parentPropertyType": null,
+        "subPropertyInputPath": null,
+        "annotations": null,
+        "parentUniqueId": null,
+        "getInputValues": null,
+        "isDeclaredListInput": false,
+        "getPolicyValues": null,
+        "getInputProperty": false,
+        "schemaType": null,
+        "schemaProperty": null,
+        "version": null,
+        "ownerId": null,
+        "empty": false
+      },
+      "version": null,
+      "ownerId": null,
+      "empty": false,
+      "type": null
+    },
+    "password": false,
+    "name": "vl0_segmentation_id",
+    "value": null,
+    "label": null,
+    "hidden": false,
+    "immutable": false,
+    "inputPath": null,
+    "status": null,
+    "inputId": null,
+    "instanceUniqueId": "693b08c5-bd20-41f4-8d10-81a8d8351944.6c42f981-f1d1-4b00-b54c-901a653589d2.vl0",
+    "propertyId": "6619e73b-35ea-45af-baf4-2a90c4b6baf7.segmentation_id",
+    "parentPropertyType": "string",
+    "subPropertyInputPath": null,
+    "annotations": null,
+    "parentUniqueId": "cs0008",
+    "getInputValues": null,
+    "isDeclaredListInput": false,
+    "getPolicyValues": null,
+    "constraints": [],
+    "inputs": null,
+    "properties": null,
+    "getInputProperty": false,
+    "schemaType": null,
+    "schemaProperty": {
+      "uniqueId": null,
+      "type": null,
+      "required": false,
+      "definition": true,
+      "defaultValue": null,
+      "description": null,
+      "schema": null,
+      "password": false,
+      "name": null,
+      "value": null,
+      "label": null,
+      "hidden": false,
+      "immutable": false,
+      "inputPath": null,
+      "status": null,
+      "inputId": null,
+      "instanceUniqueId": null,
+      "propertyId": null,
+      "parentPropertyType": null,
+      "subPropertyInputPath": null,
+      "annotations": null,
+      "parentUniqueId": null,
+      "getInputValues": null,
+      "isDeclaredListInput": false,
+      "getPolicyValues": null,
+      "getInputProperty": false,
+      "schemaType": null,
+      "schemaProperty": null,
+      "version": null,
+      "ownerId": null,
+      "empty": false
+    },
+    "version": null,
+    "ownerId": "cs0008",
+    "empty": false
+  }
+]
+
index bad6dee..a13f4f6 100644 (file)
@@ -12,6 +12,7 @@ describe('Test add property to self in service at property assignment page', ()
         cy.fixture('properties-assignment/service-include-policies').as('serviceIncludePolicies');
         cy.fixture('properties-assignment/service-properties').as('serviceProperty');
         cy.fixture('properties-assignment/service-update-properties').as('serviceUpdateProperty');
+        cy.fixture('properties-assignment/service-update-inputs').as('serviceUpdateInputs');
         cy.fixture('properties-assignment/service-proxy-properties').as('serviceProxyProperties');
         cy.fixture('properties-assignment/create-policies').as('createPolicy');
         cy.fixture('properties-assignment/undeclare-policy').as('undeclarePolicy');
@@ -72,4 +73,57 @@ describe('Test add property to self in service at property assignment page', ()
         cy.get('.properties-table').contains('vl 0 list');
     });
 
+    it('update input default value and required in runtime check', function () {
+        const new_value = 'new value';
+        const another_value = 'another';
+        cy.route('GET', '**/authorize', '@onapUserData');
+        cy.route('GET', '**/services/*/filteredDataByParams?include=metadata', '@metadata');
+        cy.route('GET', '**/services/*/filteredDataByParams?include=componentInstancesRelations&include=componentInstances&include=nonExcludedPolicies&include=nonExcludedGroups&include=forwardingPaths', '@fullData');
+        cy.route('GET', '**/services/*/filteredDataByParams?include=inputs&include=componentInstances&include=componentInstancesProperties&include=properties','fixture:service-proxy-tabs/full-properties');
+        cy.route('GET','**/services/*/filteredDataByParams?include=componentInstances&include=policies&include=nonExcludedGroups', '@serviceIncludePolicies');
+        cy.route('GET', '**/services/*/properties', '@serviceProperty');
+        cy.route('POST', '**/services/*/properties', '@serviceUpdateProperty');
+        cy.route('GET','**/services/*/componentInstances/*/properties','@serviceProxyProperties');
+        cy.route('POST', '**/services/*/create/policies', '@createPolicy');
+        cy.route('PUT', '**/services/*/policies/*/undeclare','@undeclarePolicy');
+        cy.route('POST', '**/services/*/update/inputs', '@serviceUpdateInputs');
+
+        const compositionPageUrl = '#!/dashboard/workspace/' + this.metadata.metadata.uniqueId + '/service/properties_assignment';
+        cy.visit(compositionPageUrl);
+
+        // Go to Inputs tab
+        cy.get('[data-tests-id="Inputs"]').trigger('click', {force: true});
+        cy.get('.table-row').should('have.length', 2);
+        cy.get('.properties-table').contains('mac_requirements');
+        cy.get('.table-body .col4 .sdc-checkbox').first().should('have.attr', 'ng-reflect-checked', 'false');
+        cy.get('[data-tests-id="properties-reverse-button"]').should('have.attr', 'disabled');
+        // Change default value
+        cy.get('.table-body .valueCol').first().find('input').type(new_value);
+        cy.get('.table-body .valueCol').first().find('input').should('have.value', new_value);
+        cy.get('[data-tests-id="properties-reverse-button"]').should('not.have.attr', 'disabled');
+        // Check a required-in-runtime checkbox
+        cy.get('.table-body .col4 .sdc-checkbox').first().find('input').click({force: true})
+        cy.get('.table-body .col4 .sdc-checkbox').first().should('have.attr', 'ng-reflect-checked', 'true');
+        cy.get('[data-tests-id="properties-reverse-button"]').should('not.have.attr', 'disabled');
+        // Click Discard button
+        cy.get('[data-tests-id="properties-reverse-button"]').click({force: true});
+        cy.get('.table-body .col4 .sdc-checkbox').first().should('have.attr', 'ng-reflect-checked', 'false');
+        cy.get('.table-body .valueCol').first().find('input').should('have.value', '');
+        // Make changes again and click Save button
+        cy.get('.table-body .valueCol').first().find('input').type(new_value);
+        cy.get('.table-body .col4 .sdc-checkbox').first().find('input').click({force: true})
+        cy.get('[data-tests-id="properties-save-button"]').click({force: true});
+        cy.get('.table-body .valueCol').first().find('input').should('have.value', new_value);
+        cy.get('.table-body .col4 .sdc-checkbox').first().should('have.attr', 'ng-reflect-checked', 'true');
+        // Make changes and try to leave the tab without saving
+        cy.get('.table-body .valueCol').first().find('input').type(another_value);
+        cy.get('.table-body .col4 .sdc-checkbox').first().find('input').click({force: true})
+        cy.get('[data-tests-id="Properties"]').trigger('click', {force: true});
+        cy.get('.sdc-modal .title').should('be.visible');
+        cy.get('.sdc-modal .title').contains('Unsaved inputs');
+        cy.get('.sdc-modal [data-tests-id="navigate-modal-button-discard"]').click({force: true});
+        cy.get('[data-tests-id="Inputs"]').trigger('click', {force: true});
+        cy.get('.table-body .valueCol').first().find('input').should('have.value', new_value);
+        cy.get('.table-body .col4 .sdc-checkbox').first().should('have.attr', 'ng-reflect-checked', 'true');
+    });
 });
index c349f41..85c514b 100644 (file)
@@ -34,6 +34,7 @@ export class InputFEModel extends InputBEModel {
     defaultValueObjOrig:any;
     defaultValueObjIsChanged:boolean;
     derivedDataType: DerivedPropertyType;
+    requiredOrig: boolean;
 
     constructor(input?: InputBEModel) {
         super(input);
@@ -47,6 +48,8 @@ export class InputFEModel extends InputBEModel {
             this.derivedDataType = this.getDerivedPropertyType();
             this.resetDefaultValueObjValidation();
             this.updateDefaultValueObjOrig();
+
+            this.requiredOrig = this.required;
         }
     }
 
@@ -77,4 +80,11 @@ export class InputFEModel extends InputBEModel {
         return !_.isEqual(this.defaultValueObj, this.defaultValueObjOrig);
     }
 
+    hasRequiredChanged(): boolean {
+        return this.required !== this.requiredOrig;
+    }
+
+    hasChanged(): boolean {
+        return this.hasDefaultValueChanged() || this.hasRequiredChanged();
+    }
 }
\ No newline at end of file
index eeba590..d3db53a 100644 (file)
@@ -29,6 +29,9 @@
             <span *ngIf="sortBy === 'type'" class="table-header-sort-arrow" [ngClass]="{'down': reverse, 'up':!reverse}">
             </span>
         </div>
+        <div class="table-cell col4" (click)="sort('required')" *ngIf="componentType == 'SERVICE'">
+            <span tooltip="Required in Runtime" tooltipDelay="400">Req. in RT</span>
+        </div>
         <div class="table-cell valueCol">Value</div>
     </div>
     <div class="table-body">
@@ -37,7 +40,9 @@
             <div class="table-row" *ngFor="let input of inputs" (click)="selectedInputId = input.path" [ngClass]="{'selected': selectedInputId && selectedInputId === input.path}">
                 <!-- Property Name -->
                 <div class="table-cell col1">
-                    <div class="inner-cell-div" tooltip="{{input.name}}"><span class="property-name">{{input.name}}</span></div>
+                    <div class="inner-cell-div">
+                        <span class="property-name" tooltip="{{input.name}}">{{input.name}}</span>
+                    </div>
                     <span *ngIf="input.description"
                           class="property-description-icon sprite-new show-desc"
                           tooltip="{{input.description}}" tooltipDelay="0"></span>
                         <span>{{input.type | contentAfterLastDot}}</span>
                     </div>
                 </div>
+                <!-- Required in runtime -->
+                <div class="table-cell col4" *ngIf="componentType == 'SERVICE'">
+                    <sdc-checkbox [(checked)]="input.required"
+                        (checkedChange)="onRequiredChanged(input, $event)"
+                        [disabled]="readonly"></sdc-checkbox>
+                </div>
                 <!-- Value -->
                 <div class="table-cell valueCol input-value-col" [class.inner-table-container]="input.childrenProperties || !input.isSimpleType">
                     <dynamic-element class="value-input"
index 72e19f3..77c002c 100644 (file)
         &:last-child {
             border-right:#d2d2d2 solid 1px;
         }
+
+        // Column: Property Name
         &.col1 {
             flex: 1 0 130px;
-            max-width:130px;
+            max-width: 250px;
 
             justify-content: space-between;
 
                 flex: 0 0 auto;
             }
         }
+
+        // Column: Type
         &.col2 {
             flex: 0 0 140px;
-            max-width:140px;
+            max-width: 140px;
         }
 
+        // Column: From Instance
         &.col3 {
-            flex:0 0 120px;
-            max-width:120px;
+            flex: 0 0 120px;
+            max-width: 120px;
+        }
+
+        // Column: Required in Runtime
+        &.col4 {
+            flex: 0 0 80px;
+            max-width: 80px;
+            text-align: center;
         }
 
+        // Column: Value
         &.valueCol {
              .value-input {
                 flex: 1;
index f45d5a8..682a3e2 100644 (file)
@@ -40,6 +40,7 @@ export class InputsTableComponent {
     @Input() instanceNamesMap: Map<string, InstanceFeDetails>;
     @Input() readonly: boolean;
     @Input() isLoading: boolean;
+    @Input() componentType: string;
     @Output() inputChanged: EventEmitter<any> = new EventEmitter<any>();
     @Output() deleteInput: EventEmitter<any> = new EventEmitter<any>();
 
@@ -47,7 +48,7 @@ export class InputsTableComponent {
     
     sortBy: String;
     reverse: boolean;
-    selectedInputToDelete: InputFEModel;    
+    selectedInputToDelete: InputFEModel;
 
     sort = (sortBy) => {
         this.reverse = (this.sortBy === sortBy) ? !this.reverse : true;
@@ -88,6 +89,10 @@ export class InputsTableComponent {
         this.inputChanged.emit(input);
     };
 
+    onRequiredChanged = (input: InputFEModel, event) => {
+        this.inputChanged.emit(input);
+    }
+
     onDeleteInput = () => {
         this.deleteInput.emit(this.selectedInputToDelete);
         this.modalService.closeCurrentModal();
index 89b85d3..af7a612 100644 (file)
@@ -27,7 +27,7 @@
             <span *ngIf="sortBy === 'type'" class="table-header-sort-arrow" [ngClass]="{'down': reverse, 'up':!reverse}">
             </span>
         </div>
-        <div class="table-cell col3" (click)="sort('schema.property.type')" *ngIf="!hidePropertyType">ES
+        <div class="table-cell col3" (click)="sort('schema.property.type')" *ngIf="!hidePropertyType">EntrySchema
             <span *ngIf="sortBy === 'schema.property.type'" class="table-header-sort-arrow" [ngClass]="{'down': reverse, 'up':!reverse}">
             </span>
         </div>
index 86832e5..8c2c6ce 100644 (file)
         &:last-child {
             border-right:#d2d2d2 solid 1px;
         }
+
+        // Column: Property Name
         &.col1 {
-            flex: 1 0 210px;
+            flex: 1 0 190px;
             max-width:300px;
             display: flex;            
             @media @smaller-screen { flex: 0 0 25%;}
                 flex: 0 0 auto;
             }
         }
+
+        // Column: Type
         &.col2 {
             flex: 0 0 150px;
             max-width:150px;
             @media @smaller-screen { flex: 0 0 20%;}
         }
 
+        // Column: ES
         &.col3 {
             flex:0 0 120px;
             max-width:120px;
             @media @smaller-screen { flex: 0 0 15%;}
         }
 
+        // Column: Value
         &.valueCol {
-            flex: 2 0 300px;
+            flex: 2 0 250px;
             display: flex;
             @media @smaller-screen { flex: 1 0 40%;}
         }
index c0bcc78..187ffa6 100644 (file)
                     [ngModelOptions]="{ debounce: 200 }">
         </div>
         
+        <!-- Required in Runtime -->
+        <div class="i-sdc-form-item">
+            <sdc-checkbox
+                [(checked)]="propertyModel.required"
+                label="Required in Runtime"
+                data-tests-id="property-required">
+            </sdc-checkbox>
+        </div>
+
         <!-- Properties -->
         <div class="i-sdc-form-item">
             <label class="i-sdc-form-label">Properties</label>
index fe31066..8ca4f44 100644 (file)
@@ -57,6 +57,7 @@ export class DeclareListComponent {
         this.propertyModel = new PropertyBEModel();
         this.propertyModel.type = '';
         this.propertyModel.schema.property.type = '';
+        this.propertyModel.required = false;
         const types: string[] =  PROPERTY_DATA.TYPES; // All types - simple type + map + list
         this.dataTypes = this.dataTypeService.getAllDataTypes(); // Get all data types in service
         const nonPrimitiveTypes: string[] = _.filter(Object.keys(this.dataTypes), (type: string) => {
index 97667f9..82e9b6f 100644 (file)
@@ -25,6 +25,7 @@ import { FormElementsModule } from 'app/ng2/components/ui/form-components/form-e
 import { UiElementsModule } from 'app/ng2/components/ui/ui-elements.module';
 import { TranslateModule } from '../../../shared/translator/translate.module';
 import { DeclareListComponent } from './declare-list.component';
+import { SdcUiComponentsModule } from 'onap-ui-angular';
 
 @NgModule({
     declarations: [
@@ -35,7 +36,8 @@ import { DeclareListComponent } from './declare-list.component';
         FormsModule,
         FormElementsModule,
         UiElementsModule,
-        TranslateModule
+        TranslateModule,
+        SdcUiComponentsModule
     ],
     exports: [],
     entryComponents: [
index f5500d4..3def63e 100644 (file)
@@ -34,6 +34,8 @@ import {HierarchyNavService} from "./services/hierarchy-nav.service";
 import {PropertiesUtils} from "./services/properties.utils";
 import {InputsUtils} from "./services/inputs.utils";
 import {ComponentModeService} from "../../services/component-services/component-mode.service";
+import {SdcUiComponentsModule} from "onap-ui-angular";
+import {ModalFormsModule} from "app/ng2/components/ui/forms/modal-forms.module";
 
 @NgModule({
     declarations: [
@@ -48,7 +50,9 @@ import {ComponentModeService} from "../../services/component-services/component-
         GlobalPipesModule,
         PropertyTableModule,
         PoliciesTableModule,
-        UiElementsModule],
+        UiElementsModule,
+        SdcUiComponentsModule,
+        ModalFormsModule],
 
     entryComponents: [PropertiesAssignmentComponent],
     exports: [
index 8d4215a..6856ae8 100644 (file)
@@ -47,6 +47,7 @@
                             [inputs]="inputs | searchFilter:'name':searchQuery"
                             [instanceNamesMap]="componentInstanceNamesMap"
                             [isLoading]="loadingInputs"
+                            [componentType]="component.componentType"
                             (deleteInput)="deleteInput($event)"
                             (inputChanged)="dataChanged($event)">
                         </inputs-table>
index 4b84f0e..725847b 100644 (file)
@@ -348,7 +348,7 @@ export class PropertiesAssignmentComponent {
         if (this.isPropertiesTabSelected && item instanceof PropertyFEModel) {
             itemHasChanged = item.hasValueObjChanged();
         } else if (this.isInputsTabSelected && item instanceof InputFEModel) {
-            itemHasChanged = item.hasDefaultValueChanged();
+            itemHasChanged = item.hasChanged();
         } else if (this.isPoliciesTabSelected && item instanceof InputFEModel) {
             itemHasChanged = item.hasDefaultValueChanged();
         }
@@ -574,16 +574,17 @@ export class PropertiesAssignmentComponent {
                         let typelist: any = PROPERTY_TYPES.LIST;
                         let uniID: any = insId;
                         let boolfalse: any = false;
+                        let required: any = content.propertyModel.required;
                         let schem :any = {
                             "empty": boolfalse,
                             "property": {
                                 "type": content.propertyModel.simpleType,
-                                "required": boolfalse
+                                "required": required
                             }
                         }
                         let schemaProp :any = {
                             "type": content.propertyModel.simpleType,
-                            "required": boolfalse
+                            "required": required
                         }
 
                         reglistInput.description = content.propertyModel.description;
@@ -592,7 +593,7 @@ export class PropertiesAssignmentComponent {
                         reglistInput.schemaType = content.propertyModel.simpleType;
                         reglistInput.instanceUniqueId = uniID;
                         reglistInput.uniqueId = uniID;
-                        reglistInput.required =boolfalse;
+                        reglistInput.required = required;
                         reglistInput.schema = schem;
                         reglistInput.schemaProperty = schemaProp;
 
@@ -789,6 +790,8 @@ export class PropertiesAssignmentComponent {
                     response.forEach((resInput) => {
                         const changedInput = <InputFEModel>this.changedData.shift();
                         this.inputsUtils.resetInputDefaultValue(changedInput, resInput.defaultValue);
+                        changedInput.required = resInput.required;
+                        changedInput.requiredOrig = resInput.required;
                     });
                     console.log("updated the component inputs and got this response: ", response);
                 }
@@ -842,6 +845,7 @@ export class PropertiesAssignmentComponent {
             handleReverseItem = (changedItem) => {
                 changedItem = <InputFEModel>changedItem;
                 this.inputsUtils.resetInputDefaultValue(changedItem, changedItem.defaultValue);
+                changedItem.required = changedItem.requiredOrig;
             };
         }
 
@@ -906,8 +910,8 @@ export class PropertiesAssignmentComponent {
                         {id: 'cancelButton', text: 'Cancel', type: SdcUiCommon.ButtonType.secondary, size: 'xsm', closeModal: true, callback: () => reject()},
                         {id: 'discardButton', text: 'Discard', type: SdcUiCommon.ButtonType.secondary, size: 'xsm', closeModal: true, callback: () => { this.reverseChangedData(); resolve()}},
                         {id: 'saveButton', text: 'Save', type: SdcUiCommon.ButtonType.primary, size: 'xsm', closeModal: true, disabled: !this.isValidChangedData, callback: () => this.doSaveChangedData(resolve, reject)}
-                ] as SdcUiCommon.IModalButtonComponent[]
-            } as SdcUiCommon.IModalConfig, UnsavedChangesComponent, {isValidChangedData: this.isValidChangedData});
+                    ] as SdcUiCommon.IModalButtonComponent[]
+                } as SdcUiCommon.IModalConfig, UnsavedChangesComponent, {isValidChangedData: this.isValidChangedData});
         });
 
     }