http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/components/conditional-data-input.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/conditional-data-input.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/conditional-data-input.js new file mode 100644 index 0000000..83d8a8e --- /dev/null +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/conditional-data-input.js @@ -0,0 +1,78 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You 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. +*/ +import Ember from 'ember'; +import { validator, buildValidations } from 'ember-cp-validations'; + +const Validations = buildValidations({ + 'condition.operator': validator('presence', { + presence : true + }), + 'condition.operands': { + validators: [ + validator('operand-length', { + min : 2, + dependentKeys: ['condition.operands.[]','condition.operator'] + }) + ] + } +}); + +export default Ember.Component.extend(Validations, { + initialize : function(){ + this.set('conditionsList', Ember.A([])); + this.get('conditionsList').pushObjects([ + {value : 'and', displayName: 'All'}, + {value : 'or', displayName: 'Any'} + ]); + if(!this.get('isToplevel')){ + this.get('conditionsList').pushObject({value : 'combine', displayName: 'Combine'}); + } + this.sendAction('register', this, this); + }.on('init'), + onDestroy : function(){ + this.sendAction('deregister', this); + }.on('willDestroyElement'), + actions : { + registerChild (key, context){ + this.sendAction('register', key, context); + }, + deregisterChild(key){ + this.sendAction('deregister', key); + }, + addCondition(){ + if(!this.get('condition.operands')){ + this.set('condition.operands', Ember.A([])); + } + this.get('condition.operands').pushObject({operands : Ember.A([]), type:'condition'}); + }, + addDataInput(){ + if(!this.get('condition.operands')){ + this.set('condition.operands', Ember.A([])); + } + this.get('condition.operands').pushObject({type:'dataInput'}); + }, + deleteOperand(index){ + this.get('condition.operands').removeAt(index); + }, + showAdvanced(){ + this.set('showAdvanced', true); + }, + hideAdvanced(){ + this.set('showAdvanced', false); + } + } +});
http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/components/confirmation-dialog.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/confirmation-dialog.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/confirmation-dialog.js new file mode 100644 index 0000000..6f726f0 --- /dev/null +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/confirmation-dialog.js @@ -0,0 +1,25 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You 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. +*/ +import Ember from 'ember'; + +export default Ember.Component.extend({ + actions : { + onOk (){ + this.sendAction('onOk'); + } + } +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js new file mode 100644 index 0000000..57fcdf8 --- /dev/null +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js @@ -0,0 +1,521 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You 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. +*/ +import Ember from 'ember'; +import {Coordinator} from '../domain/coordinator/coordinator'; +import {CoordinatorGenerator} from '../domain/coordinator/coordinator-xml-generator'; +import {CoordinatorXmlImporter} from '../domain/coordinator/coordinator-xml-importer'; +import {SlaInfo} from '../domain/sla-info'; +import Constants from '../utils/constants'; +import { validator, buildValidations } from 'ember-cp-validations'; + +const Validations = buildValidations({ + 'coordinator.name': validator('presence', { + presence : true + }), + 'coordinator.workflow.appPath': validator('presence', { + presence : true + }), + 'coordinator.frequency.value': validator('presence', { + presence : true + }), + 'coordinator.frequency.type': validator('presence', { + presence : true + }), + 'coordinator.timezone': validator('presence', { + presence : true + }) +}); + +export default Ember.Component.extend(Validations, Ember.Evented, { + coordinator : null, + childComponents : new Map(), + fileBrowser : Ember.inject.service('file-browser'), + propertyExtractor : Ember.inject.service('property-extractor'), + workspaceManager : Ember.inject.service('workspace-manager'), + showErrorMessage: Ember.computed.alias('saveAttempted'), + datasetsForInputs : Ember.computed('coordinator.datasets.[]','coordinator.dataOutputs.[]',function(){ + var datasetsForInputs = Ember.copy(this.get('coordinator.datasets')); + this.get('coordinator.dataOutputs').forEach((dataOutput)=>{ + var existing = datasetsForInputs.findBy('name', dataOutput.dataset); + if(existing){ + datasetsForInputs = datasetsForInputs.without(existing); + } + }.bind(this)); + return datasetsForInputs; + }), + datasetsForOutputs : Ember.computed('coordinator.datasets.[]','coordinator.dataInputs.[]',function(){ + var datasetsForOutputs = Ember.copy(this.get('coordinator.datasets')); + this.get('coordinator.dataInputs').forEach((dataInput)=>{ + var existing = datasetsForOutputs.findBy('name', dataInput.dataset); + if(existing){ + datasetsForOutputs = datasetsForOutputs.without(existing); + } + }.bind(this)); + return datasetsForOutputs; + }), + onDestroy : function(){ + Ember.run.cancel(this.schedulePersistWorkInProgress); + this.persistWorkInProgress(); + }.on('willDestroyElement'), + initialize : function(){ + var draftCoordinator = this.get('workspaceManager').restoreWorkInProgress(this.get('tabInfo.id')); + if(draftCoordinator){ + this.set('coordinator', JSON.parse(draftCoordinator)); + }else{ + this.set('coordinator', this.createNewCoordinator()); + } + this.set('timeUnitOptions',Ember.A([])); + this.get('timeUnitOptions').pushObject({value:'',displayName:'Select'}); + this.get('timeUnitOptions').pushObject({value:'months',displayName:'Months'}); + this.get('timeUnitOptions').pushObject({value:'endOfMonths',displayName:'End of Months'}); + this.get('timeUnitOptions').pushObject({value:'days',displayName:'Days'}); + this.get('timeUnitOptions').pushObject({value:'endOfDays',displayName:'End of Days'}); + this.get('timeUnitOptions').pushObject({value:'hours',displayName:'Hours'}); + this.get('timeUnitOptions').pushObject({value:'minutes',displayName:'Minutes'}); + this.get('timeUnitOptions').pushObject({value:'cron',displayName:'Cron'}); + this.set('coordinator.slaInfo', SlaInfo.create({})); + + this.get('fileBrowser').on('fileBrowserOpened',function(context){ + this.get('fileBrowser').setContext(context); + }.bind(this)); + this.on('fileSelected',function(fileName){ + this.set(this.get('filePathModel'), fileName); + }.bind(this)); + this.set('coordinatorControls',[ + {'name':'timeout', 'displayName':'Timeout', 'value':''}, + {'name':'concurrency', 'displayName':'Concurrency', 'value':''}, + {'name':'execution', 'displayName':'Execution', 'value':''}, + {'name':'throttle', 'displayName':'Throttle', 'value':''} + ]); + this.set('timezoneList', Ember.copy(Constants.timezoneList)); + if(Ember.isBlank(this.get('coordinator.name'))){ + this.set('coordinator.name', Ember.copy(this.get('tabInfo.name'))); + } + this.schedulePersistWorkInProgress(); + }.on('init'), + conditionalDataInExists :false, + elementsInserted : function(){ + this.$("input[name=dataInputType][value=" + this.get('coordinator.dataInputType') + "]").prop('checked','checked'); + }.on('didInsertElement'), + observeXmlAppPath : Ember.observer('xmlAppPath', function(){ + if(!this.get('xmlAppPath') || null === this.get('xmlAppPath')){ + return; + } else { + this.showExistingWorkflow(); + } + }), + observeFilePath : Ember.observer('coordinatorFilePath', function(){ + if(!this.get('coordinatorFilePath') || null === this.get('coordinatorFilePath')){ + return; + }else{ + this.sendAction('changeFilePath', this.get('tabInfo'), this.get('coordinatorFilePath')); + } + }), + nameObserver : Ember.observer('coordinator.name', function(){ + if(!this.get('coordinator')){ + return; + }else if(this.get('coordinator') && Ember.isBlank(this.get('coordinator.name'))){ + if(!this.get('clonedTabInfo')){ + this.set('clonedTabInfo', Ember.copy(this.get('tabInfo'))); + } + this.sendAction('changeTabName', this.get('tabInfo'), this.get('clonedTabInfo.name')); + }else{ + this.sendAction('changeTabName', this.get('tabInfo'), this.get('coordinator.name')); + } + }), + schedulePersistWorkInProgress (){ + Ember.run.later(function(){ + this.persistWorkInProgress(); + this.schedulePersistWorkInProgress(); + }.bind(this), Constants.persistWorkInProgressInterval); + }, + persistWorkInProgress(){ + if(!this.get('coordinator')){ + return; + } + var json = JSON.stringify(this.get("coordinator")); + this.get('workspaceManager').saveWorkInProgress(this.get('tabInfo.id'), json); + }, + showExistingWorkflow : function(){ + if(!this.get('xmlAppPath')){ + return; + } + var workflowXmlPath = this.get("xmlAppPath"), relXmlPath = "", tempArr; + if(workflowXmlPath.indexOf("://") === -1 && workflowXmlPath.indexOf(":") === -1){ + relXmlPath = workflowXmlPath; + } else{ + tempArr = workflowXmlPath.split("//")[1].split("/"); + tempArr.splice(0, 1); + relXmlPath = "/" + tempArr.join("/"); + if(relXmlPath.indexOf(".xml") !== relXmlPath.length-4) { + if(relXmlPath.charAt(relXmlPath.length-1) !== "/"){ + relXmlPath = relXmlPath+ "/" +"workflow.xml"; + } else{ + relXmlPath = relXmlPath+"workflow.xml"; + } + } + } + this.importCoordinator(relXmlPath); + }.on('didInsertElement'), + createNewCoordinator(){ + return Coordinator.create({ + workflow : { + appPath : undefined, + configuration :{ + property : Ember.A([]) + } + }, + frequency : { + type : undefined, + value : undefined + }, + start : { + value : undefined, + displayValue : undefined, + type : 'date' + }, + end : { + value : undefined, + displayValue : undefined, + type : 'date' + }, + timezone : 'UTC', + datasets : Ember.A([]), + dataInputs : Ember.A([]), + dataOutputs : Ember.A([]), + dataInputType : 'simple', + parameters : { + configuration :{ + property : Ember.A([]) + } + }, + controls : Ember.A([]), + slainfo : SlaInfo.create({}) + }); + }, + importSampleCoordinator (){ + var deferred = Ember.RSVP.defer(); + Ember.$.ajax({ + url: "/sampledata/coordinator.xml", + dataType: "text", + cache:false, + success: function(data) { + var coordinatorXmlImporter = CoordinatorXmlImporter.create({}); + var coordinator = coordinatorXmlImporter.importCoordinator(data); + deferred.resolve(coordinator); + }.bind(this), + failure : function(data){ + deferred.reject(data); + } + }); + return deferred; + }, + importSampleWorkflow (){ + var deferred = Ember.RSVP.defer(); + Ember.$.ajax({ + url: "/sampledata/workflow.xml", + dataType: "text", + cache:false, + success: function(data) { + deferred.resolve(data); + }.bind(this), + failure : function(data){ + deferred.reject(data); + } + }); + return deferred; + }, + importCoordinator (filePath){ + this.set("coordinatorFilePath", filePath); + this.set("isImporting", false); + var deferred = this.readFromHdfs(filePath); + deferred.promise.then(function(data){ + this.getCoordinatorFromXml(data); + this.set("isImporting", false); + }.bind(this)).catch(function(){ + this.set("isImporting", false); + this.set("isImportingSuccess", false); + }.bind(this)); + }, + readFromHdfs(filePath){ + var url = Ember.ENV.API_URL + "/readWorkflowXml?workflowXmlPath="+filePath; + var deferred = Ember.RSVP.defer(); + Ember.$.ajax({ + url: url, + method: 'GET', + dataType: "text", + beforeSend: function (xhr) { + xhr.setRequestHeader("X-XSRF-HEADER", Math.round(Math.random()*100000)); + xhr.setRequestHeader("X-Requested-By", "Ambari"); + } + }).done(function(data){ + deferred.resolve(data); + }).fail(function(){ + deferred.reject(); + }); + return deferred; + }, + getCoordinatorFromXml(coordinatorXml){ + var coordinatorXmlImporter = CoordinatorXmlImporter.create({}); + var coordinator = coordinatorXmlImporter.importCoordinator(coordinatorXml); + this.set("coordinator", coordinator); + this.$('input[name="dataInputType"][value="'+ coordinator.get('dataInputType')+'"]').prop('checked', true); + if(coordinator.get('dataInputType') === 'logical'){ + this.set('conditionalDataInExists', true); + } + }, + validateChildComponents(){ + var isChildComponentsValid = true; + this.get('childComponents').forEach((context)=>{ + if(context.get('validations') && context.get('validations.isInvalid')){ + isChildComponentsValid = false; + context.set('showErrorMessage', true); + } + }.bind(this)); + return isChildComponentsValid; + }, + actions : { + registerChild(key, context){ + this.get('childComponents').set(key, context); + }, + deregisterChild(key){ + this.get('childComponents').delete(key); + }, + createDataset(){ + this.set('datasetEditMode', false); + this.set('datasetCreateMode', true); + this.set('currentDataset',{}); + }, + editDataset(index){ + this.set('datasetEditMode', true); + this.set('datasetCreateMode', false); + this.set('currentDatasetIndex', index); + this.set('currentDataset', Ember.copy(this.get('coordinator.datasets').objectAt(index))); + }, + addDataset(){ + this.get('coordinator.datasets').pushObject(Ember.copy(this.get('currentDataset'))); + this.set('datasetCreateMode', false); + }, + updateDataset(){ + this.get('coordinator.datasets').replace(this.get('currentDatasetIndex'), 1, Ember.copy(this.get('currentDataset'))); + this.set('datasetEditMode', false); + }, + cancelDatasetOperation(){ + this.set('datasetCreateMode', false); + this.set('datasetEditMode', false); + }, + deleteDataset(index){ + this.get('coordinator.datasets').removeAt(index); + if(index === this.get('currentDatasetIndex')){ + this.set('datasetEditMode', false); + } + }, + createDataInput(){ + this.set('dataInputEditMode', false); + this.set('dataInputCreateMode', true); + this.set('currentDataInput', {}); + }, + addDataInput(){ + this.get('coordinator.dataInputs').pushObject(Ember.copy(this.get('currentDataInput'))); + this.set('dataInputCreateMode', false); + }, + editDataInput(index){ + this.set('dataInputCreateMode', false); + this.set('dataInputEditMode', true); + this.set('currentDataInputIndex', index); + this.set('currentDataInput', Ember.copy(this.get('coordinator.dataInputs').objectAt(index))); + }, + updateDataInput(){ + this.get('coordinator.dataInputs').replace(this.get('currentDataInputIndex'), 1, Ember.copy(this.get('currentDataInput'))); + this.set('dataInputEditMode', false); + }, + deleteDataInput(index){ + this.get('coordinator.dataInputs').removeAt(index); + if(index === this.get('currentDataInputIndex')){ + this.set('dataInputEditMode', false); + } + }, + cancelDataInputOperation(){ + this.set('dataInputEditMode', false); + this.set('dataInputCreateMode', false); + }, + createDataOutput(){ + this.set('dataOutputEditMode', false); + this.set('dataOutputCreateMode', true); + this.set('currentDataOutput', {}); + }, + addDataOutput(){ + this.get('coordinator.dataOutputs').pushObject(Ember.copy(this.get('currentDataOutput'))); + this.set('dataOutputCreateMode', false); + }, + editDataOutput(index){ + this.set('dataOutputCreateMode', false); + this.set('dataOutputEditMode', true); + this.set('currentDataOutputIndex', index); + this.set('currentDataOutput', Ember.copy(this.get('coordinator.dataOutputs').objectAt(index))); + }, + updateDataOutput(){ + this.get('coordinator.dataOutputs').replace(this.get('currentDataOutputIndex'), 1, Ember.copy(this.get('currentDataOutput'))); + this.set('dataOutputEditMode', false); + }, + deleteDataOutput(index){ + this.get('coordinator.dataOutputs').removeAt(index); + if(index === this.get('currentDataOutputIndex')){ + this.set('dataOutputEditMode', false); + } + }, + cancelDataOutputOperation(){ + this.set('dataOutputEditMode', false); + this.set('dataOutputCreateMode', false); + }, + submitCoordinator(){ + var isChildComponentsValid = this.validateChildComponents(); + if(this.get('validations.isInvalid') || !isChildComponentsValid) { + this.set('showErrorMessage', true); + return; + } + var coordGenerator=CoordinatorGenerator.create({coordinator:this.get("coordinator")}); + var coordinatorXml=coordGenerator.process(); + var dynamicProperties = this.get('propertyExtractor').getDynamicProperties(coordinatorXml); + var configForSubmit={props:dynamicProperties,xml:coordinatorXml,params:this.get('coordinator.parameters')}; + this.set("coordinatorConfigs", configForSubmit); + this.set("showingJobConfig", true); + }, + closeCoordSubmitConfig(){ + this.set("showingJobConfig", false); + }, + closeFileBrowser(){ + this.set("showingFileBrowser", false); + this.get('fileBrowser').getContext().trigger('fileSelected', this.get('filePath')); + if(this.get('coordinatorFilePath')){ + this.importCoordinator(Ember.copy(this.get('coordinatorFilePath'))); + this.set('coordinatorFilePath', null); + } + }, + openFileBrowser(model, context){ + if(!context){ + context = this; + } + this.get('fileBrowser').trigger('fileBrowserOpened',context); + this.set('filePathModel', model); + this.set('showingFileBrowser', true); + }, + createCondition(){ + this.set('coordinator.conditionalDataInput', {type:'condition', operator:'and'}); + this.set('conditionalDataInExists', true); + }, + deleteCondition(index){ + this.set('coordinator.conditionalDataInput', undefined); + this.set('conditionalDataInExists', false); + }, + toggleDataTnput(type){ + this.set('coordinator.dataInputType', type); + }, + createInputLogic(){ + this.set('coordinator.inputLogic', {type:'condition', operator:'and'}); + this.set('inputLogicExists', true); + }, + deleteInputLogic(index){ + this.set('coordinator.inputLogic', undefined); + this.set('inputLogicExists', false); + }, + preview(){ + var isChildComponentsValid = this.validateChildComponents(); + if(this.get('validations.isInvalid') || !isChildComponentsValid) { + this.set('showErrorMessage', true); + return; + } + this.set("showingPreview", false); + var coordGenerator = CoordinatorGenerator.create({coordinator:this.get("coordinator")}); + var coordinatorXml = coordGenerator.process(); + this.set("previewXml", vkbeautify.xml(coordinatorXml)); + this.set("showingPreview", true); + }, + confirmReset(){ + this.set('showingResetConfirmation', true); + }, + resetCoordinator(){ + this.set('coordinator', this.createNewCoordinator()); + }, + importCoordinatorTest(){ + var deferred = this.importSampleCoordinator(); + deferred.promise.then(function(data){ + this.set("coordinator", data); + this.$('input[name="dataInputType"][value="'+ data.get('dataInputType')+'"]').prop('checked', true); + if(data.get('dataInputType') === 'logical'){ + this.set('conditionalDataInExists', true); + } + console.error(this.get('coordinator')); + }.bind(this)).catch(function(e){ + throw new Error(e); + }); + }, + openTab(type, path){ + this.sendAction('openTab', type, path); + }, + showParameterSettings(value){ + if(this.get('coordinator.parameters') !== null){ + this.set('parameters', Ember.copy(this.get('coordinator.parameters'))); + }else{ + this.set('parameters', {}); + } + this.set('showParameterSettings', value); + }, + closeWorkFlowParam(){ + this.set("showParameterSettings", false); + }, + saveWorkFlowParam(){ + this.set('coordinator.parameters', Ember.copy(this.get('parameters'))); + this.set("showParameterSettings", false); + }, + showControlConfig(){ + if(this.get('coordinator.controls')){ + this.get('coordinatorControls').forEach((control)=>{ + var coordControl = this.get('coordinator.controls').findBy('name', control.name); + if(coordControl){ + Ember.set(control, 'value', coordControl.value); + }else{ + Ember.set(control, 'value', ''); + } + }, this); + } + this.set('showControlConfig', true); + }, + saveCoordControls(){ + this.get('coordinatorControls').forEach((control)=>{ + var coordControl = this.get('coordinator.controls').findBy('name', control.name); + if(coordControl){ + Ember.set(coordControl, 'value', control.value); + }else{ + this.get('coordinator.controls').pushObject({'name':control.name, 'value':control.value}); + } + }, this); + this.set('showControlConfig', false); + }, + showWorkflowName(){ + this.set('workflowName', null); + var deferred = this.readFromHdfs(this.get('coordinator.workflow.appPath')); + deferred.promise.then(function(data){ + var x2js = new X2JS(); + var workflowJson = x2js.xml_str2json(data); + this.set('workflowName', workflowJson["workflow-app"]._name); + }.bind(this)).catch(function(){ + this.set('workflowName', null); + }.bind(this)); + } + } +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/components/credentials-config.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/credentials-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/credentials-config.js index f100808..32e2103 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/components/credentials-config.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/credentials-config.js @@ -15,29 +15,39 @@ * limitations under the License. */ import Ember from 'ember'; -import EmberValidations from 'ember-validations'; +import { validator, buildValidations } from 'ember-cp-validations'; -export default Ember.Component.extend(EmberValidations, { +const Validations = buildValidations({ + 'credential.name': validator('presence', { + presence : true, + message : 'Required' + }), + 'credential.type': validator('presence', { + presence : true, + message : 'Required' + }) +}); + +export default Ember.Component.extend(Validations, { childComponents : new Map(), initialize : function(){ + if(this.get('mode') === 'create'){ + this.set("credential", {}); + this.set("credential.property", Ember.A([])); + } + this.initializeCredentialDetails(); if(this.get('mode') === 'edit'){ this.sendAction('register', this, this); } this.get('childComponents').clear(); this.set('credentialType',Ember.A([])); - this.get('credentialType').pushObject({value:'',displayName:'Select'}); + this.get('credentialType').pushObject({value:undefined,displayName:'Select'}); this.get('credentialType').pushObject({value:'hcat',displayName:'HCat'}); this.get('credentialType').pushObject({value:'hive2',displayName:'Hive2'}); this.get('credentialType').pushObject({value:'hbase',displayName:'HBase'}); Ember.addObserver(this, 'credential.type', this, this.credentialTypeObserver); - this.initializeCredentialDetails(); - - if(this.get('mode') === 'create'){ - this.set("credential", {}); - this.set("credential.property", Ember.A([])); - } if(this.get('credential.type') && this.get('credential.property')){ this.set('staticProps', Ember.copy(this.get('credentialDetails').findBy('name',this.get('credential.type')).staticProps)); var configProperties = this.get('credential.property'); @@ -50,37 +60,35 @@ export default Ember.Component.extend(EmberValidations, { }); } }.on('init'), - rendered : function(){ - if(this.get('mode') === 'create'){ - this.$('.collapse').collapse('show'); - }else if(this.get('mode') === 'edit'){ - this.$('.collapse').collapse('hide'); + bindStaticPropsOnEdit : function(){ + if(this.get('mode') === 'edit'){ + this.processStaticProps(); } - }.on('didInsertElement'), + }.on('willDestroyElement'), initializeCredentialDetails : function(){ this.set('credentialDetails', Ember.A([])); this.get('credentialDetails').pushObject({ name:'hcat', staticProps: - [{name:'hcat.metastore.principal',displayName:'Hcat Metastore principal', value:'', belongsTo:'credential.property'}, - {name:'hcat.metastore.uri',displayName:'Hcat Metastore uri', value:'', belongsTo:'credential.property'}] + [{name:'hcat.metastore.principal',displayName:'Hcat Metastore principal', value:undefined, belongsTo:'credential.property'}, + {name:'hcat.metastore.uri',displayName:'Hcat Metastore uri', value:undefined, belongsTo:'credential.property'}] }); this.get('credentialDetails').pushObject({ name:'hive2', staticProps: - [{name:'hive2.jdbc.url',displayName:'Hive2 Jdbc Url', value:'', belongsTo:'credential.property'}, - {name:'hive2.server.principal',displayName:'Hive2 Server principal', value:'', belongsTo:'credential.property'}] + [{name:'hive2.jdbc.url',displayName:'Hive2 Jdbc Url', value:undefined, belongsTo:'credential.property'}, + {name:'hive2.server.principal',displayName:'Hive2 Server principal', value:undefined, belongsTo:'credential.property'}] }); this.get('credentialDetails').pushObject({ name:'hbase', staticProps: - [{name:'hadoop.security.authentication',displayName:'Hadoop security auth', value:'', belongsTo:'credential.property'}, - {name:'hbase.security.authentication',displayName:'Hbase security auth', value:'', belongsTo:'credential.property'}, - {name:'hbase.master.kerberos.principal',displayName:'Hbase Master kerberos principal', value:'', belongsTo:'credential.property'}, - {name:'hbase.regionserver.kerberos.principal',displayName:'Hbase regionserver kerberos principal', value:'', belongsTo:'credential.property'}, - {name:'hbase.zookeeper.quorum',displayName:'Hbase zookeeper quorum', value:'', belongsTo:'credential.property'}, - {name:'hadoop.rpc.protection',displayName:'Hadoop Rpc protection', value:'', belongsTo:'credential.property'}, - {name:'hbase.rpc.protection',displayName:'Hbase Rpc protection', value:'', belongsTo:'credential.property'}] + [{name:'hadoop.security.authentication',displayName:'Hadoop security auth', value:undefined, belongsTo:'credential.property'}, + {name:'hbase.security.authentication',displayName:'Hbase security auth', value:undefined, belongsTo:'credential.property'}, + {name:'hbase.master.kerberos.principal',displayName:'Hbase Master kerberos principal', value:undefined, belongsTo:'credential.property'}, + {name:'hbase.regionserver.kerberos.principal',displayName:'Hbase regionserver kerberos principal', value:undefined, belongsTo:'credential.property'}, + {name:'hbase.zookeeper.quorum',displayName:'Hbase zookeeper quorum', value:undefined, belongsTo:'credential.property'}, + {name:'hadoop.rpc.protection',displayName:'Hadoop Rpc protection', value:undefined, belongsTo:'credential.property'}, + {name:'hbase.rpc.protection',displayName:'Hbase Rpc protection', value:undefined, belongsTo:'credential.property'}] }); }, credentialTypeObserver : function(){ @@ -97,93 +105,56 @@ export default Ember.Component.extend(EmberValidations, { } }); }, - resetForm : function(){ - this.set('credential', {}); - this.set('credential.property',Ember.A([])); - this.get('staticProps').clear(); - this.initializeCredentialDetails(); - }, - validateChildrenComponents(){ - var validationPromises = []; - var deferred = Ember.RSVP.defer(); - if(this.get('childComponents').size === 0){ - deferred.resolve(true); - }else{ - this.get('childComponents').forEach((childComponent)=>{ - if(!childComponent.validations){ - return; - } - var validationDeferred = Ember.RSVP.defer(); - childComponent.validate().then(()=>{ - validationDeferred.resolve(); - }).catch((e)=>{ - validationDeferred.reject(e); - }); - validationPromises.push(validationDeferred.promise); - }); - Ember.RSVP.Promise.all(validationPromises).then(function(){ - deferred.resolve(true); - }).catch(function(e){ - deferred.reject(e); - }); + processStaticProps() { + var staticProps = this.get('staticProps'); + var index = 0; + if(!staticProps){ + return; } - return deferred; - }, - validations : { - 'credential.name': { - presence: { - 'message' : 'Required', + staticProps.forEach((property)=>{ + var existingStaticProp = this.get('credential.property').findBy('name',property.name); + if (existingStaticProp) { + Ember.set(existingStaticProp,'value',property.value); + index++; + } else { + var propObj = {name : property.name, value:property.value, static:true}; + this.get('credential.property').insertAt(index++, propObj); } - }, - 'credential.type': { - presence: { - 'message' : 'Required', + }.bind(this)); + }, + validateChildrenComponents(){ + var isChildComponentsValid = true; + this.get('childComponents').forEach((context)=>{ + if(context.get('validations') && context.get('validations.isInvalid')){ + isChildComponentsValid = false; + context.set('showErrorMessage', true); } - } + }.bind(this)); + return isChildComponentsValid; }, actions : { register(component, context){ - if(this.get('mode') === 'edit'){ - this.sendAction('register', component, context); - } this.get('childComponents').set(component, context); }, add(){ - var isFormValid = this.validateChildrenComponents(); - isFormValid.promise.then(function(){ - this.validate().then(function(){ - var staticProps = this.get('staticProps'); - var index = 0; - staticProps.forEach((property)=>{ - var existingStaticProp = this.get('credential.property').findBy('name',property.name); - if (existingStaticProp) { - Ember.set(existingStaticProp,'value',property.value); - index++; - } else { - var propObj = {name : property.name, value:property.value, static:true}; - this.get('credential.property').insertAt(index++, propObj); - } - }); - this.processMultivaluedComponents(); - this.sendAction('add',this.get('credential')); - this.resetForm(); - }.bind(this)).catch(function(e){ - }.bind(this)); - }.bind(this)).catch(function (e) { - }); - - }, - delete(name){ - this.sendAction('delete',name); - }, - togglePanel (){ - this.$('.collapse').collapse('toggle'); - if(this.$('.collapse').hasClass('in')){ - this.set('isOpen', true); + var isChildComponentsValid = this.validateChildrenComponents(); + if(this.get('validations.isInvalid') || !isChildComponentsValid) { + this.set('showErrorMessage', true); + return; + } + this.processStaticProps(); + this.processMultivaluedComponents(); + if(this.get('mode') === 'create'){ + this.sendAction('add',this.get('credential')); }else{ - this.set('isOpen', false); + this.sendAction('update'); } + }, + cancel (){ + this.sendAction('cancel'); + }, + unregister(component, context){ + this.get('childComponents').delete(component); } } - }); http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/components/data-input-output-config.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/data-input-output-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/data-input-output-config.js new file mode 100644 index 0000000..5ce92f5 --- /dev/null +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/data-input-output-config.js @@ -0,0 +1,97 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You 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. +*/ +import Ember from 'ember'; +import { validator, buildValidations } from 'ember-cp-validations'; + +const Validations = buildValidations({ + 'data.name': validator('presence', { + presence : true + }), + 'data.dataset': validator('presence', { + presence : true + }) +}); + +export default Ember.Component.extend(Validations, { + initialize : function(){ + if(!this.get('data.start')){ + this.set('data.start',{ + type : 'date', + value :'' + }); + } + if(!this.get('data.end')){ + this.set('data.end',{ + type : 'date', + value :'' + }); + } + if(this.get('type') === 'output'){ + if(!this.get('data.instance')){ + this.set('data.instance',{ + type : 'date', + value :'' + }); + } + } + if(this.get('type') === 'input' && !this.get('data.instances')){ + this.set('data.instances', Ember.A([])); + this.set('data.isList', true); + } + this.set('childComponents', new Map()); + }.on('init'), + validateChildComponents(){ + var isChildComponentsValid = true; + this.get('childComponents').forEach((context)=>{ + if(context.get('validations') && context.get('validations.isInvalid')){ + isChildComponentsValid = false; + context.set('showErrorMessage', true); + } + }.bind(this)); + return isChildComponentsValid; + }, + actions : { + registerChild(key, context){ + this.get('childComponents').set(key, context); + }, + deregisterChild(key){ + this.get('childComponents').delete(key); + }, + onInstanceTypeChange(isList) { + this.set('data.isList', isList); + }, + add(){ + var isChildComponentsValid = this.validateChildComponents(); + if(this.get('validations.isInvalid') || !isChildComponentsValid) { + this.set('showErrorMessage', true); + return; + } + this.sendAction('add'); + }, + update(){ + var isChildComponentsValid = this.validateChildComponents(); + if(this.get('validations.isInvalid') || !isChildComponentsValid) { + this.set('showErrorMessage', true); + return; + } + this.sendAction('update'); + }, + cancel(){ + this.sendAction('cancel'); + } + } +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/components/data-input.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/data-input.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/data-input.js new file mode 100644 index 0000000..c484968 --- /dev/null +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/data-input.js @@ -0,0 +1,41 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You 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. +*/ +import Ember from 'ember'; +import { validator, buildValidations } from 'ember-cp-validations'; + +const Validations = buildValidations({ + 'dataInput.dataset': validator('presence', { + presence : true + }) +}); + +export default Ember.Component.extend(Validations, { + initialize : function(){ + this.sendAction('register', this, this); + }.on('init'), + onDestroy : function(){ + this.sendAction('deregister', this); + }.on('willDestroyElement'), + actions : { + showAdvanced(){ + this.set('showAdvanced', true); + }, + hideAdvanced(){ + this.set('showAdvanced', false); + } + } +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/components/dataset-config.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/dataset-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/dataset-config.js new file mode 100644 index 0000000..d5253ab --- /dev/null +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/dataset-config.js @@ -0,0 +1,103 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You 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. +*/ +import Ember from 'ember'; +import { validator, buildValidations } from 'ember-cp-validations'; +import Constants from '../utils/constants'; + +const Validations = buildValidations({ + 'dataset.name': validator('presence', { + presence : true + }), + 'dataset.frequency.value': validator('presence', { + presence : true + }), + 'dataset.frequency.type': validator('presence', { + presence : true + }), + 'dataset.timezone': validator('presence', { + presence : true + }), + 'dataset.uriTemplate': validator('presence', { + presence : true + }) +}); + +export default Ember.Component.extend(Validations, { + childComponents : new Map(), + initialize : function(){ + if(!this.get('dataset.initialInstance')){ + this.set('dataset.initialInstance', { + type : 'date', + value : '' + }); + } + if(!this.get('dataset.timezone')){ + this.set('dataset.timezone','UTC'); + } + if(!this.get('dataset.frequency')){ + this.set('dataset.frequency',{ type : undefined, value : undefined }); + } + this.set('timeUnitOptions',Ember.A([])); + this.get('timeUnitOptions').pushObject({value:'',displayName:'Select'}); + this.get('timeUnitOptions').pushObject({value:'months',displayName:'Months'}); + this.get('timeUnitOptions').pushObject({value:'endOfMonths',displayName:'End of Months'}); + this.get('timeUnitOptions').pushObject({value:'days',displayName:'Days'}); + this.get('timeUnitOptions').pushObject({value:'endOfDays',displayName:'End of Days'}); + this.get('timeUnitOptions').pushObject({value:'hours',displayName:'Hours'}); + this.get('timeUnitOptions').pushObject({value:'minutes',displayName:'Minutes'}); + this.get('timeUnitOptions').pushObject({value:'cron',displayName:'Cron'}); + this.set('childComponents', new Map()); + this.set('timezoneList', Ember.copy(Constants.timezoneList)); + }.on('init'), + validateChildComponents(){ + var isChildComponentsValid = true; + this.get('childComponents').forEach((context)=>{ + if(context.get('validations') && context.get('validations.isInvalid')){ + isChildComponentsValid = false; + context.set('showErrorMessage', true); + } + }.bind(this)); + return isChildComponentsValid; + }, + actions : { + registerChild(key, context){ + this.get('childComponents').set(key, context); + }, + deregisterChild(key){ + this.get('childComponents').delete(key); + }, + addDataset(){ + var isChildComponentsValid = this.validateChildComponents(); + if(this.get('validations.isInvalid') || !isChildComponentsValid) { + this.set('showErrorMessage', true); + return; + } + this.sendAction('add'); + }, + updateDataset(){ + var isChildComponentsValid = this.validateChildComponents(); + if(this.get('validations.isInvalid') || !isChildComponentsValid) { + this.set('showErrorMessage', true); + return; + } + this.sendAction('update'); + }, + cancelDatasetOperation(){ + this.sendAction('cancel'); + } + } +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/components/date-with-expr.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/date-with-expr.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/date-with-expr.js new file mode 100644 index 0000000..dd9a9ae --- /dev/null +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/date-with-expr.js @@ -0,0 +1,78 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You 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. +*/ +import Ember from 'ember'; +import { validator, buildValidations } from 'ember-cp-validations'; +const Validations = buildValidations({ + 'dateField.displayValue': { + validators: [ + validator('presence', true), + validator('date', { + format: 'MM/DD/YYYY hh:mm A', + disabled(model, attribute) { + return model.get('dateField.type') === 'expr'; + } + }) + ] + }, +}); +export default Ember.Component.extend(Validations, { + initialize : function(){ + this.sendAction('register', this, this); + }.on('init'), + elementsInserted : function(){ + if(this.get('dateField.type') === 'date'){ + this.$('input[name="'+this.get('inputName')+'"]').datetimepicker({ + format: 'MM/DD/YYYY hh:mm A', + useCurrent: false, + showClose : true + }); + } + Ember.addObserver(this, 'dateField.type', this, this.typeObserver); + Ember.addObserver(this, 'dateField.displayValue', this, this.timeObserver); + }.on('didInsertElement'), + onDestroy : function(){ + this.sendAction('deregister', this); + Ember.removeObserver(this, 'dateField.type', this, this.typeObserver); + Ember.removeObserver(this, 'dateField.displayValue', this, this.timeObserver); + }.on('willDestroyElement'), + typeObserver : function(){ + if(this.get('dateField.type') === 'date'){ + this.$('input[name="'+this.get('inputName')+'"]').datetimepicker({ + useCurrent: false, + showClose : true + }); + this.set('dateField.displayValue', undefined); + }else{ + var dateTimePicker = this.$('input[name="'+this.get('inputName')+'"]').data("DateTimePicker"); + if(dateTimePicker){ + dateTimePicker.destroy(); + } + } + }, + timeObserver : function(){ + if(this.get('dateField.type') === 'date'){ + var date = new Date(this.get('dateField.displayValue')); + if(isNaN(date.getTime())){ + this.set('dateField.value', undefined); + return; + } + this.set('dateField.value', moment(date).format("YYYY-MM-DDTHH:mm")+'Z'); + }else{ + this.set('dateField.value', Ember.copy(this.get('dateField.displayValue'))); + } + } +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/components/decision-add-branch.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/decision-add-branch.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/decision-add-branch.js index 84d1393..e4b2224 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/components/decision-add-branch.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/decision-add-branch.js @@ -17,9 +17,27 @@ import Ember from 'ember'; import {FindNodeMixin} from '../domain/findnode-mixin'; -import EmberValidations from 'ember-validations'; +import { validator, buildValidations } from 'ember-cp-validations'; -export default Ember.Component.extend(EmberValidations, FindNodeMixin,{ +const Validations = buildValidations({ + 'condition': validator('presence', { + presence : true, + disabled(model) { + return !model.get('canValidate'); + }, + 'message' : 'Required', + dependentKeys : ['canValidate'] + }), + 'targetNode': validator('presence', { + presence : true, + disabled(model) { + return !model.get('canValidate'); + }, + 'message' : 'Required', + dependentKeys : ['canValidate'] + }), +}); +export default Ember.Component.extend(Validations, FindNodeMixin,{ isInsertAction: false, condition:"", targetNode:"", @@ -27,13 +45,22 @@ export default Ember.Component.extend(EmberValidations, FindNodeMixin,{ initialize : function(){ var self=this; - this.on("showBranchOptions",function(){ + this.on("showBranchOptions",function(node){ if (self.$("#selector-content").is(":visible")){ self.$("#selector-content").hide(); }else{ + if (node) { + self.set("node", node); + } self.set("isInsertAction",false); this.set("newNodeType",null); - this.set('descendantNodes',this.getDesendantNodes(this.get('node'))); + var commonTarget=this.findCommonTargetNode(this.workflow.startNode,this.get('node')); + var descendantNodes=this.getDesendantNodes(this.get('node')); + if (commonTarget){ + descendantNodes.removeObject(commonTarget); + descendantNodes.unshiftObject(commonTarget); + } + this.set('descendantNodes',descendantNodes); self.$("#selector-content").show(); } }); @@ -41,20 +68,6 @@ export default Ember.Component.extend(EmberValidations, FindNodeMixin,{ setup : function(){ this.sendAction('registerAddBranchAction',this); }.on('didInsertElement'), - validations : { - 'condition': { - presence: { - 'if' : 'canValidate', - 'message' : 'Required', - } - }, - 'targetNode': { - presence: { - 'if' : 'canValidate', - 'message' : 'Required', - } - } - }, actions:{ addNewNode(type){ this.set("newNodeType",type); @@ -65,20 +78,21 @@ export default Ember.Component.extend(EmberValidations, FindNodeMixin,{ }, save(){ this.set('canValidate', true); - this.validate().then(function(){ - this.sendAction("addDecisionBranch",{ - sourceNode: this.get("node"), - condition:this.get("condition"), - targetNode:this.get("targetNode"), - newNodeType:this.get("newNodeType") - }); - this.$("#selector-content").hide(); - this.set('canValidate', false); - this.set('condition',""); - this.set('targetNode',""); - this.$('#target-node-select').prop('selectedIndex', 0); - }.bind(this)).catch(function(e){ - }.bind(this)); + if(this.get('validations.isInvalid')){ + this.set('showErrorMessage', true); + return; + } + this.sendAction("addDecisionBranch",{ + sourceNode: this.get("node"), + condition:this.get("condition"), + targetNode:this.get("targetNode"), + newNodeType:this.get("newNodeType") + }); + this.$("#selector-content").hide(); + this.set('canValidate', false); + this.set('condition',""); + this.set('targetNode',""); + this.$('#target-node-select').prop('selectedIndex', 0); }, cancel(){ this.$("#selector-content").hide(); http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/components/decision-config.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/decision-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/decision-config.js index 324be66..ad664d7 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/components/decision-config.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/decision-config.js @@ -16,35 +16,20 @@ */ import Ember from 'ember'; -import EmberValidations,{ validator } from 'ember-validations'; +import { validator, buildValidations } from 'ember-cp-validations'; -export default Ember.Component.extend(EmberValidations,{ +const Validations = buildValidations({ + 'actionModel': { + validators: [ + validator('decission-node-validator', { + dependentKeys: ['[email protected]'] + }) + ] + } +}); + +export default Ember.Component.extend(Validations,{ initialize : function(){ this.sendAction('register','decision',this); - }.on('init'), - validations: { - 'actionModel': { - inline : validator(function() { - var hasDefaultCond = false; - this.get('actionModel').forEach(function(item, index){ - if(item.condition === "default"){ - hasDefaultCond = true; - return; - } - }); - if(!hasDefaultCond){ - return "Decision Should have one default condition"; - } - var hasEmptyCond = false; - this.get('actionModel').forEach(function(item, index){ - if(item.condition === '' || item.condition === undefined || Ember.$.trim(item.condition).length === 0){ - hasEmptyCond = true; - return; - } - }); - if(hasEmptyCond){ - return "Condition cannot be blank"; - } - })} - } - }); + }.on('init') +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/components/designer-workspace.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/designer-workspace.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/designer-workspace.js new file mode 100644 index 0000000..a3d64b0 --- /dev/null +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/designer-workspace.js @@ -0,0 +1,158 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You 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. +*/ +import Ember from 'ember'; + +export default Ember.Component.extend({ + workspaceManager : Ember.inject.service('workspace-manager'), + xmlAppPath : null, + appPath : null, + type : 'wf', + tabId: 0, + hasMultitabSupport : true, + tabCounter : new Map(), + tabs : Ember.A([]), + currentIndex : Ember.computed('tabs.[]', function() { + return this.get('tabs').length > 0 ? this.get('tabs').length - 1 : 0; + }), + tabsObserver : Ember.observer('tabs.[]', function(){ + this.get('workspaceManager').saveTabs(this.get('tabs')); + }), + initialize : function(){ + this.get('tabCounter').set('wf', 0); + this.get('tabCounter').set('coord', 0); + this.get('tabCounter').set('bundle', 0); + var tabs = this.get('workspaceManager').restoreTabs(); + if(tabs){ + this.set('tabs', tabs); + } + this.get('tabs').forEach((tab)=>{ + this.get('tabCounter').set(tab.type, (this.get('tabCounter').get(tab.type)) + 1); + }, this); + }.on('init'), + elementsInserted : function(){ + this.$('.nav-tabs a[data-toggle="tab"]').on('shown.bs.tab', function (e) { + this.get('workspaceManager').setLastActiveTab((this.$(e.target).attr('href').slice(1))); + }.bind(this)); + + if(this.get('tabs') && this.get('tabs').length > 0){ + var lastActiveTabId = this.get('workspaceManager').getLastActiveTab(); + var activeTab = this.get('tabs').findBy('id', lastActiveTabId); + if(!activeTab){ + activeTab = this.get('tabs').objectAt(this.get('tabs').length - 1); + } + this.$('.nav-tabs a[href="#' + activeTab.id + '"]').tab('show'); + }else{ + if(this.get('hasMultitabSupport')){ + this.createNewTab(this.get('type'), this.get('xmlAppPath')); + }else{ + var tab = this.get('tabs').findBy('type', this.get('type')); + if(!tab){ + this.createNewTab(this.get('type'), this.get('xmlAppPath')); + }else{ + Ember.set(tab,'path', this.get('xmlAppPath')); + this.$('.nav-tabs a[href="#' + tab.id + '"]').tab('show'); + } + } + } + }.on('didInsertElement'), + onDestroy : function(){ + this.get('tabs').clear(); + }.on('willDestroyElement'), + createNewTab : function(type, path){ + var tab = { + type : type, + id : this.generateTabId(), + name : this.getDisplayName(type)+this.getTabId(type) + }; + if(path){ + tab.path = path; + } + this.$('.nav-tabs li').removeClass('active'); + this.$('.tab-content .tab-pane').removeClass('active'); + this.get('tabs').pushObject(tab); + this.set('isNew', true); + }, + getDisplayName(type){ + if(type === 'wf'){ + return "Workflow"; + }else if(type === 'coord'){ + return "Coordinator"; + }else{ + return "Bundle"; + } + }, + getTabId(type){ + var count = this.get('tabCounter').get(type); + this.get('tabCounter').set(type, ++count); + return count; + }, + generateTabId(){ + return 'tab-'+ Math.ceil(Math.random() * 100000); + }, + actions : { + register(tabInfo, context){ + var tab = this.get('tabs').findBy('id', tabInfo.id); + Ember.set(tab, 'context', context); + }, + show(type){ + if(this.get('hasMultitabSupport')){ + this.createNewTab(type); + }else{ + var tab = this.get('tabs').findBy('type', type); + if(!tab){ + this.createNewTab(type); + }else{ + this.$('.nav-tabs a[href="#' + tab.id + '"]').tab('show'); + } + } + }, + closeTab(index){ + if(index < this.get('tabs').length - 1){ + var previousTab = this.get('tabs').objectAt(index + 1); + this.$('.nav-tabs a[href="#'+ previousTab.id + '"]').tab('show'); + } + this.get('workspaceManager').deleteWorkInProgress(this.get('tabs').objectAt(index).id); + this.get('tabs').removeAt(index); + }, + openTab(type, path){ + if(this.get('hasMultitabSupport')){ + this.createNewTab(type, path); + }else{ + var tab = this.get('tabs').findBy('type', type); + if(!tab){ + this.createNewTab(type, path); + }else{ + Ember.set(tab,'path', path); + this.$('.nav-tabs a[href="#' + tab.id + '"]').tab('show'); + } + } + }, + changeTabName(tabInfo, name){ + var tab = this.get('tabs').findBy('id', tabInfo.id); + Ember.set(tab, 'name', name); + }, + changeFilePath(tabInfo, path){ + var tab = this.get('tabs').findBy('id', tabInfo.id); + Ember.set(tab, 'filePath', path); + }, + interceptShow(tab){ + if(tab.type === 'wf' && tab.context){ + tab.context.resize(); + } + } + } +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/components/distcp-action-info.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/distcp-action-info.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/distcp-action-info.js new file mode 100644 index 0000000..73cabac --- /dev/null +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/distcp-action-info.js @@ -0,0 +1,26 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You 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. +*/ + +import Ember from 'ember'; +export default Ember.Component.extend({ + actions : { + hideNotification(){ + this.sendAction("hideNotification"); + } + } +}); + \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/components/distcp-action.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/distcp-action.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/distcp-action.js index 1fbe4c9..e5740e3 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/components/distcp-action.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/distcp-action.js @@ -16,9 +16,8 @@ */ import Ember from 'ember'; -import EmberValidations from 'ember-validations'; -export default Ember.Component.extend(EmberValidations, { +export default Ember.Component.extend({ fileBrowser : Ember.inject.service('file-browser'), setUp : function(){ if(this.get('actionModel.args') === undefined){ @@ -44,9 +43,6 @@ export default Ember.Component.extend(EmberValidations, { this.$('#collapseOne').collapse('show'); } }.on('didUpdate'), - validations : { - - }, actions : { openFileBrowser(model, context){ if(undefined === context){ http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/components/email-action-info.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/email-action-info.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/email-action-info.js new file mode 100644 index 0000000..73cabac --- /dev/null +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/email-action-info.js @@ -0,0 +1,26 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You 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. +*/ + +import Ember from 'ember'; +export default Ember.Component.extend({ + actions : { + hideNotification(){ + this.sendAction("hideNotification"); + } + } +}); + \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/components/email-action.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/email-action.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/email-action.js index 357fe90..e8277f9 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/components/email-action.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/email-action.js @@ -16,9 +16,21 @@ */ import Ember from 'ember'; -import EmberValidations from 'ember-validations'; +import { validator, buildValidations } from 'ember-cp-validations'; -export default Ember.Component.extend(EmberValidations, { +const Validations = buildValidations({ + 'actionModel.to': validator('presence', { + presence : true + }), + 'actionModel.subject': validator('presence', { + presence : true + }), + 'actionModel.body': validator('presence', { + presence : true + }) +}); + +export default Ember.Component.extend(Validations, { fileBrowser : Ember.inject.service('file-browser'), setUp : function(){ @@ -34,23 +46,6 @@ export default Ember.Component.extend(EmberValidations, { this.$('#collapseOne').collapse('show'); } }.on('didUpdate'), - validations : { - 'actionModel.to': { - presence: { - 'message' : 'You need to provide a value for Email To', - } - }, - 'actionModel.subject': { - presence: { - 'message' : 'You need to provide a value for subject', - } - }, - 'actionModel.body': { - presence: { - 'message' : 'You need to provide a value for body', - } - } - }, actions : { openFileBrowser(model, context){ if(undefined === context){ http://git-wip-us.apache.org/repos/asf/ambari/blob/d1b0bb9e/contrib/views/wfmanager/src/main/resources/ui/app/components/file-config.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/file-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/file-config.js index 46d30d1..c0fba4a 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/components/file-config.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/file-config.js @@ -16,9 +16,8 @@ */ import Ember from 'ember'; -import EmberValidations from 'ember-validations'; -export default Ember.Component.extend(EmberValidations,{ +export default Ember.Component.extend({ multivalued: true, fileBrowser : Ember.inject.service('file-browser'), initialize : function(){
