diff options
Diffstat (limited to 'catalog-ui/app/scripts/view-models/wizard/artifact-deployment-step')
3 files changed, 472 insertions, 0 deletions
diff --git a/catalog-ui/app/scripts/view-models/wizard/artifact-deployment-step/artifact-deployment-step.html b/catalog-ui/app/scripts/view-models/wizard/artifact-deployment-step/artifact-deployment-step.html new file mode 100644 index 0000000000..97817d59f2 --- /dev/null +++ b/catalog-ui/app/scripts/view-models/wizard/artifact-deployment-step/artifact-deployment-step.html @@ -0,0 +1,137 @@ +<div class="artifact-deployment-step" data-ng-controller="Sdc.ViewModels.Wizard.ArtifactDeploymentStepViewModel"> + + <div data-tests-id="add-deployment-artifact-button" data-tests-id="addGrey" class="w-sdc-classic-btn gray" data-ng-click="addOrUpdate({})">Add</div> + + <div class="table-container-flex"> + + <div class="table"> + + <div class="head flex-container"> + <div class="table-header head-row hand flex-item" data-ng-repeat="header in tableHeadersList track by $index" data-ng-click="sort(header.property)">{{header.title}} + <span data-ng-if="sortBy === header.property" class="table-header-sort-arrow" data-ng-class="{'down': reverse, 'up':!reverse}"> </span> + </div> + <div class="table-no-text-header head-row flex-item"></div> + </div> + + <form class="body" name="editForm"> + + <perfect-scrollbar scroll-y-margin-offset="0" include-padding="true" class="scrollbar-container"> + + <!-- Artifact row --> + <div ng-if="noArtifactsToShow()" class="no-row-text" translate="DEPLOYMENT_ARTIFACT_NO_ARTIFACTS_TO_DISPLAY"></div> + <div data-ng-repeat-start="artifact in artifacts | orderBy:sortBy:reverse track by $index" + class="flex-container data-row" + data-ng-class="{'selected': artifact.selected || undefined==artifact.selected && updateInProgress}" + data-ng-if="artifact.esId"> + + <div class="table-col-general flex-item" data-ng-click="update(artifact)"> + <loader data-display="isLoading"></loader> + <span class="sprite table-arrow" data-tests-id="{{artifact.artifactDisplayName}}" data-ng-class="{'opened': artifact.selected || undefined==artifact.selected && updateInProgress}"></span> + {{artifact.artifactDisplayName}} + </div> + + <div class="table-col-general flex-item" data-tests-id="{{artifact.artifactType}}"> + {{artifact.artifactType}} + </div> + <div class="table-col-general flex-item" data-tests-id="{{artifact.timeout}}"> + {{artifact.timeout? artifact.timeout:''}} + </div> + + <div class="table-btn-col flex-item" sdc-keyboard-events> + <button class="table-edit-btn" data-ng-click="addOrUpdate(artifact)"></button> + <button class="table-delete-btn" data-ng-click="delete(artifact)"> </button> + </div> + </div> + <div data-ng-repeat-end="" data-ng-if="artifact.selected || undefined==artifact.selected && updateInProgress" class="w-sdc-form item-opened"> + <!-- Artifact panel opened --> + + <!-- Description field --> + <div class="w-sdc-form-item" ng-form="descriptionForm" data-ng-class="{error:(descriptionForm.$dirty && descriptionForm.$invalid)}"> + <label class="i-sdc-env-form-label required">Description</label> + <textarea class="i-sdc-form-textarea {{$index}}" + data-ng-maxlength="256" + maxlength="256" + data-ng-required="true" + name="description" + data-ng-model="artifact.description" + data-ng-model-options="{ debounce: 200 }" + data-ng-pattern="getValidationPattern('string')" + data-tests-id="description"> + </textarea> + + <div class="input-error" data-ng-show="descriptionForm.$dirty && descriptionForm.$invalid"> + <span ng-show="descriptionForm.$error.required" translate="ADD_ARTIFACT_ERROR_DESCRIPTION_REQUIRED"></span> + <span ng-show="descriptionForm.$error.maxlength" translate="VALIDATION_ERROR_MAX_LENGTH" translate-values="{'max': '256' }"></span> + <span ng-show="descriptionForm.$error.pattern" translate="VALIDATION_ERROR_SPECIAL_CHARS_NOT_ALLOWED"></span> + </div> + + </div> + + <!-- Parameters in 2 columns --> + <div class="w-sdc-form-columns-wrapper" data-ng-if="artifact.heatParameters"> + <!-- Left column --> + <div class="w-sdc-form-column"> + <div class="i-sdc-form-item" ng-form="parameterForm" data-ng-repeat="parameter in artifact.heatParameters.slice(0, artifact.heatParameters.length%2+artifact.heatParameters.length/2) | orderBy: 'name' track by $index"> + <label class="i-sdc-env-form-label" data-ng-class="{required:parameter.defaultValue}" tooltip-side="top" sdc-smart-tooltip>{{parameter.name +' (' + parameter.type + ')'}}</label> + <span class="parameter-description" tooltips tooltip-side="top" tooltip-content="{{parameter.description}}">?</span> + <input class="i-sdc-form-input" data-ng-class="{error:(parameterForm.currentValue.$invalid)}" + data-ng-model-options="{ debounce: 200 }" + data-ng-model="parameter.currentValue" + type="text" + name="currentValue" + data-ng-pattern="getValidationPattern(parameter.type, 'heat')" + data-ng-required="parameter.defaultValue" + data-ng-change="'json'==parameter.type && parameterForm.currentValue.$setValidity('pattern', validateJson(parameter.currentValue))" + data-ng-blur="!parameterForm.currentValue.$error.pattern && resetValue(parameter)" + /> + + <div class="input-error" data-ng-show="parameterForm.currentValue.$invalid"> + <span ng-show="parameterForm.currentValue.$error.required" translate="VALIDATION_ERROR_REQUIRED" translate-values="{'field': 'Value'}"></span> + <span ng-show="parameterForm.currentValue.$error.pattern && parameter.type==='string'" translate="VALIDATION_ERROR_SPECIAL_CHARS_NOT_ALLOWED"></span> + <span ng-show="parameterForm.currentValue.$error.pattern && !(parameter.type==='string')" translate="VALIDATION_ERROR_TYPE" translate-values="{'type': '{{parameter.type}}'}"></span> + </div> + </div> + </div> + + <!-- Right column --> + <div class="w-sdc-form-column"> + <div class="i-sdc-form-item" ng-form="parameterForm" data-ng-repeat="parameter in artifact.heatParameters.slice(artifact.heatParameters.length%2+artifact.heatParameters.length/2) | orderBy: 'name' track by $index"> + <label class="i-sdc-env-form-label" data-ng-class="{required:parameter.defaultValue}" tooltip-side="top" sdc-smart-tooltip>{{parameter.name +' (' + parameter.type + ')'}}</label> + <span class="parameter-description" tooltips tooltip-side="top" tooltip-content="{{parameter.description}}">?</span> + <input class="i-sdc-form-input" data-ng-class="{error:(parameterForm.currentValue.$invalid)}" + data-ng-model-options="{ debounce: 200 }" + data-ng-model="parameter.currentValue" + type="text" + name="currentValue" + data-ng-pattern="getValidationPattern(parameter.type, 'heat')" + data-ng-required="parameter.defaultValue" + data-ng-change="'json'==parameter.type && parameterForm.currentValue.$setValidity('pattern', validateJson(parameter.currentValue))" + data-ng-blur="!parameterForm.currentValue.$error.pattern && resetValue(parameter)" + /> + + <div class="input-error" data-ng-show="parameterForm.currentValue.$invalid"> + <span ng-show="parameterForm.currentValue.$error.required" translate="VALIDATION_ERROR_REQUIRED" translate-values="{'field': 'Value'}"></span> + <span ng-show="parameterForm.currentValue.$error.pattern && parameter.type==='string'" translate="VALIDATION_ERROR_SPECIAL_CHARS_NOT_ALLOWED"></span> + <span ng-show="parameterForm.currentValue.$error.pattern && !(parameter.type==='string')" translate="VALIDATION_ERROR_TYPE" translate-values="{'type': '{{parameter.type}}'}"></span> + </div> + </div> + </div> + + </div><!-- Close: Parameters in 2 columns --> + </div><!-- Close: Artifact panel opened --> + + <!-- Add artifacts buttons --> + <button class="add-button" data-ng-repeat="artifact in artifacts track by $index" + data-ng-show="!artifact.esId" + data-tests-id="{{artifact.artifactDisplayName}}" + translate="DEPLOYMENT_ARTIFACT_BUTTON_ADD_HEAT" + translate-values="{'name': '{{artifact.artifactDisplayName}}'}" + data-ng-click="addOrUpdate(artifact)"></button> + + <!-- Top add button --> + <button class="add-button" translate="DEPLOYMENT_ARTIFACT_BUTTON_ADD_OTHER" data-ng-click="addOrUpdate({})"></button> + </perfect-scrollbar> + </form> + </div> + </div> +</div> diff --git a/catalog-ui/app/scripts/view-models/wizard/artifact-deployment-step/artifact-deployment-step.less b/catalog-ui/app/scripts/view-models/wizard/artifact-deployment-step/artifact-deployment-step.less new file mode 100644 index 0000000000..043fba3277 --- /dev/null +++ b/catalog-ui/app/scripts/view-models/wizard/artifact-deployment-step/artifact-deployment-step.less @@ -0,0 +1,107 @@ +.artifact-deployment-step { + + .table-container-flex .table .body .data-row + div.item-opened { + padding: 10px 40px 10px 30px; + } + + .w-sdc-classic-btn { + float: right; + margin-bottom: 10px; + } + + .table { + height:412px; + margin-bottom: 0; + } + + .parameter-description { + .circle(18px, @color_p); + content: '?'; + line-height: 18px; + vertical-align: middle; + margin-left: 5px; + cursor: default; + display: inline-block; + position: absolute; + top: 16px; + } + + .table-container-flex { + + margin-top: 0px; + + .flex-item:nth-child(1) { + flex-grow: 15; + padding: 5px 4px; + .hand; + span.table-arrow { + margin-right: 7px; + + } + } + + .flex-item:nth-child(2) { + padding: 5px 4px; + flex-grow: 6; + } + + .flex-item:nth-child(3) { + padding: 5px 4px; + flex-grow: 9; + } + + .flex-item:nth-child(4) { + padding: 5px 4px; + flex-grow: 3; + padding-top: 10px; + } + } + .w-sdc-form{ + text-align: left; + + .w-sdc-env-params{ + border-top: 1px solid #cdcdcd; + margin: 25px 0 10px 0; + } + + .i-sdc-form-textarea { + border: 1px solid @color_e; + min-height: 60px; + padding: 10px 13px; + width: 100%; + resize: none; + + &:disabled { + .disabled; + } + } + + .w-sdc-form-item { + &.error { + .i-sdc-form-input, + .i-sdc-form-select, + .i-sdc-form-textarea { + border-color: @color_h; + outline: none; + box-sizing: border-box; + } + } + } + + .i-sdc-env-form-label{ + .p_9; + overflow: hidden; + max-width: 245px; + text-overflow: ellipsis; + display: inline-block; + white-space: nowrap; + margin-top: 14px; + + &.required::before { + color: #f33; + content: '*'; + margin-right: 4px; + } + } + } +} diff --git a/catalog-ui/app/scripts/view-models/wizard/artifact-deployment-step/artifact-deployment-step.ts b/catalog-ui/app/scripts/view-models/wizard/artifact-deployment-step/artifact-deployment-step.ts new file mode 100644 index 0000000000..80f145b9b1 --- /dev/null +++ b/catalog-ui/app/scripts/view-models/wizard/artifact-deployment-step/artifact-deployment-step.ts @@ -0,0 +1,228 @@ +/*- + * ============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========================================================= + */ +/// <reference path="../../../references"/> +module Sdc.ViewModels.Wizard { + 'use strict'; + import ArtifactModel = Sdc.Models.ArtifactModel; + + interface IArtifactDeploymentStepViewModelScope extends IWizardCreationStepScope { + tableHeadersList: Array<any>; + reverse: boolean; + sortBy:string; + component: Models.Components.Component; + artifacts: Array<Models.ArtifactModel>; + editForm:ng.IFormController; + isLoading:boolean; + artifactDescriptions:any; + updateInProgress:boolean; + + addOrUpdate(artifact:Models.ArtifactModel): void; + update(artifact:Models.ArtifactModel): void; + delete(artifact:Models.ArtifactModel): void; + sort(sortBy:string): void; + noArtifactsToShow():boolean; + getValidationPattern(validationType:string, parameterType?:string):RegExp; + validateJson(json:string):boolean; + resetValue(parameter:any):void; + } + + export class ArtifactDeploymentStepViewModel implements IWizardCreationStep { + + static '$inject' = [ + '$scope', + '$filter', + '$modal', + '$templateCache', + 'ValidationUtils', + 'ModalsHandler' + ]; + + constructor( + private $scope:IArtifactDeploymentStepViewModelScope, + private $filter:ng.IFilterService, + private $modal:ng.ui.bootstrap.IModalService, + private $templateCache:ng.ITemplateCacheService, + private validationUtils: Sdc.Utils.ValidationUtils, + private ModalsHandler: Utils.ModalsHandler + ){ + this.$scope.registerChild(this); + this.$scope.setValidState(true); + this.initScope(); + } + + private initDescriptions = ():void =>{ + this.$scope.artifactDescriptions = {}; + _.forEach(this.$scope.component.deploymentArtifacts,(artifact:Models.ArtifactModel):void => { + this.$scope.artifactDescriptions[artifact.artifactLabel] = artifact.description; + }); + }; + + + private setArtifact = (artifact:Models.ArtifactModel):void =>{ + if(artifact.heatParameters) { + artifact.heatParameters.forEach((parameter:any):void => { + if (!parameter.currentValue && parameter.defaultValue) { + parameter.currentValue = parameter.defaultValue; + } else if ("" === parameter.currentValue) { + parameter.currentValue = null; + } + }); + } + if(!artifact.description || !this.$scope.getValidationPattern('string').test(artifact.description)){ + artifact.description = this.$scope.artifactDescriptions[artifact.artifactLabel]; + } + }; + + private updateAll = ():void =>{ + let artifacts:Array<Models.ArtifactModel>= []; + _.forEach(this.$scope.component.deploymentArtifacts,(artifact:Models.ArtifactModel): void => { + if(artifact.selected) { + this.setArtifact(artifact); + artifacts.push(artifact); + } + }); + this.$scope.component.updateMultipleArtifacts(artifacts); + }; + + + + private initScope = (): void => { + let self = this; + this.$scope.isLoading = false; + this.$scope.updateInProgress = false; + this.$scope.component = this.$scope.getComponent(); + this.initDescriptions(); + this.$scope.artifacts = <ArtifactModel[]>_.values(this.$scope.component.deploymentArtifacts); + + + this.$scope.tableHeadersList = [ + {title:'Name', property: 'artifactDisplayName'}, + {title:'Type', property: 'artifactType'}, + {title:'Deployment timeout', property: 'timeout'} + ]; + + this.$scope.sort = (sortBy:string):void => { + this.$scope.reverse = (this.$scope.sortBy === sortBy) ? !this.$scope.reverse : false; + this.$scope.sortBy = sortBy; + }; + + this.$scope.getValidationPattern = (validationType:string, parameterType?:string):RegExp => { + return this.validationUtils.getValidationPattern(validationType, parameterType); + }; + + this.$scope.validateJson = (json:string):boolean => { + if(!json){ + return true; + } + return this.validationUtils.validateJson(json); + }; + + + this.$scope.addOrUpdate = (artifact:Models.ArtifactModel): void => { + artifact.artifactGroupType = 'DEPLOYMENT'; + let artifactCopy = new Models.ArtifactModel(artifact); + this.ModalsHandler.openWizardArtifactModal(artifactCopy, this.$scope.component).then(() => { + this.$scope.artifactDescriptions[artifactCopy.artifactLabel]= artifactCopy.description; + this.$scope.artifacts = <ArtifactModel[]>_.values(this.$scope.component.deploymentArtifacts); + }) + }; + + this.$scope.noArtifactsToShow = ():boolean =>{ + return !_.some(this.$scope.artifacts, 'esId'); + }; + + this.$scope.resetValue = (parameter:any):void => { + if(!parameter.currentValue && parameter.defaultValue){ + parameter.currentValue = parameter.defaultValue; + } + else if('boolean'==parameter.type){ + parameter.currentValue = parameter.currentValue.toUpperCase(); + } + }; + + + this.$scope.$watch('editForm.$valid', ():void => { + if(this.$scope.editForm) { + this.$scope.setValidState(this.$scope.editForm.$valid); + } + }); + + this.$scope.update = (artifact:Models.ArtifactModel):void =>{ + if(false == this.$scope.isLoading) { + if(artifact.selected) { + this.$scope.isLoading = true; + this.$scope.updateInProgress = true; + let onSuccess = (responseArtifact:Models.ArtifactModel):void => { + this.$scope.artifactDescriptions[responseArtifact.artifactLabel] = responseArtifact.description; + this.$scope.artifacts = <ArtifactModel[]>_.values(this.$scope.component.deploymentArtifacts); + this.$scope.isLoading = false; + this.$scope.updateInProgress = false; + artifact.selected = !artifact.selected; + }; + + let onFailed = (error:any):void => { + console.log('Delete artifact returned error:', error); + this.$scope.isLoading = false; + this.$scope.updateInProgress = false; + artifact.selected = !artifact.selected; + }; + + this.setArtifact(artifact); + this.$scope.component.addOrUpdateArtifact(artifact).then(onSuccess, onFailed); + } else { + artifact.selected = !artifact.selected; + } + } + }; + + this.$scope.delete = (artifact:Models.ArtifactModel):void => { + let onOk = ():void => { + this.$scope.isLoading = true; + let onSuccess = ():void => { + this.$scope.isLoading = false; + this.$scope.artifacts = <ArtifactModel[]>_.values(this.$scope.component.deploymentArtifacts); + }; + + let onFailed = (error:any):void => { + this.$scope.isLoading = false; + console.log('Delete artifact returned error:', error); + }; + + this.$scope.component.deleteArtifact(artifact.uniqueId, artifact.artifactLabel).then(onSuccess, onFailed); + }; + + let title:string = self.$filter('translate')("ARTIFACT_VIEW_DELETE_MODAL_TITLE"); + let message:string = self.$filter('translate')("ARTIFACT_VIEW_DELETE_MODAL_TEXT", "{'name': '" + artifact.artifactDisplayName + "'}"); + this.ModalsHandler.openConfirmationModal(title, message, false).then(onOk); + }; + }; + + public save = (callback:Function):void => { + this.updateAll(); + this.$scope.setComponent(this.$scope.component); + callback(true); + }; + + public back = (callback:Function):void => { + this.$scope.setComponent(this.$scope.component); + callback(true); + } + } +} |