aboutsummaryrefslogtreecommitdiffstats
path: root/catalog-ui/src/app/view-models/workspace/tabs/inputs
diff options
context:
space:
mode:
Diffstat (limited to 'catalog-ui/src/app/view-models/workspace/tabs/inputs')
-rw-r--r--catalog-ui/src/app/view-models/workspace/tabs/inputs/inputs.less225
-rw-r--r--catalog-ui/src/app/view-models/workspace/tabs/inputs/resource-input/resource-inputs-view-model.ts117
-rw-r--r--catalog-ui/src/app/view-models/workspace/tabs/inputs/resource-input/resource-inputs-view.html86
-rw-r--r--catalog-ui/src/app/view-models/workspace/tabs/inputs/resource-input/resource-inputs.less9
-rw-r--r--catalog-ui/src/app/view-models/workspace/tabs/inputs/service-input/service-inputs-view-model.ts378
-rw-r--r--catalog-ui/src/app/view-models/workspace/tabs/inputs/service-input/service-inputs-view.html134
-rw-r--r--catalog-ui/src/app/view-models/workspace/tabs/inputs/service-input/service-inputs.less47
7 files changed, 996 insertions, 0 deletions
diff --git a/catalog-ui/src/app/view-models/workspace/tabs/inputs/inputs.less b/catalog-ui/src/app/view-models/workspace/tabs/inputs/inputs.less
new file mode 100644
index 0000000000..eff5c5395b
--- /dev/null
+++ b/catalog-ui/src/app/view-models/workspace/tabs/inputs/inputs.less
@@ -0,0 +1,225 @@
+.workspace-inputs {
+
+ .sdc-workspace-container .w-sdc-main-right-container .w-sdc-main-container-body-content {
+ padding: 25px 8% 25px 8%;
+ }
+
+ .w-sdc-main-container .w-sdc-main-right-container > div:first-child {
+ /* scroll fix */
+ padding-bottom: 0px;
+ }
+
+
+ width: 100%;
+ display: flex;
+
+ .text {
+ padding-left: 15px;
+ .no-overflow;
+ }
+
+ .title-text {
+ color: @main_color_m;
+ .f-type._13_m;
+ .bold;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ }
+
+ .no-overflow {
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+ }
+
+ .title-blue-text {
+ color: @main_color_a;
+ .f-type._13_m;
+
+ &.property-name-text {
+ padding-right: 13px;
+ border-right: 1px solid rgba(120, 136, 148, 0.26);
+ flex-grow: 1;
+ .no-overflow;
+ }
+ }
+
+ .instance-name-text {
+ flex-grow: 1;
+ }
+
+ ng-include {
+ width: 45%;
+ }
+
+ .w-sdc-inputs-search {
+ padding: 10px 20px 20px 0;
+ white-space: nowrap;
+ position: relative;
+ width: 60%;
+ height: 64px;
+
+ .inputs-search-icon {
+ top: 9px;
+ right: 11px;
+ }
+
+ .magnification-white {
+ .sprite-new;
+ .search-white-icon;
+ .hand;
+ }
+
+ .search-icon-container {
+ width: 35px;
+ height: 30px;
+ background-color: @main_color_a;
+ white-space: nowrap;
+ float: right;
+ position: relative;
+ bottom: 31px;
+ right: 1px;
+ border-radius: 0px 4px 4px 0px;
+ .hand
+ }
+ }
+
+ .total-inputs-count {
+ width: 100%;
+ font-weight: bold;
+ text-align: left;
+ }
+
+ .new-input-button {
+ margin: 9px 0 0 0;
+ }
+
+ .w-sdc-inputs-search-input {
+ border: 1px solid @color_e;
+ .border-radius(4px);
+ height: 32px;
+ margin: 0;
+ padding: 0px 28px 3px 10px;
+ vertical-align: 4px;
+ width: 100%;
+ outline: none;
+ font-style: italic;
+ }
+
+ .w-sdc-classic-btn {
+ float: right;
+ margin-bottom: 10px;
+ }
+
+ .prop-to-input-button {
+ position: absolute;
+ top: 50%;
+ margin-right: -20px;
+ margin-bottom: -10px;
+
+ }
+
+ .table-container-flex {
+
+ .flex-item {
+ line-height: 22px;
+ }
+ .expand-collapse-table-row {
+
+ .data-row {
+ background: @tlv_color_u;
+ .hand;
+ align-items: center;
+ padding: 0 12px;
+ margin: 1px 0px 1px 0px;
+ min-height: 40px;
+ }
+
+ .data-row:hover {
+ .bg_j;
+ }
+ }
+ }
+
+ .table {
+ height: 640px;
+ margin-bottom: 0;
+ clear: both;
+
+ .empty-row {
+ padding: 3px;
+ }
+
+ .flex-item {
+ line-height: 22px;
+ }
+
+ .table-header {
+
+ line-height: 14px;
+ background-color: @main_color_a;
+ color: @main_color_p;
+ text-align: left;
+ padding: 7px 5px 7px 10px;
+ .f-type._14_m;
+ }
+ .head {
+ background-color: #e6e6e6;
+ }
+
+ .body {
+ .scrollbar-container {
+ .perfect-scrollbar;
+ max-height: 610px;
+ }
+
+ .expand-collapse-inputs-table-icon {
+ .hand;
+ .sprite-new;
+ .arrow-up;
+ transition: .3s all;
+ position: relative;
+ left: 8px;
+ border: none !important;
+ padding: 0px 10px 0px 10px;
+ }
+
+ .table-col-text {
+ margin-left: 14px;
+ }
+ }
+ }
+
+ .inputs-header {
+ width: 100%;
+ position: relative;
+ bottom: 31px;
+ }
+
+ .inputs-tables-container {
+ width: 100%;
+ min-width: 100%;
+ display: flex;
+ }
+
+ .inputs-button-container {
+ width: 8%;
+ min-width: 8%;
+ display: flex;
+
+ .right-arrow-btn {
+ .sprite-new;
+ .blue-right-arrow-circle;
+ margin: auto;
+ cursor: pointer;
+ }
+ }
+
+ .table-container-flex {
+ margin-top: 27px;
+ width: 46%;
+ min-width: 46%;
+ display: inline-block;
+ float: left;
+ }
+}
diff --git a/catalog-ui/src/app/view-models/workspace/tabs/inputs/resource-input/resource-inputs-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/inputs/resource-input/resource-inputs-view-model.ts
new file mode 100644
index 0000000000..49fedd6e21
--- /dev/null
+++ b/catalog-ui/src/app/view-models/workspace/tabs/inputs/resource-input/resource-inputs-view-model.ts
@@ -0,0 +1,117 @@
+'use strict';
+import {IWorkspaceViewModelScope} from "app/view-models/workspace/workspace-view-model";
+import {ComponentInstance, InstancesInputsOrPropertiesMapData, Resource, PropertyModel, InputModel} from "app/models";
+import {ModalsHandler} from "app/utils";
+
+export interface IInputsViewModelScope extends IWorkspaceViewModelScope {
+ InstanceInputsProperties:InstancesInputsOrPropertiesMapData; //this is tha map object that hold the selected inputs and the inputs we already used
+ vfInstancesList:Array<ComponentInstance>;
+ component:Resource;
+
+ onArrowPressed():void;
+ getInputPropertiesForInstance(instanceId:string, instance:ComponentInstance):ng.IPromise<boolean> ;
+ loadInputPropertiesForInstance(instanceId:string, input:InputModel):ng.IPromise<boolean> ;
+ openEditValueModal(input:InputModel):void;
+ openEditPropertyModal(property:PropertyModel):void;
+}
+
+export class ResourceInputsViewModel {
+
+ static '$inject' = [
+ '$scope',
+ '$q',
+ 'ModalsHandler'
+ ];
+
+ constructor(private $scope:IInputsViewModelScope, private $q:ng.IQService, private ModalsHandler:ModalsHandler) {
+ this.initScope();
+ this.$scope.updateSelectedMenuItem();
+ }
+
+ private initScope = ():void => {
+
+ this.$scope.InstanceInputsProperties = new InstancesInputsOrPropertiesMapData();
+ this.$scope.vfInstancesList = this.$scope.component.componentInstances;
+
+ // Need to cast all inputs to InputModel for the search to work
+ let tmpInputs:Array<InputModel> = new Array<InputModel>();
+ _.each(this.$scope.component.inputs, (input):void => {
+ tmpInputs.push(new InputModel(input));
+ });
+ this.$scope.component.inputs = tmpInputs;
+ // This function is not supported for resource
+ //this.$scope.component.getComponentInputs();
+
+ /*
+ * When clicking on instance input in the left or right table, this function will load all properties of the selected input
+ */
+ this.$scope.getInputPropertiesForInstance = (instanceId:string, instance:ComponentInstance):ng.IPromise<boolean> => {
+ let deferred = this.$q.defer();
+ instance.properties = this.$scope.component.componentInstancesProperties[instanceId];
+ deferred.resolve(true);
+ return deferred.promise;
+ };
+
+ /*
+ * When clicking on instance input in the left or right table, this function will load all properties of the selected input
+ */
+ this.$scope.loadInputPropertiesForInstance = (instanceId:string, input:InputModel):ng.IPromise<boolean> => {
+ let deferred = this.$q.defer();
+
+ let onSuccess = (properties:Array<PropertyModel>) => {
+ input.properties = properties;
+ deferred.resolve(true);
+ };
+
+ let onError = () => {
+ deferred.resolve(false)
+ };
+
+ if (!input.properties) {
+ this.$scope.component.getComponentInstanceInputProperties(instanceId, input.uniqueId).then(onSuccess, onError);
+ } else {
+ deferred.resolve(true);
+ }
+ return deferred.promise;
+ };
+
+ /*
+ * When pressing the arrow, we create service inputs from the inputs selected
+ */
+ this.$scope.onArrowPressed = ():void => {
+ let onSuccess = (inputsCreated:Array<InputModel>) => {
+
+ //disabled all the inputs in the left table
+ _.forEach(this.$scope.InstanceInputsProperties, (properties:Array<PropertyModel>) => {
+ _.forEach(properties, (property:PropertyModel) => {
+ property.isAlreadySelected = true;
+ });
+ });
+
+ // Adding color to the new inputs (right table)
+ _.forEach(inputsCreated, (input) => {
+ input.isNew = true;
+ });
+
+ // Removing color to the new inputs (right table)
+ setTimeout(() => {
+ _.forEach(inputsCreated, (input) => {
+ input.isNew = false;
+ });
+ this.$scope.$apply();
+ }, 3000);
+ };
+
+ this.$scope.component.createInputsFormInstances(this.$scope.InstanceInputsProperties).then(onSuccess);
+ };
+
+ this.$scope.openEditValueModal = (input:InputModel) => {
+ this.ModalsHandler.openEditInputValueModal(input);
+ };
+
+ this.$scope.openEditPropertyModal = (property:PropertyModel):void => {
+ this.ModalsHandler.openEditPropertyModal(property, this.$scope.component, this.$scope.component.componentInstancesProperties[property.resourceInstanceUniqueId], false).then(() => {
+ });
+ }
+ }
+}
diff --git a/catalog-ui/src/app/view-models/workspace/tabs/inputs/resource-input/resource-inputs-view.html b/catalog-ui/src/app/view-models/workspace/tabs/inputs/resource-input/resource-inputs-view.html
new file mode 100644
index 0000000000..a0715973ab
--- /dev/null
+++ b/catalog-ui/src/app/view-models/workspace/tabs/inputs/resource-input/resource-inputs-view.html
@@ -0,0 +1,86 @@
+<div class="workspace-inputs">
+ <div class="table-container-flex">
+ <div class="w-sdc-inputs-search pull-left hideme">
+ <input type="text" class="w-sdc-inputs-search-input" placeholder="Search"/>
+ <div class="search-icon-container">
+ <span class="w-sdc-search-icon inputs-search-icon magnification-white"></span>
+ </div>
+ </div>
+ <div class="table">
+ <div class="table-header">VFC instances inputs</div>
+ <div class="body">
+ <div class="table-loader" ng-class="{'tlv-loader large loader': isLoading}"></div>
+ <perfect-scrollbar scroll-y-margin-offset="0" class="scrollbar-container">
+
+ <expand-collapse expanded-selector=".vf-instance-list.{{$index}}"
+ class="expand-collapse-table-row"
+ load-data-function="getInputPropertiesForInstance(instance.uniqueId, instance)"
+ is-close-on-init="true"
+ data-ng-repeat-start="instance in vfInstancesList track by $index">
+ <div class="flex-container data-row" data-tests-id="input-instance-{{$index}}">
+ <div class="expand-collapse-inputs-table-icon"></div>
+ <div class="table-col-general flex-item text">
+ <span class="title-text">{{instance.name}}</span>
+ </div>
+ </div>
+
+ </expand-collapse>
+
+ <div data-ng-repeat-end="" class="vf-instance-list {{$index}}">
+ <div class="empty-row" data-tests-id="empty-row" ng-if="instance.properties.length===0">No properties to display </div>
+ <div ng-repeat="property in instance.properties track by $index">
+ <property-row property="property" instance-name="instance.name" on-name-clicked="openEditPropertyModal(property)"></property-row>
+ </div>
+
+ </div>
+
+ </perfect-scrollbar>
+ </div>
+ </div>
+ </div>
+
+ <div class="inputs-button-container pull-left">
+ <!--<div ng-click="onArrowPressed()" class="right-arrow-btn"></div>-->
+ </div>
+
+ <div class="table-container-flex">
+ <div class="w-sdc-inputs-search pull-left">
+ <input type="text" class="w-sdc-inputs-search-input" data-ng-model="search.filterTerm" placeholder="Search"
+ data-ng-model-options="{debounce: 200}"/>
+ <div class="search-icon-container">
+ <span class="w-sdc-search-icon inputs-search-icon magnification-white"></span>
+ </div>
+ </div>
+ <div class="table">
+ <div class="body">
+ <div class="table-header">VF inputs</div>
+ <perfect-scrollbar scroll-y-margin-offset="0" include-padding="true" class="scrollbar-container">
+ <expand-collapse expanded-selector=".resource-inputs.{{$index}}"
+ class="expand-collapse-table-row"
+ load-data-function="loadInputPropertiesForInstance(resourceInput.uniqueId, resourceInput)"
+ is-close-on-init="true"
+ data-ng-repeat-start="resourceInput in component.inputs | filter:search track by $index ">
+ <div class="input-row service-input-row">
+ <input-row input="resourceInput" is-view-only='isViewOnly'
+ instance-name='resourceInput.name'
+ data-tests-id="resource-input-{{$index}}"
+ class="service-input-row"
+ on-name-clicked="openEditValueModal(resourceInput)"
+ ng-class="resourceInput.isNew ? 'new-input': ''">
+
+ </input-row>
+ </div>
+ </expand-collapse>
+
+ <div data-ng-repeat-end="" class="input-inputs-list resource-inputs {{$index}}">
+ <div class="empty-row" ng-if="resourceInput.properties.length===0">No properties to display </div>
+ <div ng-repeat="property in resourceInput.properties track by $index">
+ <property-row property="property" instance-name="property.name"></property-row>
+ </div>
+ </div>
+
+ </perfect-scrollbar>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/catalog-ui/src/app/view-models/workspace/tabs/inputs/resource-input/resource-inputs.less b/catalog-ui/src/app/view-models/workspace/tabs/inputs/resource-input/resource-inputs.less
new file mode 100644
index 0000000000..ebb32fbdb2
--- /dev/null
+++ b/catalog-ui/src/app/view-models/workspace/tabs/inputs/resource-input/resource-inputs.less
@@ -0,0 +1,9 @@
+.workspace-inputs {
+
+ .property-row {
+ .input-check-box {
+ text-align: center;
+ }
+ }
+
+}
diff --git a/catalog-ui/src/app/view-models/workspace/tabs/inputs/service-input/service-inputs-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/inputs/service-input/service-inputs-view-model.ts
new file mode 100644
index 0000000000..f3b2de0943
--- /dev/null
+++ b/catalog-ui/src/app/view-models/workspace/tabs/inputs/service-input/service-inputs-view-model.ts
@@ -0,0 +1,378 @@
+'use strict';
+import {IWorkspaceViewModelScope} from "app/view-models/workspace/workspace-view-model";
+import {ComponentInstance, InstancesInputsOrPropertiesMapData, Service, IAppMenu, InputModel, PropertyModel, InputPropertyBase} from "app/models";
+import {DataTypesService} from "app/services";
+import {ModalsHandler, ResourceType} from "app/utils";
+
+
+interface IServiceInputsViewModelScope extends IWorkspaceViewModelScope {
+
+ vfInstancesList:Array<ComponentInstance>;
+ instanceInputsMap:InstancesInputsOrPropertiesMapData; //this is tha map object that hold the selected inputs and the inputs we already used
+ instancePropertiesMap:InstancesInputsOrPropertiesMapData;
+ component:Service;
+ sdcMenu:IAppMenu;
+ isViewOnly:boolean;
+ isArrowDisabled:boolean;
+ onArrowPressed():void;
+ checkArrowState():void;
+ loadComponentInputs():void;
+ loadInstanceInputs(instance:ComponentInstance):ng.IPromise<boolean> ;
+ loadInstanceProperties(instance:ComponentInstance):ng.IPromise<boolean> ;
+ loadInputPropertiesForInstance(instanceId:string, input:InputModel):ng.IPromise<boolean> ;
+ loadInputInputs(input:InputModel):ng.IPromise<boolean>;
+ deleteInput(input:InputModel):void
+ openEditValueModal(input:InputModel):void;
+ openSelectPropertyDataTypeViewModel(instanceId:string, property:PropertyModel):void;
+ openEditPropertyDataTypeViewModel(property:PropertyModel):void;
+ dataTypesService:DataTypesService;
+}
+
+export class ServiceInputsViewModel {
+
+ static '$inject' = [
+ '$scope',
+ '$q',
+ 'ModalsHandler',
+ 'Sdc.Services.DataTypesService'
+ ];
+
+ constructor(private $scope:IServiceInputsViewModelScope,
+ private $q:ng.IQService,
+ private ModalsHandler:ModalsHandler,
+ private DataTypesService:DataTypesService) {
+ this.initScope();
+ this.$scope.updateSelectedMenuItem();
+ this.$scope.isViewOnly = this.$scope.isViewMode();
+ }
+
+
+ private getInputsOrPropertiesAlreadySelected = (instanceNormalizeName:string, arrayToFilter:Array<InputPropertyBase>):Array<any> => {
+ let alreadySelectedInput = [];
+ _.forEach(arrayToFilter, (inputOrProperty:InputPropertyBase) => {
+ let expectedServiceInputName = instanceNormalizeName + '_' + inputOrProperty.name;
+ let inputAlreadyInService = _.find(this.$scope.component.inputs, (serviceInput:InputModel) => {
+ //Checking if the input prefix is the instance name + '_' + property/input name (prefix because we don't need to check full name for complex dataType)
+ return serviceInput.name.substring(0, expectedServiceInputName.length) === expectedServiceInputName;
+ });
+ if (inputAlreadyInService) {
+ inputOrProperty.isAlreadySelected = true;
+ alreadySelectedInput.push(inputOrProperty);
+ } else {
+ inputOrProperty.isAlreadySelected = false;
+ }
+ });
+ return alreadySelectedInput;
+ };
+
+
+ /*
+ * When loading the screen again, we need to disabled the inputs that already created on the service,
+ * we do that by comparing the service input name, to the instance name + '_' + the resource instance input name.
+ */
+ private disableEnableSelectedInputsOrPropertiesOnInit = (instance:ComponentInstance):void => {
+
+ if (instance.originType === ResourceType.VF) {
+ this.$scope.instanceInputsMap[instance.uniqueId] = this.getInputsOrPropertiesAlreadySelected(instance.normalizedName, instance.inputs);
+ } else {
+ this.$scope.instancePropertiesMap[instance.uniqueId] = this.getInputsOrPropertiesAlreadySelected(instance.normalizedName, instance.properties);
+ }
+ };
+
+ /*
+ * Enable Input/Property after delete
+ */
+ private enableInputsAfterDelete = (propertiesOrInputsDeletes:Array<InputPropertyBase>):void => {
+
+ _.forEach(propertiesOrInputsDeletes, (deletedInputInput:InputPropertyBase) => { //Enable all component instance inputs deleted
+
+ let inputOrPropertyDeleted:InputPropertyBase = _.find(this.$scope.instanceInputsMap[deletedInputInput.componentInstanceId], (inputOrProperty:InputPropertyBase) => {
+ return inputOrProperty.uniqueId === deletedInputInput.uniqueId;
+ });
+ inputOrPropertyDeleted.isAlreadySelected = false;
+ delete _.remove(this.$scope.instanceInputsMap[deletedInputInput.componentInstanceId], {uniqueId: inputOrPropertyDeleted.uniqueId})[0];
+ });
+ };
+
+ /*
+ * Enable Input/Property after delete
+ */
+ private enablePropertiesAfterDelete = (propertiesOrInputsDeletes:Array<InputPropertyBase>):void => {
+
+ _.forEach(propertiesOrInputsDeletes, (deletedInputInput:InputPropertyBase) => { //Enable all component instance inputs deleted
+ let componentInstance = _.find(this.$scope.vfInstancesList, (instance:ComponentInstance) => {
+ return instance.uniqueId === deletedInputInput.componentInstanceId;
+ });
+ let inputOrPropertyDeleted:InputPropertyBase = _.find(this.$scope.instancePropertiesMap[deletedInputInput.componentInstanceId], (inputOrProperty:InputPropertyBase) => {
+ return inputOrProperty.uniqueId === deletedInputInput.uniqueId;
+ });
+
+ let expectedName = componentInstance.normalizedName + '_' + inputOrPropertyDeleted.name;
+ let isAnotherInputExist = _.find(this.$scope.component.inputs, (input:InputModel) => {
+ return input.name.substring(0, expectedName.length) === expectedName;
+ });
+ if (!isAnotherInputExist) {
+ inputOrPropertyDeleted.isAlreadySelected = false;
+ delete _.remove(this.$scope.instancePropertiesMap[deletedInputInput.componentInstanceId], {uniqueId: inputOrPropertyDeleted.uniqueId})[0];
+ }
+ });
+ };
+
+ private initScope = ():void => {
+
+ this.$scope.instanceInputsMap = new InstancesInputsOrPropertiesMapData();
+ this.$scope.instancePropertiesMap = new InstancesInputsOrPropertiesMapData();
+ this.$scope.isLoading = true;
+ this.$scope.isArrowDisabled = true;
+ // Why do we need this? we call this later.
+ //this.$scope.component.getComponentInputs();
+
+ let onSuccess = (componentInstances:Array<ComponentInstance>) => {
+ console.log("component instances loaded: ", componentInstances);
+ this.$scope.vfInstancesList = componentInstances;
+ this.$scope.isLoading = false;
+ };
+
+ //This function will get al component instance for the left table - in
+ // future the instances will be filter according to search text
+ this.$scope.component.getComponentInstancesFilteredByInputsAndProperties().then(onSuccess);
+
+ // This function will get the service inputs for the right table
+ this.$scope.component.getComponentInputs();
+
+ /*
+ * When clicking on instance in the left table, this function will load all instance inputs
+ */
+ this.$scope.loadInstanceInputs = (instance:ComponentInstance):ng.IPromise<boolean> => {
+ let deferred = this.$q.defer();
+
+ let onSuccess = (inputs:Array<InputModel>) => {
+ instance.inputs = inputs;
+ this.disableEnableSelectedInputsOrPropertiesOnInit(instance);
+ deferred.resolve(true);
+ };
+
+ let onError = () => {
+ deferred.resolve(false);
+ };
+
+ if (!instance.inputs) {
+ this.$scope.component.getComponentInstanceInputs(instance.uniqueId, instance.componentUid).then(onSuccess, onError);
+ //this.disableEnableSelectedInputs(instance);
+ } else {
+ deferred.resolve(true);
+ }
+ return deferred.promise;
+ };
+
+
+ this.$scope.loadInstanceProperties = (instance:ComponentInstance):ng.IPromise<boolean> => {
+ let deferred = this.$q.defer();
+
+ let onSuccess = (properties:Array<PropertyModel>) => {
+ instance.properties = properties;
+ this.disableEnableSelectedInputsOrPropertiesOnInit(instance);
+ deferred.resolve(true);
+ };
+
+ let onError = () => {
+ deferred.resolve(false);
+ };
+
+ if (!instance.properties) {
+ this.$scope.component.getComponentInstanceProperties(instance.uniqueId).then(onSuccess, onError);
+ } else {
+ deferred.resolve(true);
+ }
+ return deferred.promise;
+ };
+
+ /*
+ * When clicking on instance input in the left or right table, this function will load all properties of the selected input
+ */
+ this.$scope.loadInputPropertiesForInstance = (instanceId:string, input:InputModel):ng.IPromise<boolean> => {
+ let deferred = this.$q.defer();
+
+ let onSuccess = (properties:Array<PropertyModel>) => {
+ input.properties = properties;
+ deferred.resolve(true);
+ };
+
+ let onError = () => {
+ deferred.resolve(false)
+ };
+
+ if (!input.properties) {
+ this.$scope.component.getComponentInstanceInputProperties(instanceId, input.uniqueId).then(onSuccess, onError);
+ } else {
+ deferred.resolve(true);
+ }
+ return deferred.promise;
+ };
+
+ /*
+ * When clicking on input in the right table, this function will load all inputs of the selected input
+ */
+ this.$scope.loadInputInputs = (input:InputModel):ng.IPromise<boolean> => {
+ let deferred = this.$q.defer();
+
+ let onSuccess = () => {
+ deferred.resolve(true);
+ };
+ let onError = () => {
+ deferred.resolve(false);
+ };
+
+ if (!input.inputs) { // Caching, if exists do not get it.
+ this.$scope.component.getServiceInputInputsAndProperties(input.uniqueId).then(onSuccess, onError);
+ } else {
+ deferred.resolve(true);
+ }
+ return deferred.promise;
+ };
+
+ /*
+ * When pressing the arrow, we create service inputs from the inputs selected
+ */
+ this.$scope.onArrowPressed = ():void => {
+ let onSuccess = (inputsCreated:Array<InputModel>) => {
+
+ //disabled all the inputs in the left table
+ _.forEach(this.$scope.instanceInputsMap, (inputs:Array<InputModel>, instanceId:string) => {
+ _.forEach(inputs, (input:InputModel) => {
+ input.isAlreadySelected = true;
+ });
+ });
+ _.forEach(this.$scope.instancePropertiesMap, (properties:Array<PropertyModel>, instanceId:string) => {
+ _.forEach(properties, (property:PropertyModel) => {
+ property.isAlreadySelected = true;
+ });
+ });
+ this.addColorToItems(inputsCreated);
+ };
+
+ let onFailed = (error:any) => {
+ this.$scope.isArrowDisabled = false;
+ console.log("Error declaring input/property");
+ };
+
+ this.$scope.isArrowDisabled = true;
+ this.$scope.component.createInputsFormInstances(this.$scope.instanceInputsMap, this.$scope.instancePropertiesMap).then(onSuccess, onFailed);
+ };
+
+
+ /* Iterates through array of selected inputs and properties and returns true if there is at least one new selection on left */
+ this.$scope.checkArrowState = ()=> {
+
+ let newInputSelected:boolean = _.some(this.$scope.instanceInputsMap, (inputs:Array<InputModel>) => {
+ return _.some(inputs, (input:InputModel)=> {
+ return input.isAlreadySelected === false;
+ });
+ });
+
+ let newPropSelected:boolean = _.some(this.$scope.instancePropertiesMap, (properties:Array<PropertyModel>) => {
+ return _.some(properties, (property:PropertyModel) => {
+ return property.isAlreadySelected === false;
+ });
+ });
+
+ this.$scope.isArrowDisabled = !(newInputSelected || newPropSelected);
+
+ };
+
+ this.$scope.deleteInput = (inputToDelete:InputModel):void => {
+
+ let onDelete = ():void => {
+
+ let onSuccess = (deletedInput:InputModel):void => {
+ if (deletedInput.inputs && deletedInput.inputs.length > 0) { // Enable input declared from input
+ this.enableInputsAfterDelete(deletedInput.inputs);
+ }
+
+ if (deletedInput.properties && deletedInput.properties.length > 0) { // Enable properties
+ this.enablePropertiesAfterDelete(deletedInput.properties);
+ }
+ deletedInput.isDeleteDisabled = false;
+ this.$scope.checkArrowState();
+
+ };
+
+ let onFailed = (error:any):void => {
+ console.log("Error deleting input");
+ inputToDelete.isDeleteDisabled = false;
+ };
+
+ inputToDelete.isDeleteDisabled = true;
+ this.addColorToItems([inputToDelete]);
+ this.$scope.component.deleteServiceInput(inputToDelete.uniqueId).then((deletedInput:InputModel):void => {
+ onSuccess(deletedInput);
+ }, onFailed);
+ };
+
+ // Get confirmation modal text from menu.json
+ let state = "deleteInput";
+ let title:string = this.$scope.sdcMenu.alertMessages[state].title;
+ let message:string = this.$scope.sdcMenu.alertMessages[state].message.format([inputToDelete.name]);
+
+ // Open confirmation modal
+ this.ModalsHandler.openAlertModal(title, message).then(onDelete);
+ };
+
+ this.$scope.openEditValueModal = (input:InputModel) => {
+ this.ModalsHandler.openEditInputValueModal(input);
+ };
+
+ this.$scope.openSelectPropertyDataTypeViewModel = (instanceId:string, property:PropertyModel) => {
+ //to open the select data type modal
+ let selectedInstance = _.find(this.$scope.vfInstancesList, {uniqueId: instanceId});
+ this.DataTypesService.selectedInstance = selectedInstance; //set the selected instance on the service for compering the input name on the service & the complex property
+ this.DataTypesService.selectedComponentInputs = this.$scope.component.inputs; // set all the service inputs on the data type service
+ let filteredPropertiesMap = _.filter(this.$scope.instancePropertiesMap[instanceId], (instanceProperty)=> {
+ return instanceProperty.name == property.name;
+ });//get all properties under the specific property
+ this.DataTypesService.selectedPropertiesName = property.propertiesName;
+
+ this.ModalsHandler.openSelectDataTypeModal(property, this.$scope.component, this.$scope.component.properties, filteredPropertiesMap).then((selectedProperty:PropertyModel)=> {
+ if (selectedProperty && selectedProperty.propertiesName) {
+ let propertyToUpdate:PropertyModel = _.find(selectedInstance.properties, {uniqueId: selectedProperty.uniqueId});
+ let existingProperty:PropertyModel = (<PropertyModel>_.find(this.$scope.instancePropertiesMap[instanceId], {uniqueId: propertyToUpdate.uniqueId}));
+
+ if (existingProperty) {
+ existingProperty.propertiesName = selectedProperty.propertiesName;
+ existingProperty.input = selectedProperty.input;
+ existingProperty.isAlreadySelected = false;
+ } else {
+ propertyToUpdate.propertiesName = selectedProperty.propertiesName;
+ propertyToUpdate.input = selectedProperty.input;
+ this.$scope.instancePropertiesMap[instanceId].push(propertyToUpdate);
+
+ }
+ this.$scope.checkArrowState();
+
+ }
+ });
+ };
+
+
+ this.$scope.openEditPropertyDataTypeViewModel = (property:PropertyModel)=> {
+ this.ModalsHandler.openEditPropertyModal(property, this.$scope.component, this.$scope.component.properties, false).then(() => {
+ });
+ }
+ };
+
+ private addColorToItems = (inputsCreated:Array<InputModel>):void => {
+
+ // Adding color to the new inputs (right table)
+ _.forEach(inputsCreated, (input) => {
+ input.isNew = true;
+ });
+
+ // Removing color to the new inputs (right table)
+ setTimeout(() => {
+ _.forEach(inputsCreated, (input) => {
+ input.isNew = false;
+ });
+ this.$scope.$apply();
+ }, 3000);
+ };
+}
diff --git a/catalog-ui/src/app/view-models/workspace/tabs/inputs/service-input/service-inputs-view.html b/catalog-ui/src/app/view-models/workspace/tabs/inputs/service-input/service-inputs-view.html
new file mode 100644
index 0000000000..cb4d853f58
--- /dev/null
+++ b/catalog-ui/src/app/view-models/workspace/tabs/inputs/service-input/service-inputs-view.html
@@ -0,0 +1,134 @@
+<div class="workspace-inputs">
+ <div class="table-container-flex">
+ <div class="w-sdc-inputs-search pull-left hideme">
+ <input type="text" class="w-sdc-inputs-search-input" placeholder="Search"/>
+ <div class="search-icon-container">
+ <span class="w-sdc-search-icon inputs-search-icon magnification-white"></span>
+ </div>
+ </div>
+ <div class="table">
+ <div class="table-header">Resource instance inputs</div>
+ <div class="body">
+ <div class="table-loader" ng-class="{'tlv-loader large loader': isLoading}"></div>
+ <perfect-scrollbar scroll-y-margin-offset="0" class="scrollbar-container">
+
+ <expand-collapse expanded-selector=".vf-instance-list.{{$index}}"
+ class="expand-collapse-table-row"
+ load-data-function="instance.originType=='VF' ? loadInstanceInputs(instance):loadInstanceProperties(instance)"
+ is-close-on-init="true"
+ data-ng-repeat-start="instance in vfInstancesList track by $index">
+ <div class="flex-container data-row">
+ <div class="expand-collapse-inputs-table-icon"></div>
+ <div class="table-col-general flex-item text" data-tests-id="inputs-vf-instance-{{$index}}">
+ <span class="title-text">{{instance.name}}</span>
+ </div>
+ </div>
+ </expand-collapse>
+
+ <div data-ng-repeat-end="" class="vf-instance-list {{$index}}">
+ <div data-ng-if="instance.originType=='VF'">
+
+ <expand-collapse expanded-selector=".input-list.{{$parent.$index}}-{{$index}}"
+ class="expand-collapse-table-row"
+ load-data-function="loadInputPropertiesForInstance(instance.uniqueId, input)"
+ is-close-on-init="true"
+ data-ng-repeat-start="input in instance.inputs track by $index">
+ <input-row input="input"
+ is-view-only='isViewOnly'
+ instance-id='instance.uniqueId'
+ instance-name='instance.name'
+ instance-inputs-map="instanceInputsMap"
+ on-checkbox-clicked="checkArrowState()"></input-row>
+ </expand-collapse>
+
+ <div data-ng-repeat-end="" class="input-list {{$parent.$index}}-{{$index}}">
+ <div class="empty-row" ng-if="input.properties.length===0">No properties to display
+ </div>
+ <div ng-repeat="property in input.properties track by $index">
+ <property-row property="property" instance-name="instance.name"></property-row>
+ </div>
+ </div>
+ </div>
+ <div data-ng-if="instance.originType!='VF'">
+ <div class="empty-row" data-tests-id="empty-row" ng-if="instance.properties.length===0"> No
+ properties to display
+ </div>
+ <div ng-repeat="property in instance.properties track by $index">
+ <property-row instance-properties-map="instancePropertiesMap" property="property"
+ on-name-clicked="openSelectPropertyDataTypeViewModel(instance.uniqueId,property)"
+ on-checkbox-clicked="checkArrowState()"
+ instance-name="instance.name"
+ instance-id='instance.uniqueId'></property-row>
+ </div>
+ </div>
+ </div>
+
+ </perfect-scrollbar>
+ </div>
+ </div>
+ </div>
+
+ <div class="inputs-button-container pull-left">
+ <div ng-click="onArrowPressed()" ng-class="{disabled: isArrowDisabled || isViewOnly}" data-ng-disabled="isArrowDisabled || isViewOnly" class="right-arrow-btn" data-tests-id="add-inputs-to-service-button"></div>
+ </div>
+
+ <div class="table-container-flex">
+ <div class="w-sdc-inputs-search pull-left">
+ <input type="text" class="w-sdc-inputs-search-input" data-ng-model="search.filterTerm" placeholder="Search"
+ data-ng-model-options="{debounce: 200}"/>
+ <div class="search-icon-container">
+ <span class="w-sdc-search-icon inputs-search-icon magnification-white"></span>
+ </div>
+ </div>
+ <div class="table">
+ <div class="body">
+ <div class="table-header">Service inputs</div>
+ <perfect-scrollbar scroll-y-margin-offset="0" include-padding="true" class="scrollbar-container">
+ <expand-collapse expanded-selector=".service-inputs.{{$index}}"
+ class="expand-collapse-table-row"
+ load-data-function="loadInputInputs(serviceInput)"
+ is-close-on-init="true"
+ data-ng-repeat-start="serviceInput in component.inputs | filter:search track by $index ">
+ <input-row input="serviceInput" is-view-only='isViewOnly' instance-name='serviceInput.name'
+ delete-input='deleteInput(serviceInput)'
+ data-tests-id="service-input-{{$index}}"
+ class="service-input-row"
+ on-name-clicked="openEditValueModal(serviceInput)"
+ ng-class="serviceInput.isNew ? 'new-input': ''"
+ ></input-row>
+ </expand-collapse>
+
+ <div data-ng-repeat-end="" class="service-inputs {{$index}}">
+ <div ng-if="serviceInput.inputs.length > 0">
+ <expand-collapse expanded-selector=".input-inputs-list.{{$parent.$index}}-{{$index}}"
+ class="expand-collapse-table-row"
+ load-data-function="loadInputPropertiesForInstance(input.componentInstanceId, input)"
+ is-close-on-init="true"
+ data-ng-repeat-start="input in serviceInput.inputs track by $index">
+ <input-row input="input"
+ is-view-only='isViewOnly'
+ instance-name='input.componentInstanceName'></input-row>
+ </expand-collapse>
+
+ <div data-ng-repeat-end="" class="input-inputs-list {{$parent.$index}}-{{$index}}">
+ <div class="empty-row" ng-if="input.properties.length===0">No properties to display
+ </div>
+ <div ng-repeat="property in input.properties track by $index">
+ <property-row property="property" instance-name="property.name" is-clickable="false"></property-row>
+ </div>
+ </div>
+ </div>
+ <div ng-if="serviceInput.properties.length > 0">
+ <div class="empty-row" ng-if="serviceInput.properties.length===0">No properties to display</div>
+ <div ng-repeat="property in serviceInput.properties track by $index">
+ <property-row property="property" instance-name="property.name" is-clickable="false"></property-row>
+ </div>
+ </div>
+ </div>
+
+
+ </perfect-scrollbar>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/catalog-ui/src/app/view-models/workspace/tabs/inputs/service-input/service-inputs.less b/catalog-ui/src/app/view-models/workspace/tabs/inputs/service-input/service-inputs.less
new file mode 100644
index 0000000000..f783d0b6d6
--- /dev/null
+++ b/catalog-ui/src/app/view-models/workspace/tabs/inputs/service-input/service-inputs.less
@@ -0,0 +1,47 @@
+.workspace-inputs {
+
+ .service-inputs-view {
+
+ .table-container-flex {
+ width:100% !important;
+ }
+
+ .table-loader {
+ position: relative;
+ top:215px;
+ }
+
+ }
+
+ .infinite-scroll {
+
+ overflow-y: scroll;
+ overflow-x: hidden;
+ max-height: 400px;
+ }
+
+ .class_with_css_props_leading_to_a_scroll {
+ height: 100%;
+ overflow-y: auto;
+ }
+
+ .table-container-flex {
+ .expand-collapse-table-row {
+ .service-input-row {
+ padding-left: 15px;
+ border: none;
+ border-bottom: rgba(120, 136, 148, 0.26) solid 1px;
+
+ &.service-input-row {
+ background: @tlv_color_u;
+ &.new-input {
+ background: @tlv_color_v;
+ }
+ }
+ }
+
+
+ }
+ }
+
+}