From 451a3400b76511393c62a444f588a4ed15f4a549 Mon Sep 17 00:00:00 2001 From: Michael Lando Date: Sun, 19 Feb 2017 10:28:42 +0200 Subject: Initial OpenECOMP SDC commit Change-Id: I0924d5a6ae9cdc161ae17c68d3689a30d10f407b Signed-off-by: Michael Lando --- .../view-models/workspace/tabs/inputs/inputs.less | 286 +++++++++++++++++++++ .../resource-input/resource-inputs-view-model.ts | 145 +++++++++++ .../resource-input/resource-inputs-view.html | 136 ++++++++++ .../inputs/resource-input/resource-inputs.less | 9 + .../service-input/service-inputs-view-model.ts | 246 ++++++++++++++++++ .../inputs/service-input/service-inputs-view.html | 205 +++++++++++++++ .../tabs/inputs/service-input/service-inputs.less | 54 ++++ 7 files changed, 1081 insertions(+) create mode 100644 catalog-ui/app/scripts/view-models/workspace/tabs/inputs/inputs.less create mode 100644 catalog-ui/app/scripts/view-models/workspace/tabs/inputs/resource-input/resource-inputs-view-model.ts create mode 100644 catalog-ui/app/scripts/view-models/workspace/tabs/inputs/resource-input/resource-inputs-view.html create mode 100644 catalog-ui/app/scripts/view-models/workspace/tabs/inputs/resource-input/resource-inputs.less create mode 100644 catalog-ui/app/scripts/view-models/workspace/tabs/inputs/service-input/service-inputs-view-model.ts create mode 100644 catalog-ui/app/scripts/view-models/workspace/tabs/inputs/service-input/service-inputs-view.html create mode 100644 catalog-ui/app/scripts/view-models/workspace/tabs/inputs/service-input/service-inputs.less (limited to 'catalog-ui/app/scripts/view-models/workspace/tabs/inputs') diff --git a/catalog-ui/app/scripts/view-models/workspace/tabs/inputs/inputs.less b/catalog-ui/app/scripts/view-models/workspace/tabs/inputs/inputs.less new file mode 100644 index 0000000000..76a82c69ee --- /dev/null +++ b/catalog-ui/app/scripts/view-models/workspace/tabs/inputs/inputs.less @@ -0,0 +1,286 @@ +.workspace-inputs { + + .sdc-workspace-container .w-sdc-main-right-container .w-sdc-main-container-body-content { + padding: 25px 8% 0px 8%; + } + + width: 100%; + display: flex; + + .text { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + padding-left: 15px; + } + + .title-text { + color: @main_color_m; + .f-type._13_m; + .bold; + } + + .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; + } + } + + .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; + + } + + .property-row { + border-bottom: 1px solid @border_color_d; + padding-left: 10px; + .property-name-container { + display: flex; + flex-grow: 4; + } + + .type-schema-container { + flex-grow: 1; + border-left: 1px solid @border_color_d; + text-align: left; + line-height: 30px; + text-transform: capitalize; + width: 10px; + } + + } + + .table-container-flex { + + .flex-item { + line-height: 22px; + } + .expand-collapse-table-row { + + &.expanded { + .flex-container { + .expand-collapse-inputs-table-icon { + transform: rotate(180deg); + left: 0px; + } + } + } + + .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; + } + + .input-row { + padding-left: 45px; + background: @tlv_color_t; + border: @main_color_o solid 1px; + align-items: center; + .hand; + margin: 1px 0px 1px 0px; + + &.service-input-row { + background: @tlv_color_u; + &.new-input { + background: @tlv_color_v; + } + } + &.selected { + background-color: @tlv_color_v; + } + .flex-item { + min-height: 60px; + padding: 0 15px; + } + .input-check-box { + padding-right: 10px; + margin-top: 9px; + } + &>.title-text{ + text-align: start; + padding: 4px 0 0 35px; + } + + .expand-collapse-inputs-table-icon{ + margin-top: 15px; + } + + } + + .input-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; + } + + .property-row:hover{ + background-color: @func_color_r; + } + + .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/app/scripts/view-models/workspace/tabs/inputs/resource-input/resource-inputs-view-model.ts b/catalog-ui/app/scripts/view-models/workspace/tabs/inputs/resource-input/resource-inputs-view-model.ts new file mode 100644 index 0000000000..2dc1b1d9ff --- /dev/null +++ b/catalog-ui/app/scripts/view-models/workspace/tabs/inputs/resource-input/resource-inputs-view-model.ts @@ -0,0 +1,145 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +/// +module Sdc.ViewModels { + 'use strict'; + import Dictionary = Sdc.Utils.Dictionary; + import InputModel = Sdc.Models.InputModel; + + export interface IInputsViewModelScope extends IWorkspaceViewModelScope { + InstanceInputsProperties:Models.InstanceInputsPropertiesMapData; //this is tha map object that hold the selected inputs and the inputs we already used + vfInstancesList: Array; + component:Models.Components.Resource; + + onArrowPressed():void; + getInputPropertiesForInstance(instanceId:string, instance:Models.ComponentsInstances.ComponentInstance): ng.IPromise ; + loadInputPropertiesForInstance(instanceId:string, input:Models.InputModel): ng.IPromise ; + loadInputInputs(input:Models.InputModel): ng.IPromise; + } + + export class ResourceInputsViewModel { + + static '$inject' = [ + '$scope', + '$q' + ]; + + constructor(private $scope:IInputsViewModelScope, private $q: ng.IQService) { + this.initScope(); + } + + private initScope = (): void => { + + this.$scope.InstanceInputsProperties = new Models.InstanceInputsPropertiesMapData(); + this.$scope.vfInstancesList = this.$scope.component.componentInstances; + + // Need to cast all inputs to InputModel for the search to work + let tmpInputs:Array = new Array(); + _.each(this.$scope.component.inputs, (input):void => { + tmpInputs.push(new Models.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:Models.ComponentsInstances.ComponentInstance): ng.IPromise => { + let deferred = this.$q.defer(); + instance.properties = this.$scope.component.componentInstancesProperties[instanceId]; + 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:Models.InputModel): ng.IPromise => { + let deferred = this.$q.defer(); + + let onSuccess = () => { deferred.resolve(true); }; + let onError = () => { deferred.resolve(false); }; + + if(!input.inputs) { + this.$scope.component.getResourceInputInputs(input.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:Models.InputModel): ng.IPromise => { + let deferred = this.$q.defer(); + + let onSuccess = (properties:Array) => { + 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) => { + + //disabled all the inputs in the left table + _.forEach(this.$scope.InstanceInputsProperties, (properties:Array) => { + _.forEach(properties, (property:Models.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); + }; + + } + + } +} diff --git a/catalog-ui/app/scripts/view-models/workspace/tabs/inputs/resource-input/resource-inputs-view.html b/catalog-ui/app/scripts/view-models/workspace/tabs/inputs/resource-input/resource-inputs-view.html new file mode 100644 index 0000000000..7cdf5a2fa4 --- /dev/null +++ b/catalog-ui/app/scripts/view-models/workspace/tabs/inputs/resource-input/resource-inputs-view.html @@ -0,0 +1,136 @@ +
+
+ +
+
VFC instances inputs
+
+
+ + + +
+
+
+ {{instance.name}} +
+
+ +
+ +
+ +
No properties to display
+ +
+
+
+ {{property.name}} + {{property.name}} +
+
+
+ {{property.type}} +
+
+
+
+ {{property.schema.property.type}} +
+
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+ +
+
+
Resource instance inputs
+ + +
+
{{resourceInput.name}}
+
+
+
+
+ Description: + {{resourceInput.description}} +
+
+
+
+ VF Instance: + {{resourceInput.name}} +
+
+ Type: + {{resourceInput.type}} +
+
+
+
+
+ +
+
No properties to display
+
+
+
+ {{property.name}} + {{property.name}} +
+
+
+ {{property.type}} +
+
+
+
+ {{property.schema.property.type}} +
+
+
+
+
+ +
+
+
+
+
diff --git a/catalog-ui/app/scripts/view-models/workspace/tabs/inputs/resource-input/resource-inputs.less b/catalog-ui/app/scripts/view-models/workspace/tabs/inputs/resource-input/resource-inputs.less new file mode 100644 index 0000000000..ebb32fbdb2 --- /dev/null +++ b/catalog-ui/app/scripts/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/app/scripts/view-models/workspace/tabs/inputs/service-input/service-inputs-view-model.ts b/catalog-ui/app/scripts/view-models/workspace/tabs/inputs/service-input/service-inputs-view-model.ts new file mode 100644 index 0000000000..6c8391720a --- /dev/null +++ b/catalog-ui/app/scripts/view-models/workspace/tabs/inputs/service-input/service-inputs-view-model.ts @@ -0,0 +1,246 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +/// +module Sdc.ViewModels { + 'use strict'; + import IAngularEvent = angular.IAngularEvent; + import ComponentInstance = Sdc.Models.ComponentsInstances.ComponentInstance; + + + interface IServiceInputsViewModelScope extends IWorkspaceViewModelScope { + + vfInstancesList: Array; + selectedInputs:Array; + instanceInputsMap:Models.InstancesInputsMapData; //this is tha map object that hold the selected inputs and the inputs we already used + component:Models.Components.Service; + sdcMenu:Models.IAppMenu; + + onArrowPressed():void; + loadComponentInputs(): void; + loadInstanceInputs(instance:ComponentInstance): ng.IPromise ; + loadInputPropertiesForInstance(instanceId:string, input:Models.InputModel): ng.IPromise ; + loadInputInputs(input:Models.InputModel): ng.IPromise; + deleteInput(input:Models.InputModel):void + } + + export class ServiceInputsViewModel { + + static '$inject' = [ + '$scope', + '$q', + 'ModalsHandler' + ]; + + constructor(private $scope:IServiceInputsViewModelScope, + private $q: ng.IQService, + private ModalsHandler: Sdc.Utils.ModalsHandler) { + this.initScope(); + } + + /* + * 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 disableEnableSelectedInputs = (instance: ComponentInstance): void => { + + let alreadySelectedInput = new Array(); + _.forEach(instance.inputs, (input:Models.InputModel) => { + let expectedServiceInputName = instance.normalizedName + '_' + input.name; + let inputAlreadyInService: Models.InputModel = _.find(this.$scope.component.inputs, (serviceInput: Models.InputModel) => { + return serviceInput.name === expectedServiceInputName; + }); + if(inputAlreadyInService) { + input.isAlreadySelected = true; + alreadySelectedInput.push(input); + } else { + input.isAlreadySelected = false; + } + }); + this.$scope.instanceInputsMap[instance.uniqueId] = alreadySelectedInput; + }; + + private initScope = (): void => { + + this.$scope.instanceInputsMap = new Models.InstancesInputsMapData(); + this.$scope.isLoading = true; + this.$scope.selectedInputs = new Array(); + + // Why do we need this? we call this later. + //this.$scope.component.getComponentInputs(); + + let onSuccess = (componentInstances:Array) => { + 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 => { + let deferred = this.$q.defer(); + + let onSuccess = (inputs:Array) => { + instance.inputs = inputs; + this.disableEnableSelectedInputs(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; + }; + + /* + * 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:Models.InputModel): ng.IPromise => { + let deferred = this.$q.defer(); + + let onSuccess = (properties:Array) => { + 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:Models.InputModel): ng.IPromise => { + 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.getServiceInputInputs(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) => { + + //disabled all the inputs in the left table + _.forEach(this.$scope.instanceInputsMap, (inputs:Array, instanceId:string) => { + _.forEach(inputs, (input:Models.InputModel) => { + input.isAlreadySelected = true; + }); + }); + + this.addColorToItems(inputsCreated); + }; + + this.$scope.component.createInputsFormInstances(this.$scope.instanceInputsMap).then(onSuccess); + }; + + this.$scope.deleteInput = (input: Models.InputModel):void => { + + var onDelete = ():void => { + var onSuccess = (deletedInput: Models.InputModel, componentInstanceId:string):void => { + // Remove from component.inputs the deleted input (service inputs) + var remainingServiceInputs:Array = _.filter(this.$scope.component.inputs, (input:Models.InputModel):boolean => { + return input.uniqueId !== deletedInput.uniqueId; + }); + this.$scope.component.inputs = remainingServiceInputs; + + // Find the instance that contains the deleted input, and set disable|enable the deleted input + var deletedInputComponentInstance:ComponentInstance = _.find(this.$scope.vfInstancesList, (instanceWithChildToDelete:ComponentInstance):boolean => { + return instanceWithChildToDelete.uniqueId === componentInstanceId; + }); + this.disableEnableSelectedInputs(deletedInputComponentInstance); + }; + + var onFailed = (error:any) : void => { + console.log("Error deleting input"); + }; + + this.addColorToItems([input]); + + // Get service inputs of input (so after delete we will know the component instance) + this.$scope.loadInputInputs(input).then((result:boolean):void=>{ + if (result && input.inputs.length>0) { + var componentInstanceId:string = input.inputs[0].componentInstanceId; + this.$scope.component.deleteServiceInput(input.uniqueId).then((deletedInput: Models.InputModel):void => { + onSuccess(deletedInput, componentInstanceId); + }, onFailed); + } + }); + }; + + // Get confirmation modal text from menu.json + var state = "deleteInput"; + var title:string = this.$scope.sdcMenu.alertMessages[state].title; + var message:string = this.$scope.sdcMenu.alertMessages[state].message.format([input.name]); + + // Open confirmation modal + this.ModalsHandler.openAlertModal(title, message).then(onDelete); + } + }; + + private addColorToItems = (inputsCreated:Array):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/app/scripts/view-models/workspace/tabs/inputs/service-input/service-inputs-view.html b/catalog-ui/app/scripts/view-models/workspace/tabs/inputs/service-input/service-inputs-view.html new file mode 100644 index 0000000000..bf15a70322 --- /dev/null +++ b/catalog-ui/app/scripts/view-models/workspace/tabs/inputs/service-input/service-inputs-view.html @@ -0,0 +1,205 @@ +
+
+ +
+
Resource instance inputs
+
+
+ + + +
+
+
+ {{instance.name}} +
+
+ +
+ +
+ + +
+
{{input.name}}
+
+
+
+ +
+ Description: + {{input.description}} +
+
+
+
+ VF Instance: + {{instance.name}} +
+
+ Type: + {{input.type}} +
+
+ +
+
+ + +
+ +
+
No properties to display
+ +
+
+
+ {{property.name}} + {{property.name}} +
+
+
+ {{property.type}} +
+
+
+
+ {{property.schema.property.type}} +
+
+
+
+
+
+
+
+
+
+ +
+
+
+ +
+ +
+
+
Service Inputs
+ + +
+
{{serviceInput.name}}
+
+
+
+
+ Description: + {{serviceInput.description}} +
+
+
+
+ VF Instance: + {{serviceInput.name}} +
+
+ Type: + {{serviceInput.type}} +
+
+
+ +
+
+
+
+ +
+ +
+
{{input.name}}
+
+
+
+
+ Description: + {{input.description}} +
+
+
+
+ VF Instance: + {{instance.componentInstanceName}} +
+
+ Type: + {{input.type}} +
+
+
+
+
+ +
+
No properties to display
+
+
+
+ {{property.name}} + {{property.name}} +
+
+
+ {{property.type}} +
+
+
+
+ {{property.schema.property.type}} +
+
+
+
+
+
+
+
+
+
+
diff --git a/catalog-ui/app/scripts/view-models/workspace/tabs/inputs/service-input/service-inputs.less b/catalog-ui/app/scripts/view-models/workspace/tabs/inputs/service-input/service-inputs.less new file mode 100644 index 0000000000..11e613b56e --- /dev/null +++ b/catalog-ui/app/scripts/view-models/workspace/tabs/inputs/service-input/service-inputs.less @@ -0,0 +1,54 @@ +.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; + + .delete { + width: 50px; + padding: 0; + position: relative; + } + + .remove-input-icon { + position: absolute; + top: 12px; + right: 18px; + } + + .remove-input-icon:hover { + .delete-icon-hover; + } + } + } + } + +} -- cgit 1.2.3-korg