diff options
Diffstat (limited to 'catalog-ui/src/app/view-models/workspace/tabs/req-and-capabilities')
3 files changed, 486 insertions, 0 deletions
diff --git a/catalog-ui/src/app/view-models/workspace/tabs/req-and-capabilities/req-and-capabilities-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/req-and-capabilities/req-and-capabilities-view-model.ts new file mode 100644 index 0000000000..4ac99edf8a --- /dev/null +++ b/catalog-ui/src/app/view-models/workspace/tabs/req-and-capabilities/req-and-capabilities-view-model.ts @@ -0,0 +1,147 @@ +/** + * Created by rcohen on 9/22/2016. + */ +'use strict'; +import {IWorkspaceViewModelScope} from "app/view-models/workspace/workspace-view-model"; +import {ModalsHandler} from "app/utils"; +import {Capability, PropertyModel, Requirement} from "app/models"; +import {ComponentGenericResponse} from "../../../../ng2/services/responses/component-generic-response"; +import {ComponentServiceNg2} from "../../../../ng2/services/component-services/component.service"; + +export class SortTableDefined { + reverse:boolean; + sortByField:string; +} + +interface IReqAndCapabilitiesViewModelScope extends IWorkspaceViewModelScope { + requirementsTableHeadersList:Array<any>; + capabilitiesTableHeadersList:Array<any>; + capabilityPropertiesTableHeadersList:Array<any>; + requirementsSortTableDefined:SortTableDefined; + capabilitiesSortTableDefined:SortTableDefined; + propertiesSortTableDefined:SortTableDefined; + requirements:Array<Requirement>; + capabilities:Array<Capability>; + mode:string; + filteredProperties:Array<Array<PropertyModel>>; + searchText:string; + + sort(sortBy:string, sortByTableDefined:SortTableDefined):void; + updateProperty(property:PropertyModel, indexInFilteredProperties:number):void; + allCapabilitiesSelected(selected:boolean):void; +} + +export class ReqAndCapabilitiesViewModel { + + static '$inject' = [ + '$scope', + '$filter', + 'ModalsHandler', + 'ComponentServiceNg2' + ]; + + + constructor(private $scope:IReqAndCapabilitiesViewModelScope, + private $filter:ng.IFilterService, + private ModalsHandler:ModalsHandler, + private ComponentServiceNg2: ComponentServiceNg2) { + + this.initCapabilitiesAndRequirements(); + this.$scope.updateSelectedMenuItem(); + } + + private initCapabilitiesAndRequirements = (): void => { + + if(!this.$scope.component.capabilities || !this.$scope.component.requirements) { + this.$scope.isLoading = true; + this.ComponentServiceNg2.getCapabilitiesAndRequirements(this.$scope.component.componentType, this.$scope.component.uniqueId).subscribe((response:ComponentGenericResponse) => { + this.$scope.component.capabilities = response.capabilities; + this.$scope.component.requirements = response.requirements; + this.initScope(); + this.$scope.isLoading = false; + }, () => { + this.$scope.isLoading = false; + }); + } else { + this.initScope(); + } + + } + + private openEditPropertyModal = (property:PropertyModel, indexInFilteredProperties:number):void => { + //...because there is not be api + _.forEach(this.$scope.filteredProperties[indexInFilteredProperties], (prop:PropertyModel)=> { + prop.readonly = true; + }); + this.ModalsHandler.openEditPropertyModal(property, this.$scope.component, this.$scope.filteredProperties[indexInFilteredProperties], false).then(() => { + + }); + }; + + private initScope = ():void => { + + this.$scope.requirementsSortTableDefined = { + reverse: false, + sortByField: 'name' + }; + this.$scope.capabilitiesSortTableDefined = { + reverse: false, + sortByField: 'name' + }; + this.$scope.propertiesSortTableDefined = { + reverse: false, + sortByField: 'name' + }; + + this.$scope.setValidState(true); + this.$scope.requirementsTableHeadersList = [ + {title: 'Name', property: 'name'}, + {title: 'Capability', property: 'capability'}, + {title: 'Node', property: 'node'}, + {title: 'Relationship', property: 'relationship'}, + {title: 'Connected To', property: ''}, + {title: 'Occurrences', property: ''} + ]; + this.$scope.capabilitiesTableHeadersList = [ + {title: 'Name', property: 'name'}, + {title: 'Type', property: 'type'}, + {title: 'Description', property: ''}, + {title: 'Valid Source', property: ''}, + {title: 'Occurrences', property: ''} + ]; + this.$scope.capabilityPropertiesTableHeadersList = [ + {title: 'Name', property: 'name'}, + {title: 'Type', property: 'type'}, + {title: 'Schema', property: 'schema.property.type'}, + {title: 'Description', property: 'description'}, + ]; + this.$scope.filteredProperties = []; + + this.$scope.mode = 'requirements'; + this.$scope.requirements = []; + _.forEach(this.$scope.component.requirements, (req:Array<Requirement>, capName)=> { + this.$scope.requirements = this.$scope.requirements.concat(req); + }); + + this.$scope.capabilities = []; + _.forEach(this.$scope.component.capabilities, (cap:Array<Capability>, capName)=> { + this.$scope.capabilities = this.$scope.capabilities.concat(cap); + }); + + this.$scope.sort = (sortBy:string, sortByTableDefined:SortTableDefined):void => { + sortByTableDefined.reverse = (sortByTableDefined.sortByField === sortBy) ? !sortByTableDefined.reverse : false; + sortByTableDefined.sortByField = sortBy; + }; + + this.$scope.updateProperty = (property:PropertyModel, indexInFilteredProperties:number):void => { + this.openEditPropertyModal(property, indexInFilteredProperties); + }; + + this.$scope.allCapabilitiesSelected = (selected:boolean):void => { + _.forEach(this.$scope.capabilities, (cap:Capability)=> { + cap.selected = selected; + }); + }; + } +} + diff --git a/catalog-ui/src/app/view-models/workspace/tabs/req-and-capabilities/req-and-capabilities-view.html b/catalog-ui/src/app/view-models/workspace/tabs/req-and-capabilities/req-and-capabilities-view.html new file mode 100644 index 0000000000..3d6ccb9d00 --- /dev/null +++ b/catalog-ui/src/app/view-models/workspace/tabs/req-and-capabilities/req-and-capabilities-view.html @@ -0,0 +1,143 @@ +<div class="workspace-req-and-cap"> + <div class="tabs"> + <button data-tests-id="req-tab" data-ng-click="mode='requirements';filterTerms='';" class="tlv-btn" data-ng-class="{'selected':mode=='requirements'}">Requirements({{requirements.length||'0'}})</button> + <button data-tests-id="cap-tab" data-ng-click="mode='capabilities';filterTerms='';" class="tlv-btn" data-ng-class="{'selected':mode=='capabilities'}">Capabilities({{capabilities.length||'0'}})</button> + </div> + <div class="expand-collapse-buttons" data-ng-if="mode=='capabilities'"> + <span class="sprite-new expand-all" data-ng-click="allCapabilitiesSelected(true)"></span> + <span class="sprite-new collapse-all" data-ng-click="allCapabilitiesSelected(false)"></span> + </div> + <div class="search"> + <input id="search-box" data-tests-id="search-box" type="search" placeholder="Search" data-ng-model-options="{debounce: 200}" data-ng-model="filterTerms"/> + <div class="search-icon-container"> + <span class="search-icon sprite-new search-white-icon"></span> + </div> + </div> + <div class="table-container-flex requirements-table" data-ng-if="mode=='requirements'"> + <div class="table" data-ng-class="{'view-mode': isViewMode()}"> + <div class="head flex-container"> + <div class="table-header head-row hand flex-item" data-ng-repeat="header in requirementsTableHeadersList track by $index" data-ng-click="sort(header.property, requirementsSortTableDefined)">{{header.title}} + <span data-ng-if="requirementsSortTableDefined.sortByField === header.property" class="table-header-sort-arrow" data-ng-class="{'down': requirementsSortTableDefined.reverse, 'up':!requirementsSortTableDefined.reverse}"> </span> + </div> + </div> + + <div class="body"> + <perfect-scrollbar scroll-y-margin-offset="0" include-padding="true" class="scrollbar-container"> + <div data-ng-if="requirements.length === 0" class="no-row-text"> + There are no requirements to display + + </div> + <div data-ng-repeat="req in requirements | orderBy:requirementsSortTableDefined.sortByField:requirementsSortTableDefined.reverse | filter: {filterTerm:filterTerms} track by $index" + class="flex-container data-row" data-tests-id="reqRow"> + + <div class="table-col-general flex-item text" tooltips tooltip-content="{{req.name}}"> + <span data-tests-id="{{req.name}}">{{req.name}}</span> + </div> + <div class="table-col-general flex-item text" tooltips tooltip-content="{{req.capability}}"> + <span data-tests-id="{{req.capability}}">{{req.capability.substring("tosca.capabilities.".length)}}</span> + </div> + <div class="table-col-general flex-item text" tooltips tooltip-content="{{req.node}}"> + <span data-tests-id="{{req.node}}">{{req.node.substring("tosca.nodes.".length)}}</span> + </div> + <div class="table-col-general flex-item text" tooltips tooltip-content="{{req.relationship}}"> + <span data-tests-id="{{req.relationship}}">{{req.relationship.substring("tosca.relationships.".length)}}</span> + </div> + <div class="table-col-general flex-item text" data-tests-id="{{}}" data-ng-bind=""></div> + <div class="table-col-general flex-item text" tooltips tooltip-content="{{req.minOccurrences}},{{req.maxOccurrences}}"> + <span data-tests-id="{{req.minOccurrences}},{{req.maxOccurrences}}">{{req.minOccurrences}},{{req.maxOccurrences}}</span> + </div> + </div> + </perfect-scrollbar> + </div> + + </div> + </div> + <div class="table-container-flex capabilities-table" data-ng-if="mode=='capabilities'"> + <div class="table" data-ng-class="{'view-mode': isViewMode()}"> + <div class="head flex-container"> + <div class="table-header head-row hand flex-item" data-ng-repeat="header in capabilitiesTableHeadersList track by $index" data-ng-click="sort(header.property, capabilitiesSortTableDefined)">{{header.title}} + <span data-ng-if="capabilitiesSortTableDefined.sortByField === header.property" class="table-header-sort-arrow" data-ng-class="{'down': capabilitiesSortTableDefined.reverse, 'up':!capabilitiesSortTableDefined.reverse}"> </span> + </div> + </div> + + <div class="body"> + <perfect-scrollbar scroll-y-margin-offset="0" include-padding="true" class="scrollbar-container"> + <div data-ng-if="capabilities.length === 0" class="no-row-text"> + There are no capabilities to display + + </div> + <div data-ng-repeat-start="capability in capabilities | orderBy:capabilitiesSortTableDefined.sortByField:capabilitiesSortTableDefined.reverse | filter: {filterTerm:filterTerms} track by $index" + class="flex-container data-row" data-ng-class="{'selected': capability.selected}" + data-ng-click="capability.selected = !capability.selected" data-tests-id="capabilities-table-row"> + + <div class="table-col-general flex-item text" tooltips tooltip-content="{{capability.name}}"> + <span class="sprite-new arrow-up-small" data-ng-class="{'opened': capability.selected}"></span> + <span data-tests-id="{{capability.name}}">{{capability.name}}</span> + </div> + <div class="table-col-general flex-item text" tooltips tooltip-content="{{capability.type}}"> + <span data-tests-id="{{capability.type}}">{{capability.type.replace("tosca.capabilities.","")}}</span> + </div> + + <div class="table-col-general flex-item text" tooltips tooltip-content="{{capability.description}}"> + <span data-tests-id="{{capability.description}}">{{capability.description}}</span> + </div> + + <div class="table-col-general flex-item text" tooltips tooltip-content="{{capability.validSourceTypes.join(',')}}"> + <span data-tests-id="{{capability.validSourceTypes.join(',')}}">{{capability.validSourceTypes.join(',')}}</span> + </div> + + <div class="table-col-general flex-item text" tooltips tooltip-content="{{capability.minOccurrences}},{{capability.maxOccurrences}}"> + <span data-tests-id="{{capability.minOccurrences}},{{capability.maxOccurrences}}">{{capability.minOccurrences}},{{capability.maxOccurrences}}</span> + </div> + </div> + <div data-ng-repeat-end="" data-ng-if="capability.selected" class="item-opened"> + <p class="properties-title">Properties</p> + <div class="table-container-flex properties-table"> + <div class="table" data-ng-class="{'view-mode': isViewMode()}"> + <div class="head flex-container"> + <div class="table-header head-row hand flex-item" data-ng-repeat="header in capabilityPropertiesTableHeadersList track by $index" data-ng-click="sort(header.property, propertiesSortTableDefined)">{{header.title}} + <span data-ng-if="propertiesSortTableDefined.sortByField === header.property" class="table-header-sort-arrow" data-ng-class="{'down': propertiesSortTableDefined.reverse, 'up':!propertiesSortTableDefined.reverse}"> </span> + </div> + </div> + + <div class="body"> + <div data-ng-if="capability.properties.length === 0" class="no-row-text"> + There are no properties to display + </div> + <div data-ng-repeat="property in filteredProperties[$parent.$index]=(capability.properties | orderBy:propertiesSortTableDefined.sortByField:propertiesSortTableDefined.reverse) track by $index" + data-tests-id="propertyRow" + class="flex-container data-row"> + + <div class="table-col-general flex-item text" tooltips tooltip-content="{{property.name}}"> + <a data-tests-id="{{property.name}}" + data-ng-click="updateProperty(property, $parent.$index); $event.stopPropagation();" + data-ng-class="{'disabled': isViewMode()}">{{property.name}}</a> + + </div> + + <div class="table-col-general flex-item text" + data-tests-id="{{property.type}}" + tooltips tooltip-content="{{property.type}}" + data-ng-bind="property.type"> + </div> + <div class="table-col-general flex-item text" + data-tests-id="{{property.schema.property.type}}" + tooltips tooltip-content="{{property.schema.property.type}}" + data-ng-bind="property.schema.property.type"> + </div> + <div class="table-col-general flex-item text" tooltips tooltip-content="{{property.description}}"> + <span data-tests-id="{{property.description}}" data-ng-bind="property.description"></span> + </div> + </div> + </div> + + </div> + </div> + </div> + </perfect-scrollbar> + </div> + + </div> + </div> +</div> + diff --git a/catalog-ui/src/app/view-models/workspace/tabs/req-and-capabilities/req-and-capabilities.less b/catalog-ui/src/app/view-models/workspace/tabs/req-and-capabilities/req-and-capabilities.less new file mode 100644 index 0000000000..9b52fad411 --- /dev/null +++ b/catalog-ui/src/app/view-models/workspace/tabs/req-and-capabilities/req-and-capabilities.less @@ -0,0 +1,196 @@ +.workspace-req-and-cap { + + width: 93%; + display: inline-block; + + .tabs{ + float: left; + position: relative; + top: 6px; + button{ + float: left; + width: 233px; + height: 38px; + background-color: @tlv_color_t; + border: 1px solid @main_color_o; + color: black; + &:nth-child(1){ + border-radius: 10px 0 0 0; + } + &:nth-child(2){ + border-radius: 0 10px 0 0; + } + &.selected{ + background-color: @main_color_a; + border: 1px solid @main_color_a; + color: white; + } + } + } + .search{ + margin-bottom: 12px; + float: right; + ::-webkit-input-placeholder { + font-style: italic; + } + :-moz-placeholder { + font-style: italic; + } + ::-moz-placeholder { + font-style: italic; + } + :-ms-input-placeholder { + font-style: italic; + } + #search-box{ + -webkit-border-radius: 2px 0 0 2px; + -moz-border-radius: 2px 0 0 2px; + border-radius: 2px 0 0 2px; + width: 213px; + height: 32px; + line-height: 32px; + border: 1px solid @main_color_o; + text-indent: 10px; + float: left; + } + .search-icon-container{ + background-color: @main_color_a; + height: 32px; + width: 32px; + border-radius: 0 2px 2px 0; + float: left; + .search-icon{ + position: relative; + top: 9px; + } + } + } + .expand-collapse-buttons{ + float: right; + width: 44px; + margin-left: 11px; + margin-top: 10px; + span{ + vertical-align: bottom; + .hand; + } + } + + + + .table{ + height:490px; + margin-bottom: 0; + } + + .arrow-up-small{ + &.opened{ + .arrow-up-small-hover; + } + } + + .item-opened{ + background-color: @tlv_color_t; + } + + .properties-title{ + margin:0; + font-weight: bold; + } + + .table-container-flex { + margin-top: 10px; + + .text{ + overflow: hidden; + text-overflow: ellipsis; + display: inline-block; + white-space: nowrap; + } + + &.requirements-table{ + border-top: 4px solid @main_color_a; + .flex-item:nth-child(1) { + flex-grow: 20; + } + + .flex-item:nth-child(2) { + flex-grow: 20; + } + + .flex-item:nth-child(3) { + flex-grow: 20; + } + + .flex-item:nth-child(4) { + flex-grow: 20; + } + + .flex-item:nth-child(5) { + flex-grow: 20; + } + + .flex-item:nth-child(6) { + flex-grow: 20; + } + } + + &.capabilities-table{ + border-top: 4px solid @main_color_a; + .selected{ + .flex-item:nth-child(1) { + border-left: 4px solid @main_color_a; + padding-right: 11px; + } + } + .flex-item:nth-child(1) { + flex-grow: 10; + } + + .flex-item:nth-child(2) { + flex-grow: 10; + } + + .flex-item:nth-child(3) { + flex-grow: 10; + } + + .flex-item:nth-child(4) { + flex-grow: 10; + } + + .flex-item:nth-child(5) { + flex-grow: 10; + } + + } + + &.properties-table{ + .table{ + height: auto; + } + + .flex-item:nth-child(1) { + flex-grow: 15; + a{ + .hand + } + } + + .flex-item:nth-child(2) { + flex-grow: 6; + } + + .flex-item:nth-child(3) { + flex-grow: 6; + } + + .flex-item:nth-child(4) { + flex-grow: 20; + + } + } + + } + +} |