You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by nc...@apache.org on 2016/10/28 17:45:51 UTC
[12/38] ambari git commit: AMBARI-18691. Improve and Update Workflow
designer to support coordinators and bundles. (Belliraj HB via dipayanb)
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: ['actionModel.@each.condition']
+ })
+ ]
+ }
+});
+
+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(){