You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by db...@apache.org on 2016/10/27 19:04:14 UTC

[01/10] ambari git commit: AMBARI-18691. Improve and Update Workflow designer to support coordinators and bundles. (Belliraj HB via dipayanb)

Repository: ambari
Updated Branches:
  refs/heads/branch-2.5 7306e0b2f -> 7c7412ed4


http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/fs-action-info-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/fs-action-info-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/fs-action-info-test.js
new file mode 100644
index 0000000..73ccced
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/fs-action-info-test.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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('fs-action-info', 'Integration | Component | fs action info', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{fs-action-info}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#fs-action-info}}
+      template block text
+    {{/fs-action-info}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/fsaction-info-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/fsaction-info-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/fsaction-info-test.js
new file mode 100644
index 0000000..2526fcf
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/fsaction-info-test.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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('fsaction-info', 'Integration | Component | fsaction info', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{fsaction-info}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#fsaction-info}}
+      template block text
+    {{/fsaction-info}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/hive-action-info-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/hive-action-info-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/hive-action-info-test.js
new file mode 100644
index 0000000..849408a
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/hive-action-info-test.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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('hive-action-info', 'Integration | Component | hive action info', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{hive-action-info}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#hive-action-info}}
+      template block text
+    {{/hive-action-info}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/hive2-action-info-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/hive2-action-info-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/hive2-action-info-test.js
new file mode 100644
index 0000000..d21436d
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/hive2-action-info-test.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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('hive2-action-info', 'Integration | Component | hive2 action info', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{hive2-action-info}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#hive2-action-info}}
+      template block text
+    {{/hive2-action-info}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/info-header-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/info-header-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/info-header-test.js
new file mode 100644
index 0000000..b91efc8
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/info-header-test.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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('info-header', 'Integration | Component | info header', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{info-header}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#info-header}}
+      template block text
+    {{/info-header}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/instance-list-config-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/instance-list-config-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/instance-list-config-test.js
new file mode 100644
index 0000000..785b796
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/instance-list-config-test.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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('instance-list-config', 'Integration | Component | instance list config', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{instance-list-config}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#instance-list-config}}
+      template block text
+    {{/instance-list-config}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/java-action-info-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/java-action-info-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/java-action-info-test.js
new file mode 100644
index 0000000..9109977
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/java-action-info-test.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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('java-action-info', 'Integration | Component | java action info', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{java-action-info}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#java-action-info}}
+      template block text
+    {{/java-action-info}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/job-config-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/job-config-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/job-config-test.js
new file mode 100644
index 0000000..052557d
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/job-config-test.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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('job-config', 'Integration | Component | job config', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{job-config}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#job-config}}
+      template block text
+    {{/job-config}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/killnode-config-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/killnode-config-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/killnode-config-test.js
new file mode 100644
index 0000000..5c55922
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/killnode-config-test.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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('killnode-config', 'Integration | Component | killnode config', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{killnode-config}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#killnode-config}}
+      template block text
+    {{/killnode-config}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/killnode-manager-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/killnode-manager-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/killnode-manager-test.js
new file mode 100644
index 0000000..2691d60
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/killnode-manager-test.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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('killnode-manager', 'Integration | Component | killnode manager', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{killnode-manager}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#killnode-manager}}
+      template block text
+    {{/killnode-manager}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/map-reduce-action-info-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/map-reduce-action-info-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/map-reduce-action-info-test.js
new file mode 100644
index 0000000..37b44b4
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/map-reduce-action-info-test.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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('map-reduce-action-info', 'Integration | Component | map reduce action info', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{map-reduce-action-info}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#map-reduce-action-info}}
+      template block text
+    {{/map-reduce-action-info}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/name-value-info-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/name-value-info-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/name-value-info-test.js
new file mode 100644
index 0000000..faf4987
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/name-value-info-test.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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('name-value-info', 'Integration | Component | name value info', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{name-value-info}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#name-value-info}}
+      template block text
+    {{/name-value-info}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/pig-action-info-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/pig-action-info-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/pig-action-info-test.js
new file mode 100644
index 0000000..60056de
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/pig-action-info-test.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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('pig-action-info', 'Integration | Component | pig action info', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{pig-action-info}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#pig-action-info}}
+      template block text
+    {{/pig-action-info}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/prepare-config-info-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/prepare-config-info-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/prepare-config-info-test.js
new file mode 100644
index 0000000..abf9610
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/prepare-config-info-test.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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('prepare-config-info', 'Integration | Component | prepare config info', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{prepare-config-info}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#prepare-config-info}}
+      template block text
+    {{/prepare-config-info}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/preview-dialog-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/preview-dialog-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/preview-dialog-test.js
new file mode 100644
index 0000000..e1d3775
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/preview-dialog-test.js
@@ -0,0 +1,40 @@
+/*
+*    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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('preview-dialog', 'Integration | Component | preview dialog', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{preview-dialog}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#preview-dialog}}
+      template block text
+    {{/preview-dialog}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/property-value-config-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/property-value-config-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/property-value-config-test.js
new file mode 100644
index 0000000..55b5cb9
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/property-value-config-test.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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('property-value-config', 'Integration | Component | property value config', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{property-value-config}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#property-value-config}}
+      template block text
+    {{/property-value-config}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/save-wf-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/save-wf-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/save-wf-test.js
new file mode 100644
index 0000000..4555056
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/save-wf-test.js
@@ -0,0 +1,40 @@
+/*
+ *    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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('save-wf', 'Integration | Component | save wf', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{save-wf}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#save-wf}}
+      template block text
+    {{/save-wf}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/shell-action-info-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/shell-action-info-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/shell-action-info-test.js
new file mode 100644
index 0000000..43958c4
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/shell-action-info-test.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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('shell-action-info', 'Integration | Component | shell action info', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{shell-action-info}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#shell-action-info}}
+      template block text
+    {{/shell-action-info}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/spark-action-info-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/spark-action-info-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/spark-action-info-test.js
new file mode 100644
index 0000000..e5b8995
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/spark-action-info-test.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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('spark-action-info', 'Integration | Component | spark action info', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{spark-action-info}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#spark-action-info}}
+      template block text
+    {{/spark-action-info}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/sqoop-action-info-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/sqoop-action-info-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/sqoop-action-info-test.js
new file mode 100644
index 0000000..e4f0994
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/sqoop-action-info-test.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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('sqoop-action-info', 'Integration | Component | sqoop action info', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{sqoop-action-info}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#sqoop-action-info}}
+      template block text
+    {{/sqoop-action-info}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/ssh-action-info-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/ssh-action-info-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/ssh-action-info-test.js
new file mode 100644
index 0000000..c9dcb00
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/ssh-action-info-test.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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('ssh-action-info', 'Integration | Component | ssh action info', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{ssh-action-info}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#ssh-action-info}}
+      template block text
+    {{/ssh-action-info}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/sub-workflow-action-info-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/sub-workflow-action-info-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/sub-workflow-action-info-test.js
new file mode 100644
index 0000000..576aaf8
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/sub-workflow-action-info-test.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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('sub-workflow-action-info', 'Integration | Component | sub workflow action info', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{sub-workflow-action-info}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#sub-workflow-action-info}}
+      template block text
+    {{/sub-workflow-action-info}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/unit/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/unit/.gitkeep b/contrib/views/wfmanager/src/main/resources/ui/tests/unit/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/unit/services/workflow-clipboard-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/unit/services/workflow-clipboard-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/unit/services/workflow-clipboard-test.js
new file mode 100644
index 0000000..2420a2a
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/unit/services/workflow-clipboard-test.js
@@ -0,0 +1,29 @@
+/*
+*    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 { moduleFor, test } from 'ember-qunit';
+
+moduleFor('service:workflow-clipboard', 'Unit | Service | workflow clipboard', {
+  // Specify the other units that are required for this test.
+  // needs: ['service:foo']
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+  let service = this.subject();
+  assert.ok(service);
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/unit/services/workspace-manager-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/unit/services/workspace-manager-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/unit/services/workspace-manager-test.js
new file mode 100644
index 0000000..e3083bb
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/unit/services/workspace-manager-test.js
@@ -0,0 +1,29 @@
+/*
+*    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 { moduleFor, test } from 'ember-qunit';
+
+moduleFor('service:workspace-manager', 'Unit | Service | workspace manager', {
+  // Specify the other units that are required for this test.
+  // needs: ['service:foo']
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+  let service = this.subject();
+  assert.ok(service);
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/decission-node-validator-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/decission-node-validator-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/decission-node-validator-test.js
new file mode 100644
index 0000000..3a9c059
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/decission-node-validator-test.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 { moduleFor, test } from 'ember-qunit';
+
+moduleFor('validator:decission-node-validator', 'Unit | Validator | decission-node-validator', {
+  needs: ['validator:messages']
+});
+
+test('it works', function(assert) {
+  var validator = this.subject();
+  assert.ok(validator);
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/duplicate-data-node-name-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/duplicate-data-node-name-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/duplicate-data-node-name-test.js
new file mode 100644
index 0000000..07d73b0
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/duplicate-data-node-name-test.js
@@ -0,0 +1,27 @@
+/*
+*    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 { moduleFor, test } from 'ember-qunit';
+
+moduleFor('validator:duplicate-data-node-name', 'Unit | Validator | duplicate-data-node-name', {
+  needs: ['validator:messages']
+});
+
+test('it works', function(assert) {
+  var validator = this.subject();
+  assert.ok(validator);
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/duplicate-flattened-node-name-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/duplicate-flattened-node-name-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/duplicate-flattened-node-name-test.js
new file mode 100644
index 0000000..9c40325
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/duplicate-flattened-node-name-test.js
@@ -0,0 +1,27 @@
+/*
+*    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 { moduleFor, test } from 'ember-qunit';
+
+moduleFor('validator:duplicate-flattened-node-name', 'Unit | Validator | duplicate-flattened-node-name', {
+  needs: ['validator:messages']
+});
+
+test('it works', function(assert) {
+  var validator = this.subject();
+  assert.ok(validator);
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/duplicate-kill-node-name-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/duplicate-kill-node-name-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/duplicate-kill-node-name-test.js
new file mode 100644
index 0000000..dd12d63
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/duplicate-kill-node-name-test.js
@@ -0,0 +1,27 @@
+/*
+*    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 { moduleFor, test } from 'ember-qunit';
+
+moduleFor('validator:duplicate-kill-node-name', 'Unit | Validator | duplicate-kill-node-name', {
+  needs: ['validator:messages']
+});
+
+test('it works', function(assert) {
+  var validator = this.subject();
+  assert.ok(validator);
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/fs-action-validator-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/fs-action-validator-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/fs-action-validator-test.js
new file mode 100644
index 0000000..3a441ac
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/fs-action-validator-test.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 { moduleFor, test } from 'ember-qunit';
+
+moduleFor('validator:fs-action-validator', 'Unit | Validator | fs-action-validator', {
+  needs: ['validator:messages']
+});
+
+test('it works', function(assert) {
+  var validator = this.subject();
+  assert.ok(validator);
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/job-params-validator-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/job-params-validator-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/job-params-validator-test.js
new file mode 100644
index 0000000..e757c56
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/job-params-validator-test.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 { moduleFor, test } from 'ember-qunit';
+
+moduleFor('validator:job-params-validator', 'Unit | Validator | job-params-validator', {
+  needs: ['validator:messages']
+});
+
+test('it works', function(assert) {
+  var validator = this.subject();
+  assert.ok(validator);
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/operand-length-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/operand-length-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/operand-length-test.js
new file mode 100644
index 0000000..74195f4
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/operand-length-test.js
@@ -0,0 +1,27 @@
+/*
+*    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 { moduleFor, test } from 'ember-qunit';
+
+moduleFor('validator:operand-length', 'Unit | Validator | operand-length', {
+  needs: ['validator:messages']
+});
+
+test('it works', function(assert) {
+  var validator = this.subject();
+  assert.ok(validator);
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/unique-name-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/unique-name-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/unique-name-test.js
new file mode 100644
index 0000000..96e494f
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/unit/validators/unique-name-test.js
@@ -0,0 +1,27 @@
+/*
+*    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 { moduleFor, test } from 'ember-qunit';
+
+moduleFor('validator:unique-name', 'Unit | Validator | unique-name', {
+  needs: ['validator:messages']
+});
+
+test('it works', function(assert) {
+  var validator = this.subject();
+  assert.ok(validator);
+});


[04/10] ambari git commit: AMBARI-18691. Improve and Update Workflow designer to support coordinators and bundles. (Belliraj HB via dipayanb)

Posted by db...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/dataset-config.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/dataset-config.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/dataset-config.hbs
new file mode 100644
index 0000000..e07a58c
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/dataset-config.hbs
@@ -0,0 +1,70 @@
+{{!
+* 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.
+}}
+<div class="well">
+  <div class="form-group">
+    <label for="" class="control-label col-xs-2">Name<span class="requiredField">&nbsp;*</span></label>
+    <div class="col-xs-7">
+      {{input type="text" class="form-control" name="dataset-name" value=dataset.name placeholder="Dataset Name"}}
+      {{field-error model=this field='dataset.name' showErrorMessage=showErrorMessage}}
+    </div>
+  </div>
+  <div class="form-group">
+    <label for="" class="control-label col-xs-2">URI Template<span class="requiredField">&nbsp;*</span></label>
+    <div class="col-xs-7">
+      {{input type="text" class="form-control" name="uri-template" value=dataset.uriTemplate placeholder="baseFsURI/${YEAR}/${MONTH}/${DAY}/${HOUR}/${MINUTE}"}}
+      {{field-error model=this field='dataset.uriTemplate' showErrorMessage=showErrorMessage}}
+    </div>
+  </div>
+  <div class="form-group">
+    <label class="control-label col-xs-2">Frequency<span class="requiredField">&nbsp;*</span></label>
+    <div class="col-xs-2">
+      <select class="form-control" name="frequency-type" title="Frequency type" onchange={{action (mut dataset.frequency.type) value="target.value"}}>
+        {{#each timeUnitOptions as |timeUnit|}}
+          <option value={{timeUnit.value}} selected={{eq timeUnit.value dataset.frequency.type}}>{{timeUnit.displayName}}</option>
+        {{/each}}
+      </select>
+      {{#field-error model=this field='dataset.frequency.type' showErrorMessage=showErrorMessage}}{{/field-error}}
+    </div>
+    <div class="col-xs-3">
+      {{input class="form-control" type="text" value=dataset.frequency.value placeholder="frequency" title="Periodic intervals at which datasets that are produced, and coordinator applications are scheduled to run"}}
+      {{field-error model=this field='dataset.frequency.value' showErrorMessage=showErrorMessage}}
+    </div>
+  </div>
+  {{#date-with-expr required=true inputName="initialInstance" label="Initial Instance" inputPlaceholder="Initial Instance" dateField=dataset.initialInstance register="registerChild" deregister="deregisterChild"}}{{/date-with-expr}}
+  <div class="form-group">
+    <label for="" class="control-label col-xs-2">Time Zone<span class="requiredField">&nbsp;*</span></label>
+    <div class="col-xs-7">
+      <select onchange={{action (mut dataset.timezone) value="target.value"}} name="select-input" class="form-control" data-show-icon="true">
+        {{#each timezoneList as |timezone index|}}
+        <option value={{timezone.value}} selected={{eq timezone.value dataset.timezone}}>{{timezone.displayName}}</option>
+        {{/each}}
+      </select>
+      {{field-error  model=this field='dataset.timezone' showErrorMessage=showErrorMessage}}
+    </div>
+  </div>
+  <div class="form-group">
+    <div class="col-xs-7 pull-right">
+      <button id="dataset-add-btn" {{action 'cancelDatasetOperation'}} type="button" class="btn btn-default">Cancel</button>
+      {{#if createMode}}
+      <button id="dataset-add-btn" {{action 'addDataset'}} type="button" class="btn btn-primary">Save</button>
+      {{else}}
+      <button id="dataset-update-btn" {{action 'updateDataset'}} type="button" class="btn btn-primary"> Update </button>
+      {{/if}}
+    </div>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/date-with-expr.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/date-with-expr.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/date-with-expr.hbs
new file mode 100644
index 0000000..4c86f3d
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/date-with-expr.hbs
@@ -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.
+}}
+<div class="form-group">
+  <label for="" class="control-label col-xs-2">{{label}}
+    {{#if required}}
+      <span class="requiredField">&nbsp;*</span>
+    {{/if}}
+  </label>
+  <div class="col-xs-7">
+    <div class="input-group">
+      <div class="input-group-btn">
+        <button onclick={{action (mut dateField.type) "date"}} type="button" class="btn btn-default {{if (eq dateField.type 'date') 'btn-primary' ''}} scope-btn">
+          Date
+        </button>
+        <button onclick={{action (mut dateField.type) "expr"}} type="button" class="btn btn-default {{if (eq dateField.type 'expr') 'btn-primary' ''}} scope-btn">
+          Expression
+        </button>
+      </div>
+      {{input type="text" class="form-control" name=inputName value=dateField.displayValue placeholder=inputPlaceholder}}
+    </div>
+    {{#if required}}
+      {{field-error model=this field='dateField.displayValue' showErrorMessage=showErrorMessage}}
+    {{/if}}
+  </div>
+  {{yield}}
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/decision-add-branch.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/decision-add-branch.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/decision-add-branch.hbs
index 19447dd..5670879 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/decision-add-branch.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/decision-add-branch.hbs
@@ -31,7 +31,7 @@ type="button" data-html="true">
             <label for="inputPassword" class="control-label col-xs-4">Condition<span class="requiredField">&nbsp;*</span></label>
             <div class="col-xs-7">
               {{input type="text" class="form-control" value=condition}}
-              {{field-error error=errors.condition}}
+              {{field-error model=this field='condition' showErrorMessage=showErrorMessage}}
             </div>
           </div>
           <div class="form-group">
@@ -46,7 +46,7 @@ type="button" data-html="true">
                 <option value={{node.id}} selected={{eq node.name currentNode.errorNode.name}}>{{node.name}}</option>
                 {{/each}}
               </select>
-              {{field-error error=errors.targetNode}}
+              {{field-error model=this field='targetNode' showErrorMessage=showErrorMessage}}
             </div>
           </div>
         </form>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/decision-config.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/decision-config.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/decision-config.hbs
index 342653f..cb7ff46 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/decision-config.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/decision-config.hbs
@@ -16,7 +16,7 @@
 * limitations under the License.
 }}
 <div class="decisionNodeError">
-  {{#field-error error=errors.actionModel}}{{/field-error}}
+  {{field-error model=this field='actionModel' showErrorMessage=showErrorMessage}}
 </div>
 <table id="decision-properties-table" class="table decision-properties-table listing table-hover table-bordered" cellspacing="0">
   <thead>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/designer-workspace.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/designer-workspace.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/designer-workspace.hbs
new file mode 100644
index 0000000..b775302
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/designer-workspace.hbs
@@ -0,0 +1,106 @@
+{{!
+* 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.
+}}
+<div class="main">
+  <nav class="navbar navbar-default mb0">
+    <div class="container-fluid">
+      <div class="row">
+        <div class="col-sm-4">
+          <div class="navbar-brand">
+            <label for="">Workflow Designer</label>
+          </div>
+        </div>
+        <div class="col-sm-8">
+          <div class="text-right pull-right paddingtop7">
+            <div class="btn-group btn-group" role="group" aria-label="buttons">
+              <button id="wfs_btn" {{action 'show' 'wf'}} type="button" class="btn btn-default">
+                <i class="fa fa-sitemap marginright5"></i>
+                {{#if hasMultitabSupport}}
+                New Workflow
+                {{else}}
+                Workflow
+                {{/if}}
+              </button>
+              <button id="coords_btn" {{action 'show' 'coord'}} type="button" class="btn btn-default">
+                <i class="fa fa-history marginright5"></i>
+                {{#if hasMultitabSupport}}
+                New Coordinator
+                {{else}}
+                Coordinator
+                {{/if}}
+              </button>
+              <button id="bundles_btn" {{action 'show' 'bundle'}} type="button" class="btn btn-default">
+                <i class="fa fa-cubes marginright5"></i>
+                {{#if hasMultitabSupport}}
+                New Bundle
+                {{else}}
+                Bundle
+                {{/if}}
+              </button>
+              {{#link-to 'dashboard' class="backto-dashboard btn btn-default" title="Workflow Dashboard"}}
+                <i class="fa fa-th marginright5"></i>Dashboard
+              {{/link-to}}
+            </div>
+            {{help-icon}}
+          </div>
+        </div>
+      </div>
+    </div>
+  </nav>
+  <ul class="nav nav-tabs tab-panel-heading">
+    {{#each tabs as |tab index|}}
+      <li class="{{if (eq index currentIndex) 'active'}}" title="{{tab.filePath}}">
+        <a href="#{{tab.id}}" data-toggle="tab" {{action 'interceptShow' tab}}>
+          {{#if (eq tab.type 'wf')}}
+            <i class="fa fa-sitemap marginright5"></i>
+          {{else if (eq tab.type 'coord')}}
+            <i class="fa fa-history marginright5"></i>
+          {{else if (eq tab.type 'bundle')}}
+            <i class="fa fa-cubes marginright5"></i>
+          {{/if}}
+          {{tab.name}}
+          <span class="closeTab" {{action "closeTab" index bubbles=false }}>x</span>
+        </a>
+      </li>
+    {{/each}}
+  </ul>
+  <div class="tab-content">
+    {{#each tabs as |tab index|}}
+      <div class="tab-pane {{if (eq index currentIndex) 'active'}}" id="{{tab.id}}">
+        {{#if (eq tab.type 'wf')}}
+          {{flow-designer xmlAppPath=tab.path register="register" openTab="openTab" changeTabName="changeTabName" changeFilePath="changeFilePath" tabInfo=tab}}
+        {{else if (eq tab.type 'coord')}}
+          {{coord-config xmlAppPath=tab.path register="register" openTab="openTab" changeTabName="changeTabName" changeFilePath="changeFilePath" tabInfo=tab}}
+        {{else if (eq tab.type 'bundle')}}
+          {{bundle-config register="register" openTab="openTab" changeTabName="changeTabName" changeFilePath="changeFilePath" tabInfo=tab}}
+        {{else}}
+          {{spin-spinner lines=7 length=3 width=3 radius=3 top=-10 left=150}}
+        {{/if}}
+      </div>
+    {{/each}}
+  </div>
+</div>
+<!--
+  {{#if (eq type 'wf')}}
+    {{flow-designer xmlAppPath=appPath isNew=isNew}}
+  {{else if (eq type 'coord')}}
+    {{coord-config}}
+  {{else if (eq type 'bundle')}}
+    {{bundle-config}}
+  {{else}}
+    {{spin-spinner lines=7 length=3 width=3 radius=3 top=-10 left=150}}
+  {{/if}} -->

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/distcp-action-info.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/distcp-action-info.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/distcp-action-info.hbs
new file mode 100644
index 0000000..c7de5e4
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/distcp-action-info.hbs
@@ -0,0 +1,35 @@
+{{!
+* 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.
+}}
+<div id="notificationWidget" class="">
+    <!--a href="#" class="close " data-dismiss="alert" aria-label="close">&times;</a-->
+	<ul class="list-group">
+	  <li class="list-group-item">{{info-header  hoveredAction=hoveredAction hideNotification="hideNotification"}}</li>
+	  {{#if hoveredAction.nameNode}}<li class="list-group-item"><b>Name Node : </b><br/>{{hoveredAction.nameNode}}</li>{{/if}}
+	  {{#if hoveredAction.jobTracker}}<li class="list-group-item"><b>Resource Manager : </b><br/>{{hoveredAction.jobTracker}} </li>{{/if}}
+	  {{#if hoveredAction.javaOpts}}<li class="list-group-item"><b>Java Opts :  </b><br/>{{hoveredAction.javaOpts}}</li>{{/if}}
+	  {{#if hoveredAction.args}}<li class="list-group-item"><b>Args : </b>
+	    {{#property-value-config action=hoveredAction.args}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.prepare}}<li class="list-group-item"><b>Prepare : </b>
+	    {{#prepare-config-info action=hoveredAction}}{{/prepare-config-info}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.configuration.property}}<li class="list-group-item"><b>Configuration : </b>
+	    {{#name-value-info action=hoveredAction}}{{/name-value-info}}
+	  </li>{{/if}}
+	</ul>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/email-action-info.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/email-action-info.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/email-action-info.hbs
new file mode 100644
index 0000000..a8c5343
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/email-action-info.hbs
@@ -0,0 +1,28 @@
+{{!
+* 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.
+}}
+<div id="notificationWidget" class="">
+    <!--a href="#" class="close " data-dismiss="alert" aria-label="close">&times;</a-->
+	<ul class="list-group">
+	  <li class="list-group-item">{{info-header  hoveredAction=hoveredAction hideNotification="hideNotification"}}</li>
+	  {{#if hoveredAction.to}}<li class="list-group-item"><b>To : </b><br/>{{hoveredAction.to}}</li>{{/if}}
+	  {{#if hoveredAction.cc}}<li class="list-group-item"><b>Cc : </b><br/>{{hoveredAction.cc}} </li>{{/if}}
+	  {{#if hoveredAction.bcc}}<li class="list-group-item"><b>Bcc : </b><br/>{{hoveredAction.bcc}} </li>{{/if}}
+	  {{#if hoveredAction.subject}}<li class="list-group-item"><b>Subject : </b><br/>{{hoveredAction.subject}} </li>{{/if}}
+	  {{#if hoveredAction.body}}<li class="list-group-item"><b>Body : </b><br/>{{hoveredAction.body}} </li>{{/if}}
+	</ul>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/email-action.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/email-action.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/email-action.hbs
index b9680a1..7622eb7 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/email-action.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/email-action.hbs
@@ -22,14 +22,14 @@
       <label for="inputEmail" class="control-label col-xs-2">To<span class="requiredField">&nbsp;*</span></label>
       <div class="col-xs-7">
         {{input type="text" class="form-control" name="to" value=actionModel.to placeholder="Email to" title="list of comma seperated email id's"}}
-        {{field-error error=errors.actionModel.to}}
+        {{field-error model=this field='actionModel.to' showErrorMessage=showErrorMessage}}
       </div>
     </div>
     <div class="form-group">
       <label for="inputEmail" class="control-label col-xs-2">Cc </label>
       <div class="col-xs-7">
         {{input type="text" class="form-control" name="cc" value=actionModel.cc placeholder="Cc To" title="list of comma seperated email id's"}}
-        {{field-error error=errors.actionModel.cc}}
+        {{field-error model=this field='actionModel.cc' showErrorMessage=showErrorMessage}}
       </div>
     </div>
 
@@ -37,7 +37,7 @@
       <label for="inputEmail" class="control-label col-xs-2">Bcc </label>
       <div class="col-xs-7">
         {{input type="text" class="form-control" name="bcc" value=actionModel.bcc placeholder="Bcc To" title="list of comma seperated email id's"}}
-        {{field-error error=errors.actionModel.bcc}}
+        {{field-error model=this field='actionModel.bcc' showErrorMessage=showErrorMessage}}
       </div>
     </div>
 
@@ -45,7 +45,7 @@
       <label for="inputEmail" class="control-label col-xs-2">Subject<span class="requiredField">&nbsp;*</span></label>
       <div class="col-xs-7">
         {{input type="text" class="form-control" name="subject" value=actionModel.subject placeholder="Subject"}}
-        {{field-error error=errors.actionModel.subject}}
+        {{field-error model=this field='actionModel.subject' showErrorMessage=showErrorMessage}}
       </div>
     </div>
 
@@ -53,7 +53,7 @@
       <label for="inputEmail" class="control-label col-xs-2">Body<span class="requiredField">&nbsp;*</span></label>
       <div class="col-xs-7">
         {{textarea class="form-control" name="body" value=actionModel.body placeholder="Body"}}
-        {{field-error error=errors.actionModel.body}}
+        {{field-error model=this field='actionModel.body' showErrorMessage=showErrorMessage}}
       </div>
     </div>
   </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/field-error.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/field-error.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/field-error.hbs
index 8f4d8dc..f0282bf 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/field-error.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/field-error.hbs
@@ -16,6 +16,9 @@
 * limitations under the License.
 }}
 {{yield}}
+{{#if (or (and showErrorMessage (v-get model field 'isInvalid')) (and (v-get model field 'isInvalid')(v-get model field 'isDirty')))}}
+  <label class="control-label text-danger"> {{v-get model field 'message'}}</label>
+{{/if}}
 {{#if errorMessage}}
   <label class="control-label text-danger">{{errorMessage}}</label>
 {{/if}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/flow-designer.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/flow-designer.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/flow-designer.hbs
index 71eec96..c8f0f0e 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/flow-designer.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/flow-designer.hbs
@@ -16,87 +16,138 @@
 * limitations under the License.
 }}
 <div class="main">
-  <nav class="navbar navbar-default mb0">
-  <div class="container-fluid">
+  <nav class="navbar navbar-default mb0 borderTopNone">
+  <div class="container-fluid container-custom">
     <div class="navbar-header">
-      <div class="navbar-brand">
-        <div class="padding0">
-          Workflow Designer
+      <div class="form-inline col-xs-4 paddingtop8">
+        <div class="form-group">
+          <label for="wf_title">Name</label>
+            {{input class="form-control job-title" type="text" name="wf_title" value=workflow.name title="Workflow Name" placeholder="Workflow Name"}}
         </div>
       </div>
-      <div class="padding0">
-          {{input class="form-control" type="text" id="wf_title" value=workflow.name title="Workflow Name" placeholder="Workflow Name"}}
-      </div>
       {{#if workflowFilePath}}
         <div class="wf-path padding20" title={{workflowFilePath}}>
             Path:{{ workflowFilePath}}
         </div>
       {{/if}}
-      <div class="navbar-brand pull-right paddingtop10">
-        <div class="btn-group" role="group" aria-label="...">
-          <button type="button" class="btn btn-default"  data-toggle="modal" data-target="#ConfirmDialog" title="New Workflow" {{action "conirmCreatingNewWorkflow"}}>
-              <i class="fa fa-file"> New</i>
-          </button>
-          <button  type="button" class="btn btn-default" title="Import workflow" {{action "showFileBrowser"}}>
-              <i class="fa fa-download"> Import</i>
-          </button>
-          <button  id="import-workflow-test" type="button" class="btn btn-default hide" title="Import workflow Test" {{action "importWorkflowTest"}}>
-              <i class="fa fa-download"></i>
-          </button>
-          <button type="button" class="btn btn-primary" title="Submit workflow" {{action "submitWorkflow"}}>
-              <i class="fa fa-upload"> Submit</i>
-          </button>
-          {{#link-to 'dashboard' class="backto-dashboard" }}
-          <button type="button" class="btn btn-default" title="Workflow Dashboard">
-              <i class="fa fa-th"> Dashboard</i>
-          </button>
-          {{/link-to}}
-        </div>
+      <div class="navbar-brand pull-right paddingtop8 col-xs-18">     
+        <button  type="button" class="btn btn-default" title="Import workflow" {{action "showFileBrowser"}}>
+            <i class="fa fa-download marginright5"></i>Import
+        </button>
+        <button  id="import-workflow-test" type="button" class="btn btn-default hide" title="Import workflow Test" {{action "importWorkflowTest"}}>
+            <i class="fa fa-download"></i>
+        </button>
         <div class="btn-group">
           <div class="dropdown">
-            <button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown">Settings
+            <button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown"><i class="fa fa-refresh marginright5"></i>Reset
             <span class="caret"></span></button>
             <ul class="dropdown-menu">
               <li>
-                <a href="javascript:void(0)" title="Global Configurations" {{action "showWorkflowGlobalProps"}}>
-                    Global Configurations
-              </a>
+                <a  data-toggle="modal" data-target="#ConfirmDialog" title="Reset Workflow" {{action "conirmCreatingNewWorkflow"}}>
+                  Reset Workflow
+                </a>
               </li>
-              <li><a href="javascript:void(0)" title="Workflow Credentials Configuration" {{action "showCredentials" true}}>
-                    Workflow Credentials
-              </a></li>
-              <li><a href="javascript:void(0)" title="SLA for Workflow" {{action "showWorkflowSla" true}}>
-                    SLA for Workflow
-                  </a>
+              {{#if useCytoscape}}
+              <li>
+                <a title="Reset Layout" {{action "resetLayout"}}>
+                  Reset Layout
+                </a>
               </li>
-              <li><a href="javascript:void(0)" title="Workflow Parameters Configuration" {{action "showParameterSettings" true}}>
-                    Workflow Parameters
-              </a></li>
-              <li><a href="javascript:void(0)" title="Workflow and Action Versions" {{action "showVersionSettings" true}}>
-                    Workflow and Action Versions
-                  </a>
-                </li>
+              {{/if}}
             </ul>
           </div>
         </div>
         <div class="btn-group">
-         <button type="button" class="btn btn-default"  data-toggle="modal" data-target="#kill-node-dialog" title="Create Kill Node" {{action "showCreateKillNode" true}}>
-              <i class="fa fa-ban"></i>
+          <div class="btn-group">
+            <div class="dropdown">
+              <button class="btn btn-default dropdown-toggle borderRightRadiusNone" type="button" data-toggle="dropdown"><i class="fa fa-ban marginright5"></i>Kill Nodes
+              <span class="caret"></span></button>
+              <ul class="dropdown-menu">
+                <li>
+                  <a data-toggle="modal" title="Create Kill Node" {{action "showCreateKillNode" true}}>
+                      Create Kill Node
+                  </a>
+                  <a data-toggle="modal" title="Manage Kill Nodes" {{action "showKillNodeManager" true}}>
+                      Manage Kill Nodes
+                  </a>
+                </li>
+              </ul>
+            </div>
+          </div>
+          <div class="btn-group">
+            <div class="dropdown">
+              <button class="btn btn-default dropdown-toggle borderRadiusNone" type="button" data-toggle="dropdown"><i class="fa fa-cog marginright5"></i>Settings
+              <span class="caret"></span></button>
+              <ul class="dropdown-menu">
+                <li>
+                  <a href="javascript:void(0)" title="Global Configurations" {{action "showWorkflowGlobalProps"}}>
+                      Global Configurations
+                </a>
+                </li>
+                <li><a href="javascript:void(0)" title="Workflow Credentials Configuration" {{action "showCredentials" true}}>
+                      Workflow Credentials
+                </a></li>
+                <li><a href="javascript:void(0)" title="SLA for Workflow" {{action "showWorkflowSla" true}}>
+                      SLA for Workflow
+                    </a>
+                </li>
+                <li><a href="javascript:void(0)" title="Workflow Parameters Configuration" {{action "showingParameterSettings" true}}>
+                      Workflow Parameters
+                </a></li>
+                <li><a href="javascript:void(0)" title="Workflow and Action Versions" {{action "showVersionSettings" true}}>
+                      Workflow and Action Versions
+                    </a>
+                  </li>
+              </ul>
+            </div>
+          </div>
+          <div class="btn-group">
+            <div class="dropdown">
+              <button class="btn btn-default dropdown-toggle borderRadiusNone" type="button" data-toggle="dropdown"><i class="marginright5"></i>More
+              <span class="caret"></span></button>
+              <ul class="dropdown-menu">
+                <li>
+                  <a href="javascript:void(0)" data-toggle="modal" data-target="#previewModal"  title="Preview workflow" {{action "previewWorkflow"}}>
+                    <i class="fa fa-eye marginright5"></i>Preview xml
+                  </a>
+                </li>
+                <li>
+                  <a href="javascript:void(0)" data-toggle="modal" title="Download workflow" {{action "downloadWorkflowXml"}}>
+                    <i class="fa fa-download marginright5"></i>Download xml
+                  </a>
+                </li>
+              </ul>
+            </div>
+          </div>
+          <button type="button" class="btn btn-default" title="Submit workflow" {{action "saveWorkflow"}}>
+              <i class="fa fa-floppy-o marginright5"></i>Save
+          </button>           
+          <button type="button" class="btn btn-primary" title="Dry run workflow" {{action "dryRunWorkflow"}}>
+              <i class="fa fa-play marginright5"></i> Test Run
           </button>
-
-          <button  data-toggle="modal" data-target="#previewModal"  type="button" class="btn btn-default" title="Preview workflow" {{action "previewWorkflow"}}>
-              <i class="fa fa-eye"></i>
+          <button type="button" class="btn btn-primary" title="Submit workflow" {{action "submitWorkflow"}}>
+              <i class="fa fa-upload marginright5"></i>Submit
           </button>
         </div>
-        {{help-icon}}
       </div>
     </div>
   </div>
   </nav>
+  {{#if showNotificationPanel}}
+     {{component hoveredWidget hoveredAction=hoveredAction hideNotification="hideNotification"}}
+  {{/if}}
   <div  id="content" class="panel panel-default designer-main-panel col-xs-20">
     <div class="panel-body designer-panel designer-canvas">
       {{designer-errors errors=errors validationErrors=validationErrors}}
-
+      {{#if undoAvailable}}
+        <div id="alert"class="alert alert-warning" role="alert">
+          {{#if (eq undoType 'node')}}
+            <label>Node <i>{{deletedNode.name}}</i> deleted <span class="undo" {{action 'undoDelete'}}><u>Undo</u></span></label>
+          {{else}}
+            <label>Transition deleted <span class="undo" {{action 'undoDelete'}}><u>Undo</u></span></label>
+          {{/if}}
+        </div>
+      {{/if}}
       {{#if isWorkflowImporting}}
       <div id="loader">
           <div id="alert"class="alert alert-info alert-dismissible" role="alert">
@@ -107,38 +158,94 @@
       {{#unless isImportingSuccess}}
       <div id="loader">
           <div id="alert"class="alert alert-danger alert-dismissible" role="alert">
-          There is some problem while importing.Please try again.
+              There is some problem while importing.Please try again.
+              {{#if isStackTraceAvailable}}
+                {{#if isStackTraceVisible}}
+                  <a href="#" {{action "hideStackTrace"}}>Hide Log</a>
+                  <div id="stackTrace">{{{stackTrace}}}</div>
+                {{/if}}
+                {{#unless isStackTraceVisible}}  
+                  <a href="#" {{action "showStackTrace"}}>Show Log</a>
+                {{/unless}}
+              {{/if}}
           </div>
       </div>
       {{/unless}}
       <div id="flow-designer">
         {{#each flattenedNodes as |node|}}
         <div class="node-wrapper">
-          {{#workflow-node node=node deleteNode="deleteNode" openEditor="openEditor" addBranch="addBranch" addDecisionBranch="addDecisionBranch" onNameChange="nameChanged"}}{{/workflow-node}}
+          {{#workflow-node node=node deleteNode="deleteNode" copyNode="copyNode" openEditor="openEditor"  showNotification="showNotification"  hideNotification="hideNotification" addBranch="addBranch" addDecisionBranch="addDecisionBranch" onNameChange="nameChanged"}}{{/workflow-node}}
         </div>
         {{/each}}
-        <div id="killnodes-container">
-          {{#if workflow.killNodes.length}}
-          <div class="">
-            <label id='kill-nodes-title' class='info' for="">Kill Nodes</label>
-          </div>
-          {{/if}}
-          {{#each workflow.killNodes as |node|}}
-            {{#workflow-node positionRelative=1 node=node deleteNode="deleteNode" openEditor="openEditor" addBranch="addBranch" onNameChange="nameChanged" addNode="addNode"}}{{/workflow-node}}
+        {{#if useCytoscape}}
+        <div id="cyRenderer">
+          <div id="{{cyId}}" class="cy-panel"></div>
+          {{#each dataNodes as |dataNode|}}
+            {{#if (or (eq dataNode.data.type 'action') (eq dataNode.data.type 'decision') (eq dataNode.data.type 'fork'))}}
+              <div id="{{dataNode.data.id}}" class="">
+                {{input required pattern="([a-zA-Z_]([\-_a-zA-Z0-9])*){1,39}" name="actionName" data-toggle="tooltip" title=dataNode.name classBinding="dataNode.data.node.errors:error:editable" class="editableNode overlay_node_editor" value=dataNode.dataNodeName placeholder="Action Name"}}
+              </div>
+            {{/if}}
           {{/each}}
+          <div class="overlay-node-label">asd</div>
+          <div class="overlay-transition-content">
+            <div class="decision-condition-label">
+              <div class="decision-condition-header">Condition</div>
+              <div class="decision-condition-body"></div>
+            </div>
+            <div class="overlay-transition-actions">
+              <span class="overlay-plus-icon">
+                <i class="fa fa-plus-square"></i>
+              </span>
+              <span class="overlay-trash-transition-icon">
+                <i class="fa fa-trash-o"></i>
+              </span>
+            </div>
+          </div>
+          <div class="overlay-node-actions">
+            <span class="overlay-settings-icon" title="Action settings">
+              <i class="fa fa-cog"></i>
+            </span>
+            <span class="overlay-opentab-icon" title="Open Parent Workflow">
+              <i class="fa fa-external-link"></i>
+            </span>
+            <span class="overlay-fork-icon">
+              <i class="fa fa-code-fork"></i>
+            </span>
+            <span class="overlay-trash-icon" title="Delete Node">
+              <i class="fa fa-trash-o"></i>
+            </span>
+            <span class="overlay-cut-icon" title="Cut Node">
+              <i class="fa fa-cut"></i>
+            </span>
+            <span class="overlay-copy-icon" title="Copy Node">
+              <i class="fa fa-copy"></i>
+            </span>
+            <span class="overlay-paste-icon" title="Replace Node from Clipboard">
+              <i class="fa fa-paste"></i>
+            </span>
+          </div>
+          {{decision-add-branch node=node registerAddBranchAction="registerAddBranchAction" addDecisionBranch="addDecisionBranch" workflow=workflow}}
         </div>
+          {{#if cyOverflow.overflown}}
+            <div class="cyScrollMsg"><i class="fa fa-ellipsis-h cyScrollMsgContent" title="Use the pan tool or drag on canvas to see more" aria-hidden="true"></i></div>
+          {{/if}}
+        {{/if}}
       </div>
       <div id="workflow-actions" class="hidden">
-        {{workflow-actions element=popOverElement addNode="addNode"}}
+        {{workflow-actions element=popOverElement addNode="addNode" pasteNode="pasteNode" clipboard=clipboard}}
       </div>
     </div>
   </div>
 </div>
 {{#if showActionEditor}}
-  {{workflow-action-editor actionType=currentAction closeActionEditor="closeActionEditor" addKillNode="addKillNode" actionModel=currentNode.domain nodeType=currentNode.type currentNode=currentNode killNodes=workflow.killNodes credentials=workflow.credentials}}
+  {{workflow-action-editor actionType=currentAction closeActionEditor="closeActionEditor" setNodeTransitions="setNodeTransitions" actionModel=currentNode.domain nodeType=currentNode.type currentNode=currentNode killNodes=workflow.killNodes credentials=workflow.credentials}}
+{{/if}}
+{{#if showingSaveWorkflow}}
+  {{save-wf type='wf' closeJobConfigs="closeWorkflowSubmitConfigs" jobFilePath=workflowFilePath openFileBrowser="openFileBrowser" closeFileBrowser="closeFileBrowser" jobConfigs=workflowSubmitConfigs setFilePath="setFilePath" isDryrun=dryrun}}
 {{/if}}
 {{#if showingWorkflowConfigProps}}
-  {{workflow-config closeWorkflowSubmitConfigs="closeWorkflowSubmitConfigs" workflowFilePath=workflowFilePath openFileBrowser="openFileBrowser" closeFileBrowser="closeFileBrowser" workflowSubmitConfigs=workflowSubmitConfigs}}
+  {{job-config type='wf' closeJobConfigs="closeWorkflowSubmitConfigs" jobFilePath=workflowFilePath openFileBrowser="openFileBrowser" closeFileBrowser="closeFileBrowser" jobConfigs=workflowSubmitConfigs isDryrun=dryrun}}
 {{/if}}
 {{#if showGlobalConfig}}
   {{#global-config closeGlobalConfig="closeWorkflowGlobalProps" saveGlobalConfig="saveGlobalConfig" actionModel=globalConfig}}{{/global-config}}
@@ -147,43 +254,12 @@
   {{hdfs-browser closeFileBrowser="closeFileBrowser" selectFileCallback=selectFileCallback filePath=workflowFilePath}}
 {{/if}}
 {{#if showingPreview}}
-  <div id="previewModal" class="modal fade" role="dialog">
-    <div class="modal-dialog">
-      <div class="modal-content">
-        <div class="modal-header">
-          <button type="button" class="close" data-dismiss="modal">&times;</button>
-          <h4 class="modal-title">Workflow Xml Preview</h4>
-        </div>
-        <div class="modal-body">
-
-          <pre class="preview-xml">{{previewXml}}</pre>
-        </div>
-        <div class="modal-footer">
-          <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
-        </div>
-      </div>
-    </div>
-  </div>
+  {{#preview-dialog title="Workflow XML Preview" previewXml=previewXml}}{{/preview-dialog}}
 {{/if}}
-
 {{#if showingConfirmationNewWorkflow}}
-  <div id="ConfirmDialog" class="modal fade" role="dialog">
-    <div class="modal-dialog">
-      <div class="modal-content">
-        <div class="modal-header">
-          <button type="button" class="close" data-dismiss="modal">&times;</button>
-          <h4 class="modal-title">Confirm create new workflow</h4>
-        </div>
-        <div class="modal-body">
-        Any unsaved changes may be lost.Do you want to proceed creating new workflow?
-        </div>
-        <div class="modal-footer">
-          <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
-          <button type="button" class="btn btn-primary" {{action "createNewWorkflow"}} data-dismiss="modal">Continue</button>
-        </div>
-      </div>
-    </div>
-  </div>
+  {{#confirmation-dialog title="Confirm workflow reset"
+    confirmationMessage="Any unsaved changes may be lost. Do you want to proceed resetting the workflow ?"
+    okBtnText="Continue" cancelBtnText="Cancel" onOk="createNewWorkflow"}}{{/confirmation-dialog}}
 {{/if}}
 {{#if showCreateKillNode}}
   <div id="kill-node-dialog" class="modal fade" role="dialog">
@@ -195,18 +271,15 @@
         </div>
         <div class="modal-body">
             {{#if createKillnodeError}}
+              <div class="row">
+                <div class="form-group">
+                  <label class="text-danger control-label col-xs-8">
+                    {{createKillnodeError}}
+                  </label>
+                </div>
+              </div>
+          {{/if}}
           <div class="row">
-          <div class="form-group">
-
-              <label class="text-danger control-label col-xs-8">
-              {{createKillnodeError}}
-            </label>
-
-        </div>
-      </div>
-      {{/if}}
-          <div class="row">
-
             <div class="form-group" id="killNodeName">
               <label class="control-label col-xs-3"> Kill node name</label>
               <div class="col-xs-7">
@@ -241,5 +314,8 @@
   {{#workflow-credentials showCredentials="showCredentials" workflowCredentials=workflow.credentials}}{{/workflow-credentials}}
 {{/if}}
 {{#if showParameterSettings}}
-  {{#workflow-parameters closeWorkFlowParam="closeWorkFlowParam" saveWorkFlowParam="saveWorkFlowParam" parameters=parameters}}{{/workflow-parameters}}
+  {{#workflow-parameters type='wf' closeWorkFlowParam="closeWorkFlowParam" saveWorkFlowParam="saveWorkFlowParam" parameters=parameters}}{{/workflow-parameters}}
+{{/if}}
+{{#if showKillNodeManager}}
+  {{#killnode-manager killNodes=workflow.killNodes killNode=killNode createKillnodeError=createKillnodeError createKillNode="createKillNode" deleteNode="deleteNode" addKillNodeMode=addKillNodeMode editMode=editMode closeKillNodeManager="closeKillNodeManager"}}{{/killnode-manager}}
 {{/if}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/fs-action-info.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/fs-action-info.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/fs-action-info.hbs
new file mode 100644
index 0000000..2f06e29
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/fs-action-info.hbs
@@ -0,0 +1,33 @@
+{{!
+* 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.
+}}
+<div id="notificationWidget" class="">
+    <!--a href="#" class="close " data-dismiss="alert" aria-label="close">&times;</a-->
+	<ul class="list-group">
+	  <li class="list-group-item">{{info-header  hoveredAction=hoveredAction hideNotification="hideNotification"}}</li>
+	  {{#if hoveredAction.nameNode}}<li class="list-group-item"><b>Name Node : </b><br/>{{hoveredAction.nameNode}}</li>{{/if}}
+	  {{#if hoveredAction.fsOps}}<li class="list-group-item"><b>File Operations : </b>
+	    {{#fsaction-info action=hoveredAction}}{{/fsaction-info}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.prepare}}<li class="list-group-item"><b>Prepare : </b>
+	    {{#prepare-config-info action=hoveredAction}}{{/prepare-config-info}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.configuration.property}}<li class="list-group-item"><b>Configuration : </b>
+	    {{#name-value-info action=hoveredAction}}{{/name-value-info}}
+	  </li>{{/if}}
+	</ul>
+</div> 
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/fs-action.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/fs-action.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/fs-action.hbs
index ef86a50..97f88fa 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/fs-action.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/fs-action.hbs
@@ -18,8 +18,7 @@
 <div class="panel panel-default">
   <div class="panel-heading">General</div>
   <div class="panel-body">
-    {{#field-error error=errors.actionModel}}{{/field-error}}
-
+    {{field-error model=this field='actionModel.fsOps' showErrorMessage=showErrorMessage}}
     {{#prepare-config-fs fsOps=actionModel.fsOps openFileBrowser="openFileBrowser" register="register"}}{{/prepare-config-fs}}
     {{#jobxml-config jobXml=actionModel.jobXml openFileBrowser="openFileBrowser" register="register"}}{{/jobxml-config}}
   </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/fsaction-info.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/fsaction-info.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/fsaction-info.hbs
new file mode 100644
index 0000000..6fa97d9
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/fsaction-info.hbs
@@ -0,0 +1,39 @@
+{{!
+* 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.
+}}
+{{#each action.fsOps as |obj|}}
+	<ul class="list-unstyled">
+	  {{#if (eq obj.type "mkdir")}}
+	  <li>Type is {{obj.type}} and path is {{obj.settings.path}}</li>
+	  {{/if}}
+	  {{#if (eq obj.type "delete")}}
+	  <li>Type is {{obj.type}} and path is {{obj.settings.path}}</li>
+	  {{/if}}
+	  {{#if (eq obj.type "touchz")}}
+	  <li>Type is {{obj.type}} and path is {{obj.settings.path}}</li>
+	  {{/if}}	  
+	  {{#if (eq obj.type "move")}}
+	  <li>Type is {{obj.type}} and Source is {{obj.settings.source}} and Target is {{obj.settings.target}}</li>
+	  {{/if}}	
+	  {{#if (eq obj.type "chmod")}}
+	  <li>Type is {{obj.type}} and dirfiles is {{obj.settings.dirfiles}}, recursive is {{obj.settings.recursive}}, path is {{obj.settings.path}}, permissions are {{obj.settings.permissions}}</li>
+	  {{/if}}	
+	  {{#if (eq obj.type "chgrp")}}
+	  <li>Type is {{obj.type}} and dirfiles is {{obj.settings.dirfiles}}, recursive is {{obj.settings.recursive}}, path is {{obj.settings.path}}, group : {{obj.settings.group}}</li>
+	  {{/if}}		  	  
+	</ul>	
+{{/each}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hdfs-browser.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hdfs-browser.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hdfs-browser.hbs
index d3233b6..437640d 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hdfs-browser.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hdfs-browser.hbs
@@ -74,7 +74,7 @@
                 <label class="control-label">Selected Path</label>
               </div>
               <div class="col-xs-6">
-                {{input id="selectedPath" class="form-control" type="text" value=selectedPath}}
+                {{input name="selectedPath" class="form-control" type="text" value=selectedPath}}
               </div>
               <div class="col-xs-4">
                 <button type="button" class="btn btn-primary" {{action "selectFile"}}>Select</button>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hive-action-info.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hive-action-info.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hive-action-info.hbs
new file mode 100644
index 0000000..0e30972
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hive-action-info.hbs
@@ -0,0 +1,47 @@
+{{!
+* 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.
+}}
+<div id="notificationWidget" class="">
+    <!--a href="#" class="close " data-dismiss="alert" aria-label="close">&times;</a-->
+	<ul class="list-group">
+	  <li class="list-group-item">{{info-header  hoveredAction=hoveredAction hideNotification="hideNotification"}}</li>
+	  {{#if hoveredAction.nameNode}}<li class="list-group-item"><b>Name Node</b> : <br/>{{hoveredAction.nameNode}}</li>{{/if}}
+	  {{#if hoveredAction.jobTracker}}<li class="list-group-item"><b>Resource Manager</b> : <br/>{{hoveredAction.jobTracker}} </li>{{/if}}
+	  {{#if hoveredAction.script}}<li class="list-group-item"><b>Script</b> :  <br/>{{hoveredAction.script}}</li>{{/if}}
+	  {{#if hoveredAction.jobXml}}<li class="list-group-item"><b>Job xml</b> : 
+	    {{#property-value-config action=hoveredAction.jobXml}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.archives}}<li class="list-group-item"><b>Archives</b> : 
+	    {{#property-value-config action=hoveredAction.archives}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.files}}<li class="list-group-item"><b>Files</b> : 
+	    {{#property-value-config action=hoveredAction.files}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.params}}<li class="list-group-item"><b>Params</b> : 
+	    {{#property-value-config action=hoveredAction.params}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.args}}<li class="list-group-item"><b>Args</b> : 
+	    {{#property-value-config action=hoveredAction.args}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.prepare}}<li class="list-group-item"><b>Prepare</b> : 
+	    {{#prepare-config-info action=hoveredAction}}{{/prepare-config-info}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.configuration.property}}<li class="list-group-item"><b>Configuration</b> : 
+	    {{#name-value-info action=hoveredAction}}{{/name-value-info}}
+	  </li>{{/if}}
+	</ul>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hive-action.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hive-action.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hive-action.hbs
index dc94160..eb959c3 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hive-action.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hive-action.hbs
@@ -36,7 +36,7 @@
             <button class="btn btn-primary" type="button" {{action "openFileBrowser" "actionModel.script"}}>Browse</button>
           </span>
         </div>
-        {{#field-error error=errors.actionModel.script}}{{/field-error}}
+        {{field-error model=this field='actionModel.script' showErrorMessage=showErrorMessage}}
       </div>
     </div>
   {{else}}
@@ -46,7 +46,7 @@
       <div class="input-group">
         {{textarea class="form-control" name="query" class="query-text-area" value=actionModel.query placeholder="hive query"}}
       </div>
-      {{#field-error error=errors.actionModel.query}}{{/field-error}}
+      {{field-error model=this field='actionModel.query' showErrorMessage=showErrorMessage}}
     </div>
   </div>
   {{/if}}
@@ -96,4 +96,4 @@
       </div>
     </div>
   </div>
-  {{#sla-info slaInfo=actionModel.slaInfo register="register" slaEnabled=actionModel.slaEnabled register="register"}}{{/sla-info}}
+  {{#sla-info slaInfo=actionModel.slaInfo slaEnabled=actionModel.slaEnabled register="register"}}{{/sla-info}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hive2-action-info.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hive2-action-info.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hive2-action-info.hbs
new file mode 100644
index 0000000..5a58b5a
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hive2-action-info.hbs
@@ -0,0 +1,49 @@
+{{!
+* 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.
+}}
+<div id="notificationWidget" class="">
+    <!--a href="#" class="close " data-dismiss="alert" aria-label="close">&times;</a-->
+	<ul class="list-group">
+	  <li class="list-group-item">{{info-header  hoveredAction=hoveredAction hideNotification="hideNotification"}}</li>
+	  {{#if hoveredAction.nameNode}}<li class="list-group-item"><b>Name Node :</b> <br/>{{hoveredAction.nameNode}}</li>{{/if}}
+	  {{#if hoveredAction.jobTracker}}<li class="list-group-item"><b>Resource Manager :</b> <br/>{{hoveredAction.jobTracker}} </li>{{/if}}
+	  {{#if hoveredAction.script}}<li class="list-group-item"><b>Script : </b> <br/>{{hoveredAction.script}}</li>{{/if}}
+	  {{#if hoveredAction.jdbc-url}}<li class="list-group-item"><b>Jdbc-url :</b>  <br/>{{hoveredAction.jdbc-url}}</li>{{/if}}
+	  {{#if hoveredAction.password}}<li class="list-group-item"><b>Password :</b>  <br/>{{hoveredAction.password}}</li>{{/if}}
+	  {{#if hoveredAction.jobXml}}<li class="list-group-item"><b>Job xml : </b>
+	    {{#property-value-config action=hoveredAction.jobXml}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.archives}}<li class="list-group-item"><b>Archives : </b>
+	    {{#property-value-config action=hoveredAction.archives}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.files}}<li class="list-group-item"><b>Files : </b>
+	    {{#property-value-config action=hoveredAction.files}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.params}}<li class="list-group-item"><b>Params : </b>
+	    {{#property-value-config action=hoveredAction.params}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.args}}<li class="list-group-item"><b>Args : </b>
+	    {{#property-value-config action=hoveredAction.args}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.prepare}}<li class="list-group-item"><b>Prepare : </b>
+	    {{#prepare-config-info action=hoveredAction}}{{/prepare-config-info}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.configuration.property}}<li class="list-group-item"><b>Configuration : </b>
+	    {{#name-value-info action=hoveredAction}}{{/name-value-info}}
+	  </li>{{/if}}
+	</ul>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hive2-action.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hive2-action.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hive2-action.hbs
index c4bec81..563cca8 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hive2-action.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/hive2-action.hbs
@@ -37,7 +37,7 @@
             <button class="btn btn-primary" type="button" {{action "openFileBrowser" "actionModel.script"}}>Browse</button>
           </span>
         </div>
-        {{#field-error error=errors.actionModel.script}}{{/field-error}}
+        {{field-error model=this field='actionModel.script' showErrorMessage=showErrorMessage}}
       </div>
     </div>
     {{else}}
@@ -47,7 +47,7 @@
         <div class="input-group">
           {{textarea class="form-control" name="query" class="query-text-area" value=actionModel.query placeholder="hive query"}}
         </div>
-        {{#field-error error=errors.actionModel.query}}{{/field-error}}
+        {{field-error model=this field='actionModel.query' showErrorMessage=showErrorMessage}}
       </div>
     </div>
     {{/if}}
@@ -55,7 +55,7 @@
       <label class="control-label col-xs-2">jdbc-url<span class="requiredField">&nbsp;*</span></label>
       <div class="col-xs-7">
         {{input type="text" class="form-control" validations="required" name="jdbc-url" value=actionModel.jdbc-url placeholder="jdbc-url"}}
-        {{#field-error error=errors.actionModel.jdbc-url}}{{/field-error}}
+        {{field-error model=this field='actionModel.jdbc-url' showErrorMessage=showErrorMessage}}
       </div>
     </div>
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/info-header.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/info-header.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/info-header.hbs
new file mode 100644
index 0000000..5fdd702
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/info-header.hbs
@@ -0,0 +1,18 @@
+{{!
+* 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.
+}}
+<b>Action Details</b><a href="#" class="pull-right" {{action "hideNotification"}}>X</a>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/instance-list-config.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/instance-list-config.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/instance-list-config.hbs
new file mode 100644
index 0000000..94f4e39
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/instance-list-config.hbs
@@ -0,0 +1,35 @@
+{{!
+* 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.
+}}
+<div>
+  {{#each instances as |instance index|}}
+  <div class="form-group">
+    {{#date-with-expr required=true inputName="instance" label="Instance" inputPlaceholder="Instance" dateField=instance}}
+      <div class="col-xs-1">
+        <input class="form-control btn btn-danger" type="button" {{action "deleteInstance" index}} value="-">
+      </div>
+    {{/date-with-expr}}
+  </div>
+  {{/each}}
+  <div class="form-group">
+    {{#date-with-expr inputName="instance" label="Instance" inputPlaceholder="Instance" dateField=instance}}
+      <div class="col-xs-1">
+        <input class="form-control btn btn-success" type="button" value="+" {{action "addInstance"}}>
+      </div>
+    {{/date-with-expr}}
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/java-action-info.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/java-action-info.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/java-action-info.hbs
new file mode 100644
index 0000000..e74633d
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/java-action-info.hbs
@@ -0,0 +1,52 @@
+{{!
+* 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.
+}}
+<div id="notificationWidget" class="">
+    <!--a href="#" class="close " data-dismiss="alert" aria-label="close">&times;</a-->
+	<ul class="list-group">
+	  <li class="list-group-item">{{info-header  hoveredAction=hoveredAction hideNotification="hideNotification"}}</li>
+	  {{#if hoveredAction.nameNode}}<li class="list-group-item"><b>Name Node : </b><br/>{{hoveredAction.nameNode}}</li>{{/if}}
+	  {{#if hoveredAction.jobTracker}}<li class="list-group-item"><b>Resource Manager : </b><br/>{{hoveredAction.jobTracker}} </li>{{/if}}
+	  {{#if hoveredAction.captureOutput}}<li class="list-group-item"><b>Capture Output :  </b><br/>{{hoveredAction.captureOutput}}</li>{{/if}}
+	  {{#if hoveredAction.mainClass}}<li class="list-group-item"><b>Main Class :  </b><br/>{{hoveredAction.mainClass}}</li>{{/if}}
+	  {{#if hoveredAction.javaOpts}}<li class="list-group-item"><b>Java Opts :  </b><br/>{{hoveredAction.javaOpts}}</li>{{/if}}
+	  {{#if hoveredAction.javaOpt}}<li class="list-group-item"><b>Java Opt : </b>
+	    {{#property-value-config action=hoveredAction.javaOpt}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.jobXml}}<li class="list-group-item"><b>Job xml : </b>
+	    {{#property-value-config action=hoveredAction.jobXml}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.nameNode}}<li class="list-group-item"><b>Archives : </b>
+	    {{#property-value-config action=hoveredAction.archives}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.files}}<li class="list-group-item"><b>Files : </b>
+	    {{#property-value-config action=hoveredAction.files}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.params}}<li class="list-group-item"><b>Params : </b>
+	    {{#property-value-config action=hoveredAction.params}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.args}}<li class="list-group-item"><b>Args : </b>
+	    {{#property-value-config action=hoveredAction.args}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.prepare}}<li class="list-group-item"><b>Prepare : </b>
+	    {{#prepare-config-info action=hoveredAction}}{{/prepare-config-info}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.configuration.property}}<li class="list-group-item"><b>Configuration : </b>
+	    {{#name-value-info action=hoveredAction}}{{/name-value-info}}
+	  </li>{{/if}}
+	</ul>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/java-action.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/java-action.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/java-action.hbs
index c103bd0..bdb5261 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/java-action.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/java-action.hbs
@@ -22,7 +22,7 @@
       <label for="inputEmail" class="control-label col-xs-2">Main class<span class="requiredField">&nbsp;*</span></label>
       <div class="col-xs-7">
         {{input type="text" class="form-control" name="main-class" value=actionModel.mainClass placeholder="Main class"}}
-        {{field-error error=errors.actionModel.mainClass}}
+        {{field-error model=this field='actionModel.mainClass' showErrorMessage=showErrorMessage}}
       </div>
     </div>
 
@@ -77,7 +77,7 @@
             <div class="col-xs-7">
               {{input type="text" class="form-control" name="job-tracker" value=actionModel.jobTracker placeholder="Resource Manager"}}
             </div>
-            {{field-error error=errors.actionModel.jobTracker}}
+            {{field-error model=this field='actionModel.jobTracker' showErrorMessage=showErrorMessage}}
           </div>
           <div class="form-group">
             <label for="inputPassword" class="control-label col-xs-2">Name node</label>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/job-config.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/job-config.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/job-config.hbs
new file mode 100644
index 0000000..ede8cb1
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/job-config.hbs
@@ -0,0 +1,126 @@
+{{!
+* 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.
+}}
+<div class="modal fade" id="configureJob" role="dialog">
+  <div class="modal-dialog">
+    <div class="modal-content">
+      <div class="modal-header">
+        <button type="button" class="close" data-dismiss="modal">&times;</button>
+        {{#if isDryrun}}
+          <h4 class="modal-title">Dryrun {{displayName}}</h4>
+        {{else}}
+          <h4 class="modal-title">Submit {{displayName}}</h4>
+        {{/if}}
+
+      </div>
+      <div class="modal-body">
+        <div class="panel panel-default">
+          <div class="panel-body">
+            {{#if alertType}}
+            <div id="error" class="alert alert-{{alertType}}">
+              <div>{{alertMessage}}</div>
+              <div>{{alertDetails}}</div>
+              {{#if isStackTraceAvailable}}
+                {{#if isStackTraceVisible}}
+                  <a href="#" {{action "hideStackTrace"}}>Hide Log</a>
+                  <div id="stackTrace">{{{stackTrace}}}</div>
+                {{/if}}
+                {{#unless isStackTraceVisible}}  
+                  <a href="#" {{action "showStackTrace"}}>Show Log</a>
+                {{/unless}}
+              {{/if}}
+            </div>
+            {{/if}}
+            <div class="row form-group">
+              <div class="col-xs-3"> 
+                <label class="control-label" for="{{type}}-path">{{displayName}} path</label><span class="requiredField">&nbsp;*</span>
+              </div>
+              <div class="col-xs-8">
+                <div class="input-group">
+                  {{input class="form-control" type="text" name="{{type}}-path"  value=filePath}}
+                  <span class="input-group-btn">
+                    <button type="button" class="btn btn-primary" {{action "selectFile"}}>Browse</button>
+                  </span>
+                </div>
+                {{field-error model=this field='filePath' showErrorMessage=showErrorMessage}}
+                {{input type="checkbox" checked=overwritePath}}Overwrite
+              </div>
+            </div>
+            <div class="row">
+              <div class="col-xs-3">
+                <label class="control-label">Execution Settings</label>
+              </div>
+              <div class="col-xs-8">
+                {{#each systemConfigs as |config|}}
+                <div>
+                  {{input type="checkbox" checked=config.value}}{{config.displayName}}
+                </div>
+                {{/each}}
+              </div>
+            </div>
+          </div>
+        </div>
+        <div id="jobProperties">
+          {{#if configMap.length}}
+          <div class="panel panel-default">
+            <div class="panel-heading">
+              Job Properties
+            </div>
+            <div class="panel-body">
+              {{field-error model=this field='configMap' showErrorMessage=showErrorMessage}}
+              {{#each configMap as |prop|}}
+              <div class="row form-group">
+                <div class="col-xs-3">
+                  <label class="control-label" for="{{prop}}">{{prop.name}}</label>
+                  {{#if prop.isRequired}}
+                  <span class="requiredField">&nbsp;*</span>
+                  {{/if}}
+                </div>
+                <div class="col-xs-8">
+                  {{input class="form-control" type="text" value=prop.value}}
+                </div>
+              </div>
+              {{/each}}
+            </div>
+          </div>
+          {{/if}}
+        </div>
+      </div>
+      <div class="modal-footer">
+        {{#if savingInProgress}}
+        {{spin-spinner lines=10 length=10 width=5 radius=10 }}
+        <span class="pull-left">Saving {{displayName}}</span>
+        {{/if}}
+        {{#if startingInProgress}}
+        {{spin-spinner lines=8 length=5 width=10 radius=5}}
+        <span class="pull-left">Starting {{displayName}}</span>
+        {{/if}}
+        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+        {{#if isDryrun}}
+          <button type="button" class="btn btn-primary" {{action "dryrun"}}>Test Run</button>
+        {{else}}
+          <button type="button" class="btn btn-default" {{action "dryrun"}}>Test Run</button>
+          <button type="button" class="btn btn-primary" {{action "save"}}>Submit</button>
+        {{/if}}
+
+      </div>
+    </div>
+  </div>
+</div>
+{{#if showingFileBrowser}}
+{{hdfs-browser closeFileBrowser="closeFileBrowser" selectFileCallback=selectFileCallback filePath=filePath}}
+{{/if}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/job-details.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/job-details.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/job-details.hbs
index 872cdbb..0a04d25 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/job-details.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/job-details.hbs
@@ -49,7 +49,7 @@
             <li {{action 'getJobLog'}} role="presentation"><a href="#jobLog" aria-controls="jobLog" role="tab" data-toggle="tab">Log</a></li>
             <li {{action 'getErrorLog'}} role="presentation"><a href="#jobErrorLog" aria-controls="jobErrorLog" role="tab" data-toggle="tab">Error Log</a></li>
             <li {{action 'getAuditLog'}} role="presentation"><a href="#jobAuditLog" aria-controls="jobAuditLog" role="tab" data-toggle="tab">Audit Log</a></li>
-            <li {{action 'getJobDag'}} role="presentation"><a href="#jobDag" aria-controls="jobDag" role="tab" data-toggle="tab">DAG</a></li>
+            <li {{action 'getJobDag'}} role="presentation"><a href="#jobDag" aria-controls="jobDag" role="tab" data-toggle="tab">Flow Graph</a></li>
             <li role="presentation" class="pull-right">
                 {{#link-to 'design' (query-params appPath=model.appPath) class="backto-designer" }}
                     <button type="button" class="btn btn-success" title="Back" >

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/killnode-config.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/killnode-config.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/killnode-config.hbs
new file mode 100644
index 0000000..db24051
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/killnode-config.hbs
@@ -0,0 +1,67 @@
+{{!
+* 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.
+}}
+<div class="panel panel-default">
+  <div class="panel-heading">
+    {{#if editMode}}
+      Edit Kill Node
+    {{else}}
+      Add Kill Node
+    {{/if}}
+  </div>
+  <div class="panel-body">
+    {{#if createKillnodeError}}
+      <div class="row">
+        <div class="form-group">
+            <label class="text-danger control-label col-xs-8">
+            {{createKillnodeError}}
+          </label>
+        </div>
+      </div>
+    {{/if}}
+    <div class="row">
+      <div class="form-group" id="killNodeName">
+        <label class="control-label col-xs-3"> Kill node name</label>
+        {{#if editMode}}
+          <label class="control-label col-xs-3">{{killNode.name}}</label>
+        {{else}}
+          <div class="col-xs-7">
+            {{input class="form-control" type="text" name="kill-node-name" value=killNode.name}}
+          </div>
+        {{/if}}
+      </div>
+    </div>
+    <div class="row padding10">
+      <div class="form-group">
+        <label class="control-label col-xs-3"> Kill message</label>
+        <div class="col-xs-7">
+          {{textarea class="form-control" rows="5" placeholder="kill node message" name="kill-node-message" value=killNode.killMessage}}
+        </div>
+      </div>
+    </div>
+  </div>
+  <div class="panel-footer clearfix">
+    <div class="pull-right">
+      {{#if editMode}}
+        <button type="button" class="btn btn-primary" {{action "updateNode"}}>Save</button>
+      {{else}}
+        <button type="button" class="btn btn-primary" {{action "createKillNode"}}>Save</button>
+      {{/if}}
+      <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
+    </div>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/killnode-manager.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/killnode-manager.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/killnode-manager.hbs
new file mode 100644
index 0000000..9b14cfc
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/killnode-manager.hbs
@@ -0,0 +1,69 @@
+{{!
+* 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.
+}}
+<div id="killnode-manager-dialog" class="modal fade" role="dialog">
+  <div class="modal-dialog">
+    <div class="modal-content">
+      <div class="modal-header">
+        <button type="button" class="close" data-dismiss="modal">&times;</button>
+        <h4 class="modal-title">Kill Node Manager</h4>
+      </div>
+      <div class="modal-body">
+        <div class="panel panel-default">
+          <div class="panel-heading clearfix">
+            <h4 class="panel-title pull-left paddingtop7">Kill Nodes</h4>
+            <button type="button" class="btn btn-default pull-right" {{action "addNode"}}>Add</button>
+          </div>
+          <div class="panel-body kill-nodes-list">
+            <ul class="list-group">
+              {{#each killNodes as |killNode index|}}
+                <li class="list-group-item col-xs-12">
+                  <div class="col-xs-12 plr0px">
+                    <label class="control-label col-xs-2">
+                      Name
+                    </label>
+                    <div class="col-xs-10">
+                      {{killNode.name}}
+                      <span class="pull-right">
+                        <i class="fa fa-trash-o" title="Delete" {{action "deleteNode" index}}></i>
+                      </span>
+                      <span class="pull-right paddingright10">
+                        <i class="fa fa-pencil" title="Edit" {{action "editNode" index}}></i>
+                      </span>
+                    </div>
+                  </div>
+                  <div class="col-xs-12 plr0px">
+                    <label class="control-label col-xs-2">
+                      Message
+                    </label>
+                    <div class="col-xs-10">
+                      {{killNode.killMessage}}
+                    </div>
+                  </div>
+                </li>
+              {{/each}}
+            </ul>
+          </div>
+        </div>
+
+        {{#if (or addKillNodeMode editMode)}}
+          {{killnode-config killNode=killNode createKillnodeError=createKillnodeError editMode=editMode updateNode="updateNode" createKillNode="createKillNode"}}
+        {{/if}}
+      </div>
+    </div>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/map-reduce-action-info.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/map-reduce-action-info.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/map-reduce-action-info.hbs
new file mode 100644
index 0000000..16d1b32
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/map-reduce-action-info.hbs
@@ -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.
+}}
+<div id="notificationWidget" class="">
+    <!--a href="#" class="close " data-dismiss="alert" aria-label="close">&times;</a-->
+	<ul class="list-group">
+	  <li class="list-group-item"><b>The details are</b>
+	  <a href="#" class="pull-right" {{action "hideNotification"}}>X</a></li>
+	  {{#if hoveredAction.nameNode}}<li class="list-group-item"><b>Name Node : </b><br/>{{hoveredAction.nameNode}}</li>{{/if}}
+	  {{#if hoveredAction.jobTracker}}<li class="list-group-item"><b>Resource Manager : </b><br/>{{hoveredAction.jobTracker}} </li>{{/if}}
+	  {{#if hoveredAction.jobXml}}<li class="list-group-item"><b>Job xml : </b>
+	    {{#property-value-config action=hoveredAction.jobXml}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.archives}}<li class="list-group-item"><b>Archives : </b>
+	    {{#property-value-config action=hoveredAction.archives}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.files}}<li class="list-group-item"><b>Files : </b>
+	    {{#property-value-config action=hoveredAction.files}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.prepare}}<li class="list-group-item"><b>Prepare : </b>
+	    {{#prepare-config-info action=hoveredAction}}{{/prepare-config-info}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.configuration.property}}<li class="list-group-item"><b>Configuration : </b>
+	    {{#name-value-info action=hoveredAction}}{{/name-value-info}}
+	  </li>{{/if}}
+	</ul>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/name-value-info.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/name-value-info.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/name-value-info.hbs
new file mode 100644
index 0000000..02f2499
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/name-value-info.hbs
@@ -0,0 +1,22 @@
+{{!
+* 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.
+}}
+{{#each action.configuration.property as |obj|}}
+	<ul class="list-unstyled">
+	  <li>Name : {{obj.name}}, Value : {{obj.value}}</li>
+	</ul>	
+{{/each}}


[08/10] ambari git commit: AMBARI-18691. Improve and Update Workflow designer to support coordinators and bundles. (Belliraj HB via dipayanb)

Posted by db...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js
index bd2944b..ed743f4 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/flow-designer.js
@@ -20,17 +20,45 @@ import {Workflow} from '../domain/workflow';
 import Constants from '../utils/constants';
 import {WorkflowGenerator} from '../domain/workflow-xml-generator';
 import {WorkflowImporter} from '../domain/workflow-importer';
+import {WorkflowJsonImporter} from '../domain/workflow-json-importer';
 import {WorkflowContext} from '../domain/workflow-context';
-import {DefaultLayoutManager as LayoutManager} from '../domain/default-layout-manager';
-import EmberValidations,{ validator } from 'ember-validations';
+import {JSPlumbRenderer} from '../domain/jsplumb-flow-renderer';
+import {CytoscapeRenderer} from '../domain/cytoscape-flow-renderer';
+import {FindNodeMixin} from '../domain/findnode-mixin';
+import { validator, buildValidations } from 'ember-cp-validations';
+import WorkflowPathUtil from '../domain/workflow-path-util';
 
+const Validations = buildValidations({
+  'dataNodes': { /* For Cytoscape */
+    validators: [
+      validator('duplicate-data-node-name', {
+        dependentKeys: ['dataNodes.@each.dataNodeName']
+      })
+    ]
+  },
+  'workflow.killNodes': {
+    validators: [
+      validator('duplicate-kill-node-name', {
+        dependentKeys: ['workflow.killNodes.@each.name']
+      })
+    ]
+  },
+  'flattenedNodes': {
+    validators: [
+      validator('duplicate-flattened-node-name', {
+        dependentKeys: ['flattenedNodes.@each.name']
+      })
+    ]
+  }
+});
 
-export default Ember.Component.extend(EmberValidations,{
+export default Ember.Component.extend(FindNodeMixin, Validations, {
   workflowContext : WorkflowContext.create({}),
   workflowTitle:"",
   previewXml:"",
   supportedActionTypes:["java", "hive", "pig", "sqoop", "shell", "spark", "map-reduce", "hive2", "sub-workflow", "distcp", "ssh", "FS"],
   workflow:null,
+  hoveredWidget:null,/**/
   showingConfirmationNewWorkflow:false,
   showingWorkflowConfigProps:false,
   workflowSubmitConfigs:{},
@@ -40,106 +68,118 @@ export default Ember.Component.extend(EmberValidations,{
   domain:{},
   showActionEditor : false,
   flattenedNodes: [],
-
+  dataNodes: [], /* For cytoscape */
+  hoveredAction: null,
   workflowImporter:WorkflowImporter.create({}),
-  designerPlumb:null,
   propertyExtractor : Ember.inject.service('property-extractor'),
+  clipboardService : Ember.inject.service('workflow-clipboard'),
+  workspaceManager : Ember.inject.service('workspace-manager'),
   showGlobalConfig : false,
   showParameterSettings : false,
+  showNotificationPanel : false,
   globalConfig : {},
   parameters : {},
   clonedDomain : {},
   clonedErrorNode : {},
   validationErrors : [],
-  layoutManager:null,
   showingFileBrowser : false,
   killNode : {},
   isWorkflowImporting: false,
   isImportingSuccess: true,
-  initialize :function(){
-    this.designerPlumb=jsPlumb.getInstance({});
-    this.layoutManager=LayoutManager.create({});
+  shouldPersist : false,
+  useCytoscape: Constants.useCytoscape,
+  cyOverflow: {},
+  clipboard : Ember.computed.alias('clipboardService.clipboard'),
+  isStackTraceVisible: false,
+  isStackTraceAvailable: false,
+  stackTrace:"",
+  initialize : function(){
+    var id = 'cy-' + Math.ceil(Math.random() * 1000);
+    this.set('cyId', id);
+    this.sendAction('register', this.get('tabInfo'), this);
+  }.on('init'),
+  elementsInserted :function(){
+    if (this.useCytoscape){
+      this.flowRenderer=CytoscapeRenderer.create({id : this.get('cyId')});
+    }else{
+      this.flowRenderer=JSPlumbRenderer.create({});
+    }
+
     this.setConentWidth();
     this.set('workflow',Workflow.create({}));
     if(this.get("xmlAppPath")){
-      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.importWorkflow(relXmlPath);
+      this.showExistingWorkflow();
       return;
-    }else{
+    } else {
       this.workflow.initialize();
       this.initAndRenderWorkflow();
       this.$('#wf_title').focus();
-      this.restoreWorkinProgress();
+      if (Constants.autoRestoreWorkflowEnabled){
+        this.restoreWorkflow();
+      }
+    }
+    if(Ember.isBlank(this.get('workflow.name'))){
+      this.set('workflow.name', Ember.copy(this.get('tabInfo.name')));
     }
-  }.on('didInsertElement'),
-  validations: {
-    'flattenedNodes': {
-      inline : validator(function() {
-        var nodeNames = new Map();
-        this.get("validationErrors").clear();
-        this.get('flattenedNodes').forEach((item)=>{
-          Ember.set(item, "errors", false);
-          if(nodeNames.get(item.name)){
-            Ember.set(item, "errors", true);
-            this.get("validationErrors").pushObject({node:item,message:"Node name should be unique"});
-          }else{
-            nodeNames.set(item.name, item);
-            Ember.set(item, "errors", false);
-          }
-          if(this.get("supportedActionTypes").indexOf(item.actionType) === -1 && item.type === "action"){
-            this.get('validationErrors').pushObject({node : item ,message : item.actionType+" is unsupported"});
-          }
-          var nodeErrors=item.validateCustom();
-          if (nodeErrors.length>0){
-            Ember.set(item, "errors", true);
-            nodeErrors.forEach(function(errMsg){
-              this.get("errors").pushObject({node:item,message:errMsg });
-            }.bind(this));
-          }
-        }.bind(this));
 
-        if(this.get('flattenedNodes').length !== nodeNames.size || this.get("errors").length>0){
-          return true;
-        }
-      })
-    },
-    "workflow.killnodes": {
-      inline : validator(function() {
-        let killNodes = [], flag;
-        if(this.get("workflow") && this.get("workflow").killNodes){
-          killNodes = this.get("workflow").killNodes;
-          for(let i=0; i<killNodes.length; i++){
-            for(let j=0; j<killNodes.length; j++){
-              if(killNodes[i].name === killNodes[j].name && i !== j){
-                this.get('validationErrors').pushObject({node : killNodes[j] ,message : "Duplicate killnode"});
-                flag = true;
-                break;
-              }
-            }
-            if(flag){
-              break;
-            }
-          }
-        }
-        if (flag){
-          return true;
+  }.on('didInsertElement'),
+  restoreWorkflow(){
+    if (!this.get("isNew")){
+      var draftWorkflow=this.getDraftWorkflow();
+      if (draftWorkflow){
+        this.resetDesigner();
+        this.set("workflow",draftWorkflow);
+        this.rerender();
+        this.doValidation();
+      }
+    }
+  },
+  observeXmlAppPath : Ember.observer('xmlAppPath', function(){
+    if(!this.get('xmlAppPath') || null === this.get('xmlAppPath')){
+      return;
+    }else{
+      this.showExistingWorkflow();
+    }
+  }),
+  observeFilePath : Ember.observer('workflowFilePath', function(){
+    if(!this.get('workflowFilePath') || null === this.get('workflowFilePath')){
+      return;
+    }else{
+      this.sendAction('changeFilePath', this.get('tabInfo'), this.get('workflowFilePath'));
+    }
+  }),
+  nameObserver : Ember.observer('workflow.name', function(){
+    if(!this.get('workflow')){
+      return;
+    }else if(this.get('workflow') && Ember.isBlank(this.get('workflow.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('workflow.name'));
+    }
+  }),
+  showParentWorkflow(type, path){
+    this.sendAction('openTab', type, path);
+  },
+  showExistingWorkflow(){
+    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.importWorkflow(relXmlPath);
   },
   setConentWidth(){
     var offset = 120;
@@ -150,197 +190,101 @@ export default Ember.Component.extend(EmberValidations,{
       return;
     });
   },
+  workflowXmlDownload(workflowXml){
+      var link = document.createElement("a");
+      link.download = "workflow.xml";
+      link.href = "data:text/xml,"+vkbeautify.xml(workflowXml);
+      link.click();
+  },
   nodeRendered: function(){
-    var self=this;
+    this.doValidation();
     if(this.get('renderNodeTransitions')){
-      var connections=[];
-      var visitedNodes=[];
-      this.renderTransitions(this.get("workflow").startNode,connections,visitedNodes);
-      this.workflowConnections=connections;
+      this.flowRenderer.onDidUpdate(this,this.get("workflow").startNode,this.get("workflow"));
       this.layout();
-      this.designerPlumb.setSuspendDrawing(true);
-      this.designerPlumb.batch(function(){
-        connections.forEach(function(conn){
-          self.designerPlumb.connect(conn);
-        });
-      });
-      this.designerPlumb.setSuspendDrawing(false,true);
       this.set('renderNodeTransitions',false);
     }
+    this.resize();
     this.persistWorkInProgress();
   }.on('didUpdate'),
-  cleanUpJsplumb:function(){
-    this.get('flattenedNodes').clear();
+  resize(){
+    this.flowRenderer.resize();
+  },
+  cleanupFlowRenderer:function(){
     this.set('renderNodeTransitions',false);
-    this.designerPlumb.detachEveryConnection();
+    this.flowRenderer.cleanup();
   }.on('willDestroyElement'),
   initAndRenderWorkflow(){
-    this.designerPlumb.ready(function() {
+    var panelOffset=this.$(".designer-panel").offset();
+    var canvasHeight=Ember.$(window).height()-panelOffset.top-25;
+    this.flowRenderer.initRenderer(function(){
       this.renderWorkflow();
-    }.bind(this));
+    }.bind(this),{context:this,flattenedNodes:this.get("flattenedNodes"),dataNodes:this.get("dataNodes"), cyOverflow:this.get("cyOverflow"),canvasHeight:canvasHeight});
   },
   renderWorkflow(){
-    this.get('flattenedNodes').clear();
     this.set('renderNodeTransitions', true);
-    var visitedNodes=[];
-    this.renderNodes(this.get("workflow").startNode,visitedNodes);
+    this.flowRenderer.renderWorkflow(this.get("workflow"));
+    this.doValidation();
   },
   rerender(){
-    this.designerPlumb.detachEveryConnection();
+    this.flowRenderer.cleanup();
     this.renderWorkflow(this.get("workflow"));
   },
   setCurrentTransition(transition){
     this.set("currentTransition",transition);
   },
-  renderNodes(node,visitedNodes){
-    if (!node || node.isKillNode()){
-      return;
-    }
-    if (visitedNodes.contains(node)){
-      return;
-    }
-    visitedNodes.push(node);
-    if(!this.get('flattenedNodes').contains(node)){
-      this.get('flattenedNodes').pushObject(node);
-    }
-    if (node.transitions.length > 0){
-      node.transitions.forEach(function(transition) {
-        var target = transition.targetNode;
-        this.renderNodes(target,visitedNodes);
-      }.bind(this));
-    }
-  },
-  createConnection(sourceNode,target,transition){
-    var connectionColor="#777";
-    var lineWidth=1;
-    if (transition.condition){
-      if(transition.condition==="default"){
-        lineWidth=2;
-      }else if (transition.condition==="error"|| transition.errorPath){
-        connectionColor=Constants.globalSetting.errorTransitionColor;
-      }
-    }
-    var connectionObj={
-      source:sourceNode.id,
-      target:target.id,
-      connector:["Straight"],
-      paintStyle:{lineWidth:lineWidth,strokeStyle:connectionColor},
-      endpointStyle:{fillStyle:'rgb(243,229,0)'},
-      endpoint: ["Dot", {
-        radius: 1
-      }],
-      alwaysRespectStubs:true,
-      anchors: [["Bottom"],["Top"]],
-      overlays:[]
-    };
-    return connectionObj;
+  actionInfo(node){
+    this.send("showNotification", node);
   },
   deleteTransition(transition){
+    this.createSnapshot();
     this.get("workflow").deleteTransition(transition);
+    this.showUndo('transition');
     this.rerender();
   },
-  renderTransitions(sourceNode,connections,visitedNodes){
+  showWorkflowActionSelect(element){
     var self=this;
-    if(!sourceNode){
-      return;
-    }
-    if (visitedNodes.contains(sourceNode)){
-      return;
-    }
-    if (sourceNode.hasTransition() ){
-      var transitionCount=sourceNode.transitions.length;
-      sourceNode.transitions.forEach(function(transition) {
-        var target = transition.targetNode;
-        if (target.isKillNode() || !Constants.showErrorTransitions && transition.isOnError()){
-          return;
-        }
-        var connectionObj=self.createConnection(sourceNode,target,transition);
-
-        if (transition.condition){
-          var conditionHTML = "<div class='decision-condition' title='"+transition.condition+"'>"+ transition.condition+"</div>";
-          connectionObj.overlays.push([ "Label", {label:conditionHTML, location:0.75, id:"myLabel" } ]);
-        }
-        if (!target.isPlaceholder()){
-          connectionObj.overlays.push(["PlainArrow",{location:-0.1,width: 7,length: 7}]);
-        }
-        if (!(sourceNode.isPlaceholder() || target.isKillNode())){
-          var location=target.type==="placeholder"?1:0.5;
-          var addNodeoverlay=["Custom" , {
-            id: sourceNode.id+"_"+target.id+"_"+"connector",
-            location:location,
-            create:function(component) {
-              var container=Ember.$('<div />');
-              var plus= Ember.$('<div class="fa fa-plus connector_overlay_new"></div>');
-              if ((sourceNode.isDecisionNode() && transitionCount>1 ||sourceNode.isForkNode() && transitionCount>2 ) &&
-                target.isPlaceholder() &&
-                !transition.isDefaultCasePath()){
-                var trash=Ember.$('<div class="node_actions node_left"><i class="fa fa-trash-o"></i></div>');
-                trash.on("click",function(){
-                  self.deleteTransition(transition);
-                });
-                plus.append(trash);
-              }
-              container.append(plus);
-              return container;
-            },
-            events:{
-              click:function(labelOverlay, originalEvent) {
-                var element = originalEvent.target;
-                self.set('popOverElement', element);
-                self.setCurrentTransition(transition);
-                self.$('.popover').popover('destroy');
-                Ember.$(element).parents(".jsplumb-overlay").css("z-index", "4");
-                self.$(element).attr('data-toggle','popover');
-                self.$(element).popover({
-                  html : true,
-                  title : "Add Node <button type='button' class='close'>&times;</button>",
-                  placement: 'right',
-                  trigger : 'focus',
-                  content : function(){
-                    return self.$('#workflow-actions').html();
-                  }
-                });
-                self.$(element).popover("show");
-                self.$('.popover .close').on('click',function(){
-                  Ember.$(".jsplumb-overlay").css("z-index", "");
-                  self.$('.popover').popover('destroy');
-                });
-              }
-            }
-          }];
-          connectionObj.overlays.push(addNodeoverlay);
-        }
-        connections.push(connectionObj);
-        self.renderTransitions(target,connections,visitedNodes);
-      });
-    }
+    this.$('.popover').popover('destroy');
+    Ember.$(element).parents(".jsplumb-overlay").css("z-index", "4");
+    this.$(element).attr('data-toggle','popover');
+    this.$(element).popover({
+      html : true,
+      title : "Add Node <button type='button' class='close'>&times;</button>",
+      placement: 'right',
+      trigger : 'focus',
+      content : function(){
+        return self.$('#workflow-actions').html();
+      }
+    });
+    this.$(element).popover("show");
+    this.$('.popover .close').on('click',function(){
+      Ember.$(".jsplumb-overlay").css("z-index", "");
+      this.$('.popover').popover('destroy');
+    }.bind(this));
   },
+
   layout(){
-    var nodes = Ember.$(".nodecontainer");
-    //var edges = this.designerPlumb.getConnections();
-    var edges=this.workflowConnections;
-    this.layoutManager.doLayout(this,nodes,edges,this.get("workflow"));
-    this.designerPlumb.repaintEverything();
-    var endNodeTop=this.$("#node-end").offset().top;
-    var endNodeLeft=this.$("#node-end").offset().left;
-    this.$("#killnodes-container").offset({top:endNodeTop+50,left:endNodeLeft-50});
-    var top = this.$("#killnodes-container").offset().top + 40;
-    var left = this.$("#killnodes-container").offset().left - 28;
-    this.$('.kill').each(function(index,value){
-      this.$(value).offset({top:top,left:left});
-      top = this.$(value).offset().top+70 ;
-    }.bind(this));
+    this.flowRenderer.refresh();
   },
   doValidation(){
-    this.set('validationErrors',[]);
-    this.validate().then(() => {
-      this.set('validationErrors',[]);
-    }).catch(() => {
-      this.get('flattenedNodes').filterBy('errors',true).forEach((node)=>{
-        this.get('validationErrors').pushObjects(node.errorMsgs);
-      }.bind(this));
-
-    }.bind(this));
+    this.validate();
+  },
+  getStackTrace(data){
+    if(data){
+     try{
+      var stackTraceMsg = JSON.parse(data).stackTrace;
+      if(!stackTraceMsg){
+        return "";
+      }
+     if(stackTraceMsg instanceof Array){
+       return stackTraceMsg.join("").replace(/\tat /g, '&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;');
+     } else {
+       return stackTraceMsg.replace(/\tat /g, '<br/>&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;');
+     }
+     } catch(err){
+       return "";
+     }
+    }
+    return "";
   },
   importWorkflow(filePath){
     var self = this;
@@ -352,17 +296,34 @@ export default Ember.Component.extend(EmberValidations,{
     workflowXmlDefered.promise.then(function(data){
       this.importWorkflowFromString(data);
       this.set("isWorkflowImporting", false);
-    }.bind(this)).catch(function(e){
+    }.bind(this)).catch(function(data){
+    var stackTraceMsg = self.getStackTrace(data.responseText);
+    if(stackTraceMsg.length){
+      self.set("isStackTraceVisible", true);
+      self.set("stackTrace", stackTraceMsg);
+      self.set("isStackTraceAvailable", true);
+    } else {
+      self.set("isStackTraceVisible", false);
+      self.set("isStackTraceAvailable", false);
+    }
       self.set("isWorkflowImporting", false);
       self.set("isImportingSuccess", false);
     });
   },
   importWorkflowFromString(data){
     var workflow=this.get("workflowImporter").importWorkflow(data);
-    this.resetDesigner();
-    this.set("workflow",workflow);
-    this.rerender();
-    this.doValidation();
+    if(this.get('workflow')){
+      this.resetDesigner();
+      this.set("workflow",workflow);
+      this.initAndRenderWorkflow();
+      this.rerender();
+      this.doValidation();
+    }else{
+      this.workflow.initialize();
+      this.set("workflow",workflow);
+      this.initAndRenderWorkflow();
+      this.$('#wf_title').focus();
+    }
   },
   getWorkflowFromHdfs(filePath){
     var url = Ember.ENV.API_URL + "/readWorkflowXml?workflowXmlPath="+filePath;
@@ -377,16 +338,16 @@ export default Ember.Component.extend(EmberValidations,{
       }
     }).done(function(data){
       deferred.resolve(data);
-    }).fail(function(){
-      deferred.reject();
+    }).fail(function(data){
+      deferred.reject(data);
     });
     return deferred;
   },
   resetDesigner(){
     this.set("isImportingSuccess", true);
-    this.set("xmlAppPath", null)
-    this.set('errors',{});
-    this.set('validationErrors',{});
+    this.set("xmlAppPath", null);
+    this.set('errors',[]);
+    this.set('validationErrors',[]);
     this.set('workflowFilePath',"");
     this.get("workflow").resetWorfklow();
     this.set('globalConfig', {});
@@ -395,7 +356,7 @@ export default Ember.Component.extend(EmberValidations,{
       this.set('workflow.parameters', {});
     }
     this.set('parameters', {});
-    this.designerPlumb.reset();
+    this.flowRenderer.reset();
   },
   resetZoomLevel(){
     this.set("zoomLevel", 1);
@@ -423,33 +384,150 @@ export default Ember.Component.extend(EmberValidations,{
     return deferred;
   },
   persistWorkInProgress(){
-    //TODO later
+   var json=JSON.stringify(this.get("workflow"));
+   this.get('workspaceManager').saveWorkInProgress(this.get('tabInfo.id'), json);
+  },
+  getDraftWorkflow(){
+    var drafWorkflowJson = this.get('workspaceManager').restoreWorkInProgress(this.get('tabInfo.id'));
+    var workflowImporter=WorkflowJsonImporter.create({});
+    var workflow=workflowImporter.importWorkflow(drafWorkflowJson);
+    return workflow;
+  },
+  createSnapshot() {
+    this.set('undoAvailable', false);
+    this.set('workflowSnapshot', JSON.stringify(this.get("workflow")));
+  },
+  showUndo (type){
+    this.set('undoAvailable', true);
+    this.set('undoType', type);
+  },
+  deleteWorkflowNode(node){
+    this.createSnapshot();
+    if(node.isKillNode()){
+      var result=this.get("workflow").deleteKillNode(node);
+      if (result && result.status===false){
+        this.get('validationErrors').pushObject({node : node ,message :result.message});
+      }
+    } else {
+      this.get("workflow").deleteNode(node);
+    }
+    this.rerender();
+    this.doValidation();
+    this.showUndo('node');
+  },
+  addWorkflowBranch(node){
+    this.createSnapshot();
+    this.get("workflow").addBranch(node);
+    this.rerender();
+  },
+  openWorkflowEditor(node){
+    this.createSnapshot();
+    var validOkToNodes = WorkflowPathUtil.findValidTransitionsTo(this.get('workflow'), node);
+    this.set('showActionEditor', true);
+    this.set('currentAction', node.actionType);
+    var domain = node.getNodeDetail();
+    this.set('clonedDomain',Ember.copy(domain));
+    this.set('clonedErrorNode', node.errorNode);
+    this.set('clonedKillMessage',node.get('killMessage'));
+    node.set("domain", domain);
+    node.set("validOkToNodes", validOkToNodes);
+    this.set('currentNode', node);
+  },
+  openDecisionEditor(node) {
+    this.get("addBranchListener").trigger("showBranchOptions", node);
+  },
+
+  copyNode(node){
+    this.get('clipboardService').setContent(node, 'copy');
+  },
+  cutNode(node){
+    this.get('clipboardService').setContent(node, 'cut');
+    this.deleteWorkflowNode(node);
+  },
+  replaceNode(node){
+    var clipboardContent = this.get('clipboardService').getContent();
+    Ember.set(node, 'name', clipboardContent.name+'-copy');
+    Ember.set(node, 'domain', clipboardContent.domain);
+    Ember.set(node, 'actionType', clipboardContent.actionType);
+    this.rerender();
+    this.doValidation();
   },
-  restoreWorkinProgress(){
-    //TODO later
+  scrollToNewPosition(){
+    if (Constants.useCytoscape){
+      return;
+    }
+    var scroll = Ember.$(window).scrollTop();
+    Ember.$('html, body')
+    .animate({
+      scrollTop: scroll+200
+    }, 1000);
+  },
+  openSaveWorkflow (){
+    this.get('workflowContext').clearErrors();
+    var workflowGenerator=WorkflowGenerator.create({workflow:this.get("workflow"),
+    workflowContext:this.get('workflowContext')});
+    var workflowXml=workflowGenerator.process();
+    if(this.get('workflowContext').hasErrors()){
+      this.set('errors',this.get('workflowContext').getErrors());
+    }else{
+      var dynamicProperties = this.get('propertyExtractor').getDynamicProperties(workflowXml);
+      var configForSubmit={props:dynamicProperties,xml:workflowXml,params:this.get('workflow.parameters')};
+      this.set("workflowSubmitConfigs",configForSubmit);
+      this.set("showingSaveWorkflow",true);
+    }
+  },  
+  openJobConfig (){
+    this.get('workflowContext').clearErrors();
+    var workflowGenerator=WorkflowGenerator.create({workflow:this.get("workflow"),
+    workflowContext:this.get('workflowContext')});
+    var workflowXml=workflowGenerator.process();
+    if(this.get('workflowContext').hasErrors()){
+      this.set('errors',this.get('workflowContext').getErrors());
+    }else{
+      var dynamicProperties = this.get('propertyExtractor').getDynamicProperties(workflowXml);
+      var configForSubmit={props:dynamicProperties,xml:workflowXml,params:this.get('workflow.parameters')};
+      this.set("workflowSubmitConfigs",configForSubmit);
+      this.set("showingWorkflowConfigProps",true);
+    }
   },
   actions:{
+    showStackTrace(){
+      this.set("isStackTraceVisible", true);
+    },
+    hideStackTrace(){
+      this.set("isStackTraceVisible", false);
+    },
     showWorkflowSla (value) {
       this.set('showWorkflowSla', value);
     },
     showCreateKillNode (value){
-      this.set('showCreateKillNode', value);
+      this.set('showKillNodeManager', value);
+      this.set('addKillNodeMode', true);
+      this.set('editMode', false);
+    },
+    showKillNodeManager (value){
+      this.set('showKillNodeManager', value);
+      this.set('addKillNodeMode', false);
+    },
+    closeKillNodeManager(){
+      this.set("showKillNodeManager", false);
     },
     showVersionSettings(value){
       this.set('showVersionSettings', value);
     },
-    showParameterSettings(value){
+    showingParameterSettings(value){ 
       if(this.get('workflow.parameters') !== null){
         this.set('parameters', Ember.copy(this.get('workflow.parameters')));
       }else{
-        this.set('globalConfig', {});
+        this.set('parameters', {});
       }
       this.set('showParameterSettings', value);
     },
     showCredentials(value){
       this.set('showCredentials', value);
     },
-    createKillNode(){
+    createKillNode(killNode){
+      this.set("killNode", killNode);
       this.set("createKillnodeError",null);
       var existingKillNode=this.get('workflow').get("killNodes").findBy("name",this.get('killNode.name'));
       if (existingKillNode){
@@ -460,7 +538,7 @@ export default Ember.Component.extend(EmberValidations,{
         this.set("createKillnodeError","The kill node cannot be empty");
         return;
       }
-      this.get("workflow").createKillNode(this.get('killNode.name'),this.get('killNode.message'));
+      this.get("workflow").createKillNode(this.get('killNode.name'),this.get('killNode.killMessage'));
       this.set('killNode',{});
       this.rerender();
       this.layout();
@@ -469,62 +547,89 @@ export default Ember.Component.extend(EmberValidations,{
       this.set('showCreateKillNode', false);
     },
     addNode(type){
+      this.createSnapshot();
       var currentTransition=this.get("currentTransition");
-      var newNode=this.get("workflow").addNode(currentTransition,type);
-      if(currentTransition.targetNode.isPlaceholder()){
-        this.designerPlumb.remove(currentTransition.targetNode.id);
-      }
+      this.get("workflow").addNode(this.findTransition(this.get("workflow").startNode, currentTransition.sourceNodeId, currentTransition.targetNode.id),type);
       this.rerender();
       this.doValidation();
-      var scroll = $(window).scrollTop();
-      Ember.$('html, body')
-      .animate({
-        scrollTop: scroll+200
-      }, 1000);
+      this.scrollToNewPosition();
     },
+
     nameChanged(){
       this.doValidation();
     },
-    deleteNode(node){
-      if(node.isKillNode()){
-        var result=this.get("workflow").deleteKillNode(node);
-        if (result && result.status===false){
-          this.get('validationErrors').pushObject({node : node ,message :result.message});
-        }
-      } else {
-        this.get("workflow").deleteNode(node);
+    copyNode(node){
+      this.copyNode(node);
+    },
+    pasteNode(){
+      var clipboardContent = this.get('clipboardService').getContent();
+      var currentTransition = this.get("currentTransition");
+      var node = this.get("workflow").addNode(currentTransition, clipboardContent.actionType);
+      if(clipboardContent.operation === 'cut'){
+        node.name = clipboardContent.name;
+      }else{
+        node.name = clipboardContent.name + '-copy';
       }
+      node.domain = clipboardContent.domain;
+      node.actionType = clipboardContent.actionType;
       this.rerender();
       this.doValidation();
+      this.scrollToNewPosition();
+    },
+    deleteNode(node){
+      this.deleteWorkflowNode(node);
     },
     openEditor(node){
-      this.set('showActionEditor', true);
-      this.set('currentAction', node.actionType);
-      var domain = node.getNodeDetail();
-      this.set('clonedDomain',Ember.copy(domain));
-      this.set('clonedErrorNode', node.errorNode);
-      this.set('clonedKillMessage',node.get('killMessage'));
-      node.set("domain", domain);
-      this.set('currentNode', node);
+      this.openWorkflowEditor(node);
+    },
+    setFilePath(filePath){
+      this.set("workflowFilePath", filePath);
+    },
+    showNotification(node){
+      this.set("showNotificationPanel", true);
+      if(node.actionType){
+        //this.set("hoveredWidget", node.actionType+"-action-info");
+        //this.set("hoveredAction", node.getNodeDetail());
+      }
+    },
+    hideNotification(){
+      this.set("showNotificationPanel", false);
     },
     addBranch(node){
-      this.get("workflow").addBranch(node);
-      this.rerender();
+      this.addWorkflowBranch(node);
     },
     addDecisionBranch(settings){
+      this.createSnapshot();
       this.get("workflow").addDecisionBranch(settings);
       this.rerender();
     },
-    addKillNode(errorNode){
+    setNodeTransitions(transition){
       var currentNode= this.get("currentNode");
-      if(errorNode && errorNode.isNew){
-        this.get("workflow").addKillNode(currentNode,errorNode);
-        this.get("workflow.killNodes").push(errorNode);
+      if(transition.errorNode && transition.errorNode.isNew){
+        this.get("workflow").addKillNode(currentNode,transition.errorNode);
+        this.get("workflow.killNodes").push(transition.errorNode);
       }else {
-        this.set('currentNode.errorNode', errorNode);
+        this.set('currentNode.errorNode', transition.errorNode);
       }
+      currentNode.transitions.forEach((trans)=>{
+        if(transition.okToNode){
+          if(trans.targetNode.id !== transition.okToNode.id){
+            trans.targetNode = transition.okToNode;
+            this.showUndo('transition');
+          }          
+        }
+      }, this);
     },
     submitWorkflow(){
+      this.set('dryrun', false);
+      this.openJobConfig();
+    },
+    saveWorkflow(){
+      this.set('dryrun', false);
+      this.openSaveWorkflow();
+    },
+    previewWorkflow(){
+      this.set("showingPreview",false);
       this.get('workflowContext').clearErrors();
       var workflowGenerator=WorkflowGenerator.create({workflow:this.get("workflow"),
       workflowContext:this.get('workflowContext')});
@@ -532,15 +637,11 @@ export default Ember.Component.extend(EmberValidations,{
       if(this.get('workflowContext').hasErrors()){
         this.set('errors',this.get('workflowContext').getErrors());
       }else{
-        var dynamicProperties = this.get('propertyExtractor').getDynamicProperties(workflowXml);
-        var configForSubmit={props:dynamicProperties,xml:workflowXml,params:this.get('workflow.parameters')};
-        this.set("workflowSubmitConfigs",configForSubmit);
-        this.set("showingWorkflowConfigProps",true);
+        this.set("previewXml",vkbeautify.xml(workflowXml));
+        this.set("showingPreview",true);
       }
-
     },
-    previewWorkflow(){
-      this.set("showingPreview",false);
+    downloadWorkflowXml(){
       this.get('workflowContext').clearErrors();
       var workflowGenerator=WorkflowGenerator.create({workflow:this.get("workflow"),
       workflowContext:this.get('workflowContext')});
@@ -548,12 +649,15 @@ export default Ember.Component.extend(EmberValidations,{
       if(this.get('workflowContext').hasErrors()){
         this.set('errors',this.get('workflowContext').getErrors());
       }else{
-        this.set("previewXml",vkbeautify.xml(workflowXml));
-        this.set("showingPreview",true);
+        this.workflowXmlDownload(workflowXml);
       }
     },
     closeWorkflowSubmitConfigs(){
       this.set("showingWorkflowConfigProps",false);
+      this.set("showingSaveWorkflow",false);
+    },
+    closeSaveWorkflow(){
+      this.set("showingSaveWorkflow",false);
     },
     importWorkflowTest(){
       var deferred = this.importSampleWorkflow();
@@ -563,6 +667,7 @@ export default Ember.Component.extend(EmberValidations,{
         this.rerender();
         this.doValidation();
       }.bind(this)).catch(function(e){
+        console.error(e);
       });
     },
     closeFileBrowser(){
@@ -625,7 +730,11 @@ export default Ember.Component.extend(EmberValidations,{
       this.resetZoomLevel();
       this.$("#flow-designer").css("transform", "scale(" + 1 + ")");
     },
+    resetLayout() {
+      this.flowRenderer.resetLayout();
+    },
     closeActionEditor (isSaved){
+      this.send("hideNotification");
       if(isSaved){
         this.currentNode.onSave();
         this.doValidation();
@@ -638,6 +747,27 @@ export default Ember.Component.extend(EmberValidations,{
       }
       this.set('showActionEditor', false);
       this.rerender();
+    },
+    saveDraft(){
+      this.persistWorkInProgress();
+    },
+
+    undoDelete () {
+      var workflowImporter = WorkflowJsonImporter.create({});
+      var workflow = workflowImporter.importWorkflow(this.get('workflowSnapshot'));
+      this.resetDesigner();
+      this.set("workflow", workflow);
+      this.rerender();
+      this.doValidation();
+      this.set('undoAvailable', false);
+    },
+
+    registerAddBranchAction(component){
+      this.set("addBranchListener",component);
+    },
+    dryRunWorkflow(){
+      this.set('dryrun', true);
+      this.openJobConfig();
     }
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/fs-action-info.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/fs-action-info.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/fs-action-info.js
new file mode 100644
index 0000000..73cabac
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/fs-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/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/fs-action.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/fs-action.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/fs-action.js
index 98a292d..03acbf3 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/fs-action.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/fs-action.js
@@ -15,11 +15,19 @@
 *    limitations under the License.
 */
 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.fsOps': {
+    validators: [
+      validator('fs-action-validator', {
+        dependentKeys: ['actionModel.fsOps.@each']
+      })
+    ]
+  }
+});
+
+export default Ember.Component.extend(Validations, {
   fileBrowser: Ember.inject.service('file-browser'),
   setUp: function() {
     if (this.get('actionModel.fsOps') === undefined) {
@@ -29,6 +37,8 @@ export default Ember.Component.extend(EmberValidations, {
       this.set("actionModel.configuration", {});
       this.set("actionModel.configuration.property", Ember.A([]));
     }
+    var field = 'validations.attrs.actionModel.fsOps.isDirty';
+    this.set(field, false);
     this.sendAction('register', 'fsAction', this);
   }.on('init'),
   initialize: function() {
@@ -41,52 +51,6 @@ export default Ember.Component.extend(EmberValidations, {
       this.$('#collapseOne').collapse('show');
     }
   }.on('didUpdate'),
-  validations: {
-    'actionModel': {
-      inline: validator(function() {
-        var isValidated = true,
-        msg = "";
-        if (!this.get('actionModel.fsOps')) {
-          return;
-        }
-        this.get('actionModel.fsOps').forEach(function(item, index) {
-          switch (item.type) {
-            case "mkdir":
-            case "delete":
-            case "touchz":
-            if (!item.settings.path) {
-              isValidated = false;
-              msg = "path is mandatory";
-            }
-            break;
-            case "chmod":
-            if (!item.settings.path) {
-              isValidated = false;
-              msg = "path and permissions are mandatory";
-            }
-            break;
-            case "chgrp":
-            if (!item.settings.path || !item.settings.group) {
-              isValidated = false;
-              msg = "path and group are mandatory";
-            }
-            break;
-            case "move":
-            if (!item.settings.source || !item.settings.target) {
-              isValidated = false;
-              msg = "source and target are mandatory";
-            }
-            break;
-          }
-        });
-        if (!isValidated) {
-          return "   ";
-        }
-
-      })
-    }
-  },
-  
   actions: {
     openFileBrowser(model, context) {
       if (undefined === context) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/fsaction-info.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/fsaction-info.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/fsaction-info.js
new file mode 100644
index 0000000..caf23b4
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/fsaction-info.js
@@ -0,0 +1,21 @@
+/**
+ * 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({
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/hdfs-browser.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/hdfs-browser.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/hdfs-browser.js
index fc5fd37..c9be41a 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/hdfs-browser.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/hdfs-browser.js
@@ -57,7 +57,7 @@ export default Ember.Component.extend({
     },
     createFolder(){
       var self=this;
-      var $elem=this.$("#selectedPath");
+      var $elem=this.$('input[name="selectedPath"]');
       //$elem.val($elem.val()+"/");
       var folderHint="<enter folder here>";
       this.set("selectedPath",this.get("selectedPath")+"/"+folderHint);
@@ -98,7 +98,8 @@ export default Ember.Component.extend({
       this.showNotification({
         "type": "error",
         "message": "Upload Failed",
-        "details":textStatus
+        "details":textStatus,
+        "errorThrown":errorThrown
       });
     },
     uploadProgress(e){

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/hive-action-info.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/hive-action-info.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/hive-action-info.js
new file mode 100644
index 0000000..73cabac
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/hive-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/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/hive-action.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/hive-action.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/hive-action.js
index 125aac3..ac85a9a 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/hive-action.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/hive-action.js
@@ -16,9 +16,25 @@
 */
 
 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.script': validator('presence', {
+    presence : true,
+    disabled(model, attribute) {
+      return !model.get('isScript');
+    },
+    dependentKeys : ['isScript']
+  }),
+  'actionModel.query': validator('presence', {
+    presence : true,
+    disabled(model, attribute) {
+      return model.get('isScript');
+    },
+    dependentKeys : ['isScript']
+  })
+});
+export default Ember.Component.extend(Validations, {
   hiveOptionObserver : Ember.observer('isScript',function(){
     if(this.get('isScript')){
       this.set("actionModel.query", undefined);
@@ -68,20 +84,6 @@ export default Ember.Component.extend(EmberValidations,{
       this.$('#collapseOne').collapse('show');
     }
   }.on('didUpdate'),
-  validations : {
-    'actionModel.script': {
-      presence: {
-        'if':'isScript',
-        'message' : 'You need to provide a value for Script'
-      }
-    },
-    'actionModel.query': {
-      presence: {
-        unless :'isScript',
-        'message' : 'You need to provide a value for Query'
-      }
-    }
-  },
   actions : {
     openFileBrowser(model, context){
       if(undefined === context){
@@ -95,9 +97,9 @@ export default Ember.Component.extend(EmberValidations,{
     },
     onHiveOptionChange(value){
       if(value === "script"){
-        this.set('isScript',true);
+        this.set('isScript', true);
       }else{
-        this.set('isScript',false);
+        this.set('isScript', false);
       }
     }
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/hive2-action-info.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/hive2-action-info.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/hive2-action-info.js
new file mode 100644
index 0000000..3192c72
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/hive2-action-info.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 : {    
+	  hideNotification(){
+       	  this.sendAction("hideNotification");
+	  }
+   }
+});
+ 
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/hive2-action.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/hive2-action.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/hive2-action.js
index f8b53c5..f23cca7 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/hive2-action.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/hive2-action.js
@@ -16,9 +16,30 @@
 */
 
 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.script': validator('presence', {
+    presence : true,
+    disabled(model, attribute) {
+      return !model.get('isScript');
+    },
+    dependentKeys : ['isScript']
+  }),
+  'actionModel.query': validator('presence', {
+    presence : true,
+    disabled(model, attribute) {
+      return model.get('isScript');
+    },
+    dependentKeys : ['isScript']
+  }),
+  'actionModel.jdbc-url': validator('presence', {
+    presence : true
+  })
+
+});
+
+export default Ember.Component.extend(Validations,{
   hiveOptionObserver : Ember.observer('isScript',function(){
     if(this.get('isScript')){
       this.set("actionModel.query", undefined);
@@ -68,25 +89,6 @@ export default Ember.Component.extend(EmberValidations,{
       this.$('#collapseOne').collapse('show');
     }
   }.on('didUpdate'),
-  validations : {
-    'actionModel.script': {
-      presence: {
-        'if':'isScript',
-        'message' : 'You need to provide a value for Script'
-      }
-    },
-    'actionModel.query': {
-      presence: {
-        unless :'isScript',
-        'message' : 'You need to provide a value for Query'
-      }
-    },
-    'actionModel.jdbc-url': {
-      presence: {
-        'message' : 'You need to provide a value for jdbc url'
-      }
-    }
-  },
   actions : {
     openFileBrowser(model, context){
       if(undefined === context){

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/info-header.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/info-header.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/info-header.js
new file mode 100644
index 0000000..73cabac
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/info-header.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/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/instance-list-config.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/instance-list-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/instance-list-config.js
new file mode 100644
index 0000000..c46a37f
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/instance-list-config.js
@@ -0,0 +1,54 @@
+/*
+*    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({
+  multivalued : true,
+  instance : {
+    value : '',
+    displayValue : '',
+    type : 'date'
+  },
+  initialize : function(){
+    this.sendAction('register', this, this);
+    this.on('bindInputPlaceholder',function () {
+      this.set('addUnboundValue', true);
+    }.bind(this));
+  }.on('init'),
+  bindInputPlaceholder : function () {
+    if(this.get('addUnboundValue') && !Ember.isBlank(this.get('instance'))){
+      this.addinstance();
+    }
+  }.on('willDestroyElement'),
+  addInstance (){
+    this.get('instances').pushObject(Ember.copy(this.get('instance')));
+    this.set('instance', {
+      value : '',
+      displayValue : '',
+      type : 'date'
+    });
+  },
+  actions : {
+    addInstance () {
+      this.addInstance();
+    },
+    deleteInstance (index) {
+      this.get('instances').removeAt(index);
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/java-action-info.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/java-action-info.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/java-action-info.js
new file mode 100644
index 0000000..3192c72
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/java-action-info.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 : {    
+	  hideNotification(){
+       	  this.sendAction("hideNotification");
+	  }
+   }
+});
+ 
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/java-action.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/java-action.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/java-action.js
index 873c284..9d43fe7 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/java-action.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/java-action.js
@@ -16,9 +16,18 @@
 */
 
 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.mainClass': validator('presence', {
+    presence : true
+  }),
+  'actionModel.jobTracker': validator('presence', {
+    presence : true
+  })  
+});
+
+export default Ember.Component.extend(Validations, {
   fileBrowser : Ember.inject.service('file-browser'),
   javaOptsObserver : Ember.observer('isSingle',function(){
     if(this.get('isSingle')){
@@ -67,18 +76,6 @@ export default Ember.Component.extend(EmberValidations, {
       this.$('#collapseOne').collapse('show');
     }
   }.on('didUpdate'),
-  validations : {
-    'actionModel.mainClass': {
-      presence: {
-        'message' : 'You need to provide a value for Main Class',
-      },
-      format: {
-        with: /([a-z][a-z_0-9]*\.)*[A-Za-z_]($[A-Za-z_]|[\w_])*/,
-        allowBlank: false,
-        message: 'You need to provide a valid value'
-      }
-    }
-  },
   actions : {
     openFileBrowser(model, context){
       if(undefined === context){

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/job-config.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/job-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/job-config.js
new file mode 100644
index 0000000..4fa2666
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/job-config.js
@@ -0,0 +1,303 @@
+/*
+*    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 Constants from '../utils/constants';
+import { validator, buildValidations } from 'ember-cp-validations';
+
+const Validations = buildValidations({
+  'filePath': validator('presence', {
+    presence : true
+  }),
+  'configMap': {
+    validators: [
+      validator('job-params-validator', {
+        dependentKeys: ['configMap.@each.value', 'showErrorMessage']
+      })
+    ]
+  }
+});
+
+
+export default Ember.Component.extend(Validations, {
+  systemConfigs : Ember.A([]),
+  showingFileBrowser : false,
+  jobXml : "",
+  overwritePath : false,
+  configMap : Ember.A([]),
+  configPropsExists : false,
+  savingInProgress : false,
+  isStackTraceVisible: false,
+  isStackTraceAvailable: false,
+  alertType : "",
+  alertMessage : "",
+  alertDetails : "",
+  filePath : "",
+  showErrorMessage: false,
+  displayName : Ember.computed('type', function(){
+    if(this.get('type') === 'wf'){
+      return "Workflow";
+    }else if(this.get('type') === 'coord'){
+      return "Coordinator";
+    }else{
+      return "Bundle";
+    }
+  }),
+  initialize :function(){
+    this.set("configPropsExists", this.get("jobConfigs").props.size>0);
+    var configProperties = [];
+    configProperties.pushObjects(this.extractJobParams());
+    configProperties.pushObjects(this.extractJobProperties());
+    this.configureExecutionSettings();
+    this.set("configMap", configProperties);
+    this.set("jobXml", this.get("jobConfigs").xml);
+    this.set('filePath', Ember.copy(this.get('jobFilePath')));
+    Object.keys(this.get('validations.attrs')).forEach((attr)=>{
+    var field = 'validations.attrs.'+attr+'.isDirty';
+    this.set(field, false);
+    }, this);
+  }.on('init'),
+  rendered : function(){
+    this.$("#configureJob").on('hidden.bs.modal', function () {
+      this.sendAction('closeJobConfigs');
+    }.bind(this));
+    this.$("#configureJob").modal("show");    
+  }.on('didInsertElement'),
+  extractJobParams(){
+    var params = [];
+    var jobParams = this.get("jobConfigs").params;
+    if(jobParams && jobParams.configuration && jobParams.configuration.property){
+      jobParams.configuration.property.forEach((param)=>{
+        if(param && !param.value){
+          var prop= Ember.Object.create({
+            name: param.name,
+            value: null,
+            isRequired : true
+          });
+          params.push(prop);
+        }
+      });
+    }
+    return params;
+  },
+
+  extractJobProperties(){
+    var jobProperties = [];
+    var jobParams = this.get("jobConfigs").params;
+    this.get("jobConfigs").props.forEach(function(value) {
+      if (value!== Constants.defaultNameNodeValue && value!==Constants.rmDefaultValue){
+        var propName = value.trim().substring(2, value.length-1);
+        var isRequired = true;
+        if(jobParams && jobParams.configuration && jobParams.configuration.property){
+          var param = jobParams.configuration.property.findBy('name', propName);
+          if(param && param.value){
+            isRequired = false;
+          }else {
+            isRequired = true;
+          }
+        }
+        var prop= Ember.Object.create({
+          name: propName,
+          value: null,
+          isRequired : isRequired
+        });
+        jobProperties.push(prop);
+      }
+    });
+    return jobProperties;
+  },
+  configureExecutionSettings (){
+    this.set('systemConfigs', Ember.A([]));
+    if(this.get('type') !== 'coord' && !this.get('isDryrun')){
+      this.get('systemConfigs').pushObject({displayName: 'Run on submit', name : 'runOnSubmit', value: false});
+    }
+    this.get('systemConfigs').pushObjects([
+      {displayName: 'Use system lib path', name :'useSystemLibPath', value:true},
+      {displayName: 'Rerun on Failure', name : 'rerunOnFailure', value:true}
+    ]);
+  },
+  showNotification(data){
+    if (!data){
+      return;
+    }
+    if (data.type === "success"){
+      this.set("alertType", "success");
+    }
+    if (data.type === "error"){
+      this.set("alertType", "danger");
+    }
+    this.set("alertDetails", data.details);
+    this.set("alertMessage", data.message);
+    if(data.stackTrace.length){
+      this.set("stackTrace", data.stackTrace);
+      this.set("isStackTraceAvailable", true);
+    } else {
+      this.set("isStackTraceAvailable", false);
+    }
+  },
+  prepareJobForSubmission(isDryrun){
+    if(this.get('validations.isInvalid')){
+      return;
+    };
+    this.set('jobFilePath', Ember.copy(this.get('filePath')));
+    var url = Ember.ENV.API_URL + "/submitJob?app.path=" + this.get("filePath") + "&overwrite=" + this.get("overwritePath");
+    url = url + "&jobType=" + this.get('displayName').toUpperCase();
+    var submitConfigs = this.get("configMap");
+    submitConfigs.forEach(function(item) {
+      url = url + "&config." + item.name + "=" + item.value;
+    }, this); 
+    this.get('systemConfigs').forEach((config)=>{
+      if(config.name === 'runOnSubmit' && !isDryrun){
+        url = url + "&oozieparam.action=start";
+      }else if(config.name !== 'runOnSubmit'){
+        url = url + "&oozieconfig." + config.name + "=" + config.value;
+      }
+    });
+    if(isDryrun){
+      url = url + "&oozieparam.action=dryrun";
+    }
+    if ( this.get("jobConfigs").props.has("${resourceManager}")){
+      url= url + "&resourceManager=useDefault";
+    }
+    this.set("savingInProgress", true);
+    this.submitJob(url);
+  },
+  submitJob(url){
+    Ember.$.ajax({
+      url: url,
+      method: "POST",
+      dataType: "text",
+      contentType: "text/plain;charset=utf-8",
+      beforeSend: function(request) {
+        request.setRequestHeader("X-XSRF-HEADER", Math.round(Math.random()*100000));
+        request.setRequestHeader("X-Requested-By", "workflow-designer");
+      },
+      data: this.get("jobXml"),
+      success: function(response) {
+        var result=JSON.parse(response);
+        this.showNotification({
+          "type": "success",
+          "message": this.get('displayName') +" saved.",
+          "details": "Job id :"+result.id
+        });
+        this.set("savingInProgress",false);
+      }.bind(this),
+      error: function(response) {
+        console.log(response);
+        this.set("savingInProgress",false);
+        this.set("isStackTraceVisible",true);
+        this.showNotification({
+          "type": "error",
+          "message": "Error occurred while saving "+ this.get('displayName').toLowerCase(),
+          "details": this.getParsedErrorResponse(response),
+          "stackTrace": this.getStackTrace(response.responseText)
+        });
+      }.bind(this)
+    });
+  },
+  getStackTrace(data){
+    if(data){
+     try{
+      var stackTraceMsg = JSON.parse(data).stackTrace;
+      if(!stackTraceMsg){
+        return "";
+      }
+     if(stackTraceMsg instanceof Array){
+       return stackTraceMsg.join("").replace(/\tat /g, '<br/>&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;');
+     } else {
+       return stackTraceMsg.replace(/\tat /g, '<br/>&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;');
+     }
+     } catch(err){
+       return "";
+     }
+    }
+    return "";
+  },
+  startJob (jobId){
+    this.set('startingInProgress', true);
+    var url = [Ember.ENV.API_URL,
+      "/v2/job/", jobId, "?action=", 'start','&user.name=oozie'
+    ].join("");
+    Ember.$.ajax({
+      url: url,
+      method: 'PUT',
+      beforeSend: function (xhr) {
+        xhr.setRequestHeader("X-XSRF-HEADER", Math.round(Math.random()*100000));
+        xhr.setRequestHeader("X-Requested-By", "Ambari");
+      }
+    }).done(function(){
+      this.set('startingInProgress', false);
+      this.showNotification({
+        "type": "success",
+        "message": this.get('displayName')+" Started",
+        "details": jobId
+      });
+    }.bind(this)).fail(function(response){
+      this.set('startingInProgress', false);
+      this.showNotification({
+        "type": "error",
+        "message": "Error occurred while starting "+ this.get('displayName').toLowerCase(),
+        "details": this.getParsedErrorResponse(response),
+        "stackTrace": this.getStackTrace(response.responseText)
+      });
+    }.bind(this));
+  },
+  getParsedErrorResponse (response){
+    var detail;
+    if (response.responseText && response.responseText.charAt(0)==="{"){
+      var jsonResp=JSON.parse(response.responseText);
+      if (jsonResp.status==="workflow.oozie.error"){
+        detail="Oozie error. Please check the workflow.";
+      }else if(jsonResp.message && jsonResp.message.indexOf("<html>") > -1){
+        detail= "";
+      }else{
+        detail=jsonResp.message;
+      }
+    }else{
+      detail=response; 
+    }
+    return detail;
+  },
+  actions: {
+    selectFile(){
+      this.set("showingFileBrowser",true);
+    },
+    showStackTrace(){
+      this.set("isStackTraceVisible", true);
+    },
+    hideStackTrace(){
+      this.set("isStackTraceVisible", false);
+    },
+    closeFileBrowser(){
+      this.set("showingFileBrowser",false);
+    },
+    dryrun(){
+      this.set('showErrorMessage', true);
+      this.prepareJobForSubmission(true);
+    },
+    save(){
+      this.set('showErrorMessage', true);
+      this.prepareJobForSubmission(false);
+    },
+    previewXml(){
+      this.set("showingPreview",true);
+    },
+    closePreview(){
+      this.set("showingPreview",false);
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/job-details.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/job-details.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/job-details.js
index ce78e59..e403dc4 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/job-details.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/job-details.js
@@ -16,8 +16,12 @@
 */
 
 import Ember from 'ember';
+import {WorkflowImporter} from '../domain/workflow-importer';
+import {ActionTypeResolver} from "../domain/action-type-resolver";
 
 export default Ember.Component.extend({
+  workflowImporter: WorkflowImporter.create({}),
+  actionTypeResolver: ActionTypeResolver.create({}),
   error : {},
   errorMessage : Ember.computed('error', function() {
     if(this.get('error').status === 400){
@@ -57,85 +61,342 @@ export default Ember.Component.extend({
   }),
   initialize : function(){
     if(this.get('currentTab')){
-      this.$('.nav-tabs a[href="'+this.get('currentTab').attr("href")+'"]').tab('show');
+      this.$('.nav-tabs a[href="'+this.get('currentTab').attr("href")+'"]').click();
       if(this.get('model.actions')){
         this.set('model.actionDetails', this.get('model.actions')[0]);
       }
     }
+
+    var x2js = new X2JS();
+    var configurationObj  = x2js.xml_str2json(this.get('model.conf'));
+    this.set('model.configurationProperties', configurationObj.configuration.property);
+
     this.$('.nav-tabs').on('shown.bs.tab', function(event){
       this.sendAction('onTabChange', this.$(event.target));
     }.bind(this));
   }.on('didInsertElement'),
-  actions : {
-    back (){
-      this.sendAction('back');
-    },
-    close : function(){
-      this.sendAction('close');
-    },
-    doRefresh : function(){
-      this.sendAction('doRefresh');
-    },
-    getJobDefinition : function () {
-      Ember.$.get(Ember.ENV.API_URL+'/v2/job/'+this.get('id')+'?show=definition&timezone=GMT',function(response){
-        this.set('model.jobDefinition', (new XMLSerializer()).serializeToString(response).trim());
-      }.bind(this)).fail(function(error){
-        this.set('error',error);
-      }.bind(this));
-    },
-    showFirstActionDetail : function(){
-      this.set('model.actionDetails', this.get('model.actions')[0]);
-    },
-    getJobLog : function (params){
-      var url = Ember.ENV.API_URL+'/v2/job/'+this.get('id')+'?show=log';
-      if(params && params.logFilter){
-        url = url + '&logfilter=' + params.logFilter;
+
+  getShape(nodeType) {
+    switch(nodeType) {
+      case 'start' :
+      case 'end' :
+      case 'kill' :
+      case 'fork' :
+      case 'join' :
+      return 'ellipse';
+      case 'action' :
+      return 'roundrectangle';
+      case 'decision' :
+      return 'diamond';
+      default :
+      return 'star';
+    }
+  },
+
+  getNodeActionByName(workflowActions, nodeName) {
+    if (Ember.isArray(workflowActions)) {
+      var actionInfo = workflowActions.filter(function (modelAction) {
+        return modelAction.name === nodeName;
+      });
+      return actionInfo.length>0 ? actionInfo[0] : null;
+    } else {
+      return workflowActions;
+    }
+  },
+
+  getActionStatus(nodeName, nodeType) {
+    if (nodeType === 'start') {
+      nodeName = ':start:';
+    }
+    var nodeAction = this.getNodeActionByName(this.get('model.actions'), nodeName);
+
+    if (nodeAction) {
+      return nodeAction.status;
+    }
+    return "Not-Visited";
+  },
+
+  getNodeActionType(workflowXmlString, nodeType, nodeName) {
+    if (nodeType !== 'action') {
+      return nodeType;
+    }
+
+    var workflowJson = new X2JS().xml_str2json(workflowXmlString);
+
+    if (Ember.isArray(workflowJson['workflow-app'].action)) {
+      var workflowActionJson = workflowJson['workflow-app'].action.filter(function (workflowAction) {
+        return workflowAction._name === nodeName;
+      });
+      if (workflowActionJson.length>0) {
+        return this.actionTypeResolver.getActionType(workflowActionJson[0]);
       }
-      if(params && params.logActionList){
-        url = url + '&type=action&scope='+ params.logActionList;
+    } else {
+      return this.actionTypeResolver.getActionType(workflowJson['workflow-app'].action);
+    }
+    return '';
+  },
+
+  getBgColorBasedOnStatus(nodeStatus) {
+    switch(nodeStatus) {
+      case 'Not-Visited' :
+      return '#ffffff';
+      default :
+      return '#e6e6e6';
+    }
+  },
+
+  getFontColorBasedOnStatus(nodeStatus) {
+    switch(nodeStatus) {
+      case 'ERROR' :
+      case 'KILLED' :
+      case 'FAILED' :
+      return '#a94442';
+      default :
+      return '#262626';
+    }
+  },
+
+  getBorderColorBasedOnStatus(nodeStatus) {
+    switch(nodeStatus) {
+      case 'OK' :
+        return '#5bb75b';
+      case 'ERROR' :
+      case 'KILLED' :
+      case 'FAILED' :
+        return '#a94442';
+      default :
+        return '#808080';
+    }
+  },
+
+  getNodeLabelContent(nodeType) {
+    switch(nodeType) {
+      case 'fork' :
+      return '\uf0e8';
+      case 'join' :
+      return '\uf0e8';
+      default :
+      return '';
+    }
+  },
+
+  getCyDataNodes(workflow){
+    var dataNodes = [];
+    var self=this;
+    workflow.nodeVisitor.process(workflow.startNode, function(node) {
+      if (node.type === 'kill') {
+        return;
       }
-      Ember.$.get(url,function(response){
-        this.set('model.jobLog', response);
-      }.bind(this)).fail(function(error){
-        this.set('error', error);
-      }.bind(this));
+      var nodeActionStatus = self.getActionStatus(node.name, node.type);
+      dataNodes.push({ data:
+        { id: node.id, name: node.name, type: node.type,
+        content: node.name + self.getNodeLabelContent(node.type),
+        shape: self.getShape(node.type),
+        bgColor: self.getBgColorBasedOnStatus(nodeActionStatus),
+        fontColor: self.getFontColorBasedOnStatus(nodeActionStatus),
+        borderColor: self.getBorderColorBasedOnStatus(nodeActionStatus) }
+      });
+        if (node.transitions.length > 0) {
+          node.transitions.forEach(function(tran){
+            if (tran.targetNode.type === 'kill') {
+              return;
+            }
+            dataNodes.push(
+              {
+                data: {
+                  id: tran.sourceNodeId + '_to_' + tran.targetNode.id,
+                  source:tran.sourceNodeId,
+                  target: tran.targetNode.id,
+                  borderColor: (self.getActionStatus(tran.targetNode.name, tran.targetNode.type) === 'Not-Visited')
+                    ? '#808080' : self.getBorderColorBasedOnStatus(nodeActionStatus)
+                }
+              }
+            );
+          });
+        }
+      });
+      return dataNodes;
     },
-    getErrorLog : function (){
-      Ember.$.get(Ember.ENV.API_URL+'/v2/job/'+this.get('id')+'?show=errorlog',function(response){
-        this.set('model.errorLog', response);
-      }.bind(this)).fail(function(error){
-        this.set('error', error);
-      }.bind(this));
+    showActionNodeDetail(node, workflowXmlString){
+      var nodeName = node.data().name;
+      if (nodeName === 'Start') {
+        nodeName = ':start:';
+      }
+      this.set('model.nodeName', nodeName);
+      this.set('model.nodeType', this.getNodeActionType(workflowXmlString, node.data().type, nodeName));
+      this.set('model.actionDetails', null);
+      var actionInfo = this.getNodeActionByName(this.get('model.actions'), nodeName);
+      this.set('model.actionInfo', actionInfo);
     },
-    getAuditLog : function (){
-      Ember.$.get(Ember.ENV.API_URL+'/v2/job/'+this.get('id')+'?show=auditlog',function(response){
-        this.set('model.auditLog', response);
-      }.bind(this)).fail(function(error){
-        this.set('error', error);
+    renderDag(xmlString){
+      var workflow = this.get("workflowImporter").importWorkflow(xmlString);
+      console.log("Workflow Object..", workflow);
+      var dataNodes=this.getCyDataNodes(workflow);
+      var cy = cytoscape({
+        container: document.getElementById('cy'),
+        elements: dataNodes,
+        style: [
+          {
+            selector: 'node',
+            style: {
+              shape: 'data(shape)',
+              'color': 'data(fontColor)',
+              'background-color': 'data(bgColor)',
+              'border-width': 1,
+              'border-color': 'data(borderColor)',
+              label: 'data(name)',
+              'text-valign': 'center',
+              'font-size': 8
+            }
+          },
+          {
+            selector: 'node[shape = "roundrectangle"]',
+            style: {
+              width: 100,
+              'border-radius': 1,
+            }
+          },
+          {
+            selector: 'node[type = "fork"]',
+            style: {
+              'background-image': 'assets/sitemap.png',
+              'text-halign': 'left'
+            }
+          },
+          {
+            selector: 'node[type = "join"]',
+            style: {
+              'background-image': 'assets/join.png',
+              'text-halign': 'left'
+            }
+          },
+          {
+            selector: 'edge',
+            style: {
+              width: 1,
+              'line-color': 'data(borderColor)',
+              'curve-style': 'bezier',
+      				'target-arrow-shape': 'triangle',
+              'target-arrow-color': 'data(borderColor)'
+            }
+          }
+        ],
+        layout: {
+          name: 'dagre'
+        }
+      });
+
+      // the default values of each option are outlined below:
+      var defaults = {
+        zoomFactor: 2.0, // zoom factor per zoom tick
+        minZoom: 0.1, // min zoom level
+        maxZoom: 10, // max zoom level
+
+        // icon class names
+        sliderHandleIcon: 'fa fa-minus',
+        zoomInIcon: 'fa fa-plus',
+        zoomOutIcon: 'fa fa-minus',
+        resetIcon: 'fa fa-expand'
+      };
+
+      cy.panzoom( defaults );
+
+      cy.on('click', 'node', function(event) {
+        var node = event.cyTarget;
+        this.showActionNodeDetail(node, xmlString);
       }.bind(this));
     },
-    getJobDag : function (){
-      this.set('model.jobDag', Ember.ENV.API_URL+'/v2/job/'+this.get('id')+'?show=graph');
+    importSampleWorkflow (){
+      var self=this;
+      Ember.$.ajax({
+        url: "/sampledata/workflow.xml",
+        dataType: "text",
+        cache:false,
+        success: function(data) {
+          self.renderDag(data);
+        }.bind(this),
+        failure : function(data){
+          console.error(data);
+        }
+      });
     },
-    getCoordActionReruns : function () {
-      var url = Ember.ENV.API_URL+'/v2/job/'+this.get('id')+'?show=allruns&type=action';
-      if(this.get('rerunActionList')){
-        url = url + '&scope=' + this.get('rerunActionList');
+    actions : {
+      back (){
+        this.sendAction('back');
+      },
+      close : function(){
+        this.sendAction('close');
+      },
+      doRefresh : function(){
+        this.sendAction('doRefresh');
+      },
+      getJobDefinition : function () {
+        Ember.$.get(Ember.ENV.API_URL+'/v2/job/'+this.get('id')+'?show=definition&timezone=GMT',function(response){
+          this.set('model.jobDefinition', (new XMLSerializer()).serializeToString(response).trim());
+        }.bind(this)).fail(function(error){
+          this.set('error',error);
+        }.bind(this));
+      },
+      showFirstActionDetail : function(){
+        this.set('model.actionDetails', this.get('model.actions')[0]);
+      },
+      getJobLog : function (params){
+        var url = Ember.ENV.API_URL+'/v2/job/'+this.get('id')+'?show=log';
+        if(params && params.logFilter){
+          url = url + '&logfilter=' + params.logFilter;
+        }
+        if(params && params.logActionList){
+          url = url + '&type=action&scope='+ params.logActionList;
+        }
+        Ember.$.get(url,function(response){
+          this.set('model.jobLog', response);
+        }.bind(this)).fail(function(error){
+          this.set('error', error);
+        }.bind(this));
+      },
+      getErrorLog : function (){
+        Ember.$.get(Ember.ENV.API_URL+'/v2/job/'+this.get('id')+'?show=errorlog',function(response){
+          this.set('model.errorLog', response);
+        }.bind(this)).fail(function(error){
+          this.set('error', error);
+        }.bind(this));
+      },
+      getAuditLog : function (){
+        Ember.$.get(Ember.ENV.API_URL+'/v2/job/'+this.get('id')+'?show=auditlog',function(response){
+          this.set('model.auditLog', response);
+        }.bind(this)).fail(function(error){
+          this.set('error', error);
+        }.bind(this));
+      },
+      getJobDag : function (){
+        //if (true) return this.importSampleWorkflow();
+        Ember.$.get(Ember.ENV.API_URL+'/v2/job/'+this.get('id')+'?show=definition&timezone=GMT',function(response){
+          var xmlString = (new XMLSerializer()).serializeToString(response).trim();
+          this.renderDag(xmlString);
+        }.bind(this)).fail(function(error){
+          this.set('error',error);
+        }.bind(this));
+        // this.set('model.jobDag', Ember.ENV.API_URL+'/v2/job/'+this.get('id')+'?show=graph');
+      },
+      getCoordActionReruns : function () {
+        var url = Ember.ENV.API_URL+'/v2/job/'+this.get('id')+'?show=allruns&type=action';
+        if(this.get('rerunActionList')){
+          url = url + '&scope=' + this.get('rerunActionList');
+        }
+        Ember.$.get(url, function(response){
+          this.set('model.coordActionReruns', response.workflows);
+        }.bind(this)).fail(function(error){
+          this.set('error', error);
+        }.bind(this));
+      },
+      getActionDetails : function (actionInfo) {
+        this.set('model.actionDetails', actionInfo);
+      },
+      showWorkflow : function(workflowId){
+        this.sendAction('showWorkflow', workflowId);
+      },
+      showCoord : function(coordId){
+        this.sendAction('showCoord', coordId);
       }
-      Ember.$.get(url, function(response){
-        this.set('model.coordActionReruns', response.workflows);
-      }.bind(this)).fail(function(error){
-        this.set('error', error);
-      }.bind(this));
-    },
-    getActionDetails : function (actionInfo) {
-      this.set('model.actionDetails', actionInfo);
-    },
-    showWorkflow : function(workflowId){
-      this.sendAction('showWorkflow', workflowId);
-    },
-    showCoord : function(coordId){
-      this.sendAction('showCoord', coordId);
     }
-  }
-});
+  });

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/killnode-config.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/killnode-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/killnode-config.js
new file mode 100644
index 0000000..cc9eb1e
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/killnode-config.js
@@ -0,0 +1,29 @@
+/*
+*    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: {
+    createKillNode() {
+      this.sendAction('createKillNode');
+    },
+
+    updateNode() {
+      this.sendAction('updateNode');
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/killnode-manager.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/killnode-manager.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/killnode-manager.js
new file mode 100644
index 0000000..02660be
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/killnode-manager.js
@@ -0,0 +1,62 @@
+/*
+*    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({
+  initialize : function() {
+    this.set('killNode', {});
+    this.set('editMode', false);
+  }.on('init'),
+
+  rendered : function(){
+    this.$('#killnode-manager-dialog').modal({
+      backdrop: 'static',
+      keyboard: false
+    });
+    this.$('#killnode-manager-dialog').modal('show');
+    this.$('#killnode-manager-dialog').modal().on('hidden.bs.modal', function() {
+      this.sendAction('closeKillNodeManager');
+    }.bind(this));
+  }.on('didInsertElement'),
+  actions: {
+    deleteNode(index) {
+      this.get('killNodes').removeAt(index);
+      this.set('editMode', false);
+    },
+    addNode() {
+      this.set('createKillnodeError',null);
+      this.set('editMode', false);
+      this.set('addKillNodeMode', true);
+      this.set('killNode', {});
+    },
+    editNode(index) {
+      this.set('createKillnodeError', null);
+      this.set('editMode', true);
+      this.set('currentKillNodeIndex', index);
+      var selectedKillNode = this.get('killNodes').objectAt(index);
+      this.set('killNode', {name : selectedKillNode.name, killMessage: selectedKillNode.killMessage});
+    },
+    updateNode(){
+      this.set('editMode', false);
+      this.get('killNodes').objectAt(this.get('currentKillNodeIndex')).set('killMessage', this.get('killNode').killMessage);
+      this.set('killNode', {});
+    },
+    createKillNode() {
+      this.sendAction('createKillNode', this.get("killNode"));
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/map-red-action.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/map-red-action.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/map-red-action.js
index c3782a3..3eb8545 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/map-red-action.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/map-red-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({
   hasStaticProps : true,
   fileBrowser : Ember.inject.service('file-browser'),
   staticProps : Ember.A([]),
@@ -65,9 +64,6 @@ export default Ember.Component.extend(EmberValidations, {
     }.bind(this));
     this.sendAction('register','mapRedAction', this);
   }.on('didInsertElement'),
-  validations : {
-
-  },
   observeError :function(){
     if(this.$('#collapseOne label.text-danger').length > 0 && !this.$('#collapseOne').hasClass("in")){
       this.$('#collapseOne').collapse('show');


[09/10] ambari git commit: AMBARI-18691. Improve and Update Workflow designer to support coordinators and bundles. (Belliraj HB via dipayanb)

Posted by db...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/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/7c7412ed/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/7c7412ed/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/7c7412ed/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/7c7412ed/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/7c7412ed/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/7c7412ed/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/7c7412ed/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/7c7412ed/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/7c7412ed/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/7c7412ed/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/7c7412ed/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/7c7412ed/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/7c7412ed/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/7c7412ed/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/7c7412ed/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(){


[10/10] ambari git commit: AMBARI-18691. Improve and Update Workflow designer to support coordinators and bundles. (Belliraj HB via dipayanb)

Posted by db...@apache.org.
AMBARI-18691. Improve and Update Workflow designer to support coordinators and bundles. (Belliraj HB via dipayanb)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/7c7412ed
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/7c7412ed
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/7c7412ed

Branch: refs/heads/branch-2.5
Commit: 7c7412ed4c350d900086cd880f1e4a5fdffc569b
Parents: 7306e0b
Author: Dipayan Bhowmick <di...@gmail.com>
Authored: Fri Oct 28 00:33:36 2016 +0530
Committer: Dipayan Bhowmick <di...@gmail.com>
Committed: Fri Oct 28 00:33:36 2016 +0530

----------------------------------------------------------------------
 .../apache/oozie/ambari/view/HDFSFileUtils.java |   87 +
 .../org/apache/oozie/ambari/view/JobType.java   |   22 +
 .../ambari/view/OozieProxyImpersonator.java     | 1042 ++++++------
 .../apache/oozie/ambari/view/OozieUtils.java    |   71 +
 .../org/apache/oozie/ambari/view/Utils.java     |  154 ++
 .../wfmanager/src/main/resources/ui/.jshintrc   |   38 +
 .../main/resources/ui/app/components/.gitkeep   |    0
 .../ui/app/components/archive-config.js         |    3 +-
 .../ui/app/components/bundle-config.js          |  262 +++
 .../ui/app/components/bundle-coord-config.js    |  108 ++
 .../ui/app/components/conditional-data-input.js |   78 +
 .../ui/app/components/confirmation-dialog.js    |   25 +
 .../resources/ui/app/components/coord-config.js |  521 ++++++
 .../ui/app/components/credentials-config.js     |  175 +-
 .../app/components/data-input-output-config.js  |   97 ++
 .../resources/ui/app/components/data-input.js   |   41 +
 .../ui/app/components/dataset-config.js         |  103 ++
 .../ui/app/components/date-with-expr.js         |   78 +
 .../ui/app/components/decision-add-branch.js    |   78 +-
 .../ui/app/components/decision-config.js        |   43 +-
 .../ui/app/components/designer-workspace.js     |  158 ++
 .../ui/app/components/distcp-action-info.js     |   26 +
 .../ui/app/components/distcp-action.js          |    6 +-
 .../ui/app/components/email-action-info.js      |   26 +
 .../resources/ui/app/components/email-action.js |   33 +-
 .../resources/ui/app/components/file-config.js  |    3 +-
 .../ui/app/components/flow-designer.js          |  728 +++++----
 .../ui/app/components/fs-action-info.js         |   26 +
 .../resources/ui/app/components/fs-action.js    |   64 +-
 .../ui/app/components/fsaction-info.js          |   21 +
 .../resources/ui/app/components/hdfs-browser.js |    5 +-
 .../ui/app/components/hive-action-info.js       |   26 +
 .../resources/ui/app/components/hive-action.js  |   38 +-
 .../ui/app/components/hive2-action-info.js      |   25 +
 .../resources/ui/app/components/hive2-action.js |   44 +-
 .../resources/ui/app/components/info-header.js  |   26 +
 .../ui/app/components/instance-list-config.js   |   54 +
 .../ui/app/components/java-action-info.js       |   25 +
 .../resources/ui/app/components/java-action.js  |   25 +-
 .../resources/ui/app/components/job-config.js   |  303 ++++
 .../resources/ui/app/components/job-details.js  |  391 ++++-
 .../ui/app/components/killnode-config.js        |   29 +
 .../ui/app/components/killnode-manager.js       |   62 +
 .../ui/app/components/map-red-action.js         |    6 +-
 .../ui/app/components/map-reduce-action-info.js |   25 +
 .../ui/app/components/name-value-config.js      |    7 +-
 .../ui/app/components/name-value-info.js        |   21 +
 .../ui/app/components/named-properties.js       |   25 +-
 .../ui/app/components/pig-action-info.js        |   25 +
 .../resources/ui/app/components/pig-action.js   |   16 +-
 .../ui/app/components/prepare-config-fs.js      |    7 +-
 .../ui/app/components/prepare-config-info.js    |   21 +
 .../ui/app/components/prepare-config.js         |    3 +-
 .../ui/app/components/preview-dialog.js         |   20 +
 .../ui/app/components/property-value-config.js  |   21 +
 .../main/resources/ui/app/components/save-wf.js |  170 ++
 .../ui/app/components/shell-action-info.js      |   25 +
 .../resources/ui/app/components/shell-action.js |   20 +-
 .../resources/ui/app/components/sla-info.js     |  148 +-
 .../ui/app/components/spark-action-info.js      |   25 +
 .../resources/ui/app/components/spark-action.js |   59 +-
 .../ui/app/components/sqoop-action-info.js      |   25 +
 .../resources/ui/app/components/sqoop-action.js |    5 +-
 .../ui/app/components/ssh-action-info.js        |   25 +
 .../resources/ui/app/components/ssh-action.js   |   24 +-
 .../app/components/sub-workflow-action-info.js  |   25 +
 .../resources/ui/app/components/sub-workflow.js |   17 +-
 .../ui/app/components/transition-config.js      |   44 +-
 .../ui/app/components/workflow-action-editor.js |   58 +-
 .../ui/app/components/workflow-actions.js       |    7 +
 .../ui/app/components/workflow-credentials.js   |   65 +-
 .../app/components/workflow-job-action-info.js  |   22 +
 .../ui/app/components/workflow-node.js          |    9 +
 .../ui/app/components/workflow-parameters.js    |   64 +-
 .../resources/ui/app/components/workflow-sla.js |   15 +-
 .../main/resources/ui/app/controllers/.gitkeep  |    0
 .../main/resources/ui/app/controllers/design.js |    5 -
 .../ui/app/domain/action-type-resolver.js       |   62 +
 .../ui/app/domain/actionjob_hanlder.js          |    1 +
 .../app/domain/bundle/bundle-xml-generator.js   |   55 +
 .../ui/app/domain/bundle/bundle-xml-importer.js |   87 +
 .../resources/ui/app/domain/bundle/bundle.js    |   22 +
 .../coordinator/coordinator-xml-generator.js    |  204 +++
 .../coordinator/coordinator-xml-importer.js     |  272 ++++
 .../ui/app/domain/coordinator/coordinator.js    |   22 +
 .../ui/app/domain/cytoscape-flow-renderer.js    |  348 ++++
 .../resources/ui/app/domain/cytoscape-style.js  |  123 ++
 .../ui/app/domain/default-layout-manager.js     |   10 +-
 .../resources/ui/app/domain/findnode-mixin.js   |  113 +-
 .../src/main/resources/ui/app/domain/id-gen.js  |    4 +
 .../ui/app/domain/jsplumb-flow-renderer.js      |  194 +++
 .../resources/ui/app/domain/mapping-utils.js    |   31 +-
 .../resources/ui/app/domain/node-factory.js     |   10 +-
 .../resources/ui/app/domain/node-handler.js     |   49 +-
 .../src/main/resources/ui/app/domain/node.js    |    3 +-
 .../main/resources/ui/app/domain/sla-info.js    |   38 +-
 .../main/resources/ui/app/domain/transition.js  |    5 +-
 .../ui/app/domain/workflow-importer.js          |    8 +-
 .../ui/app/domain/workflow-json-importer.js     |   92 ++
 .../ui/app/domain/workflow-path-util.js         |   73 +
 .../ui/app/domain/workflow-xml-generator.js     |    1 -
 .../main/resources/ui/app/domain/workflow.js    |  114 +-
 .../ui/app/domain/workflow_xml_mapper.js        |    5 +-
 .../src/main/resources/ui/app/helpers/.gitkeep  |    0
 .../src/main/resources/ui/app/index.html        |    9 +
 .../src/main/resources/ui/app/routes/.gitkeep   |    0
 .../main/resources/ui/app/routes/dashboard.js   |   10 +-
 .../src/main/resources/ui/app/routes/design.js  |   38 +-
 .../ui/app/services/workflow-clipboard.js       |   34 +
 .../ui/app/services/workspace-manager.js        |   62 +
 .../src/main/resources/ui/app/styles/app.less   | 1497 ++++++++++++++++++
 .../ui/app/templates/components/.gitkeep        |    0
 .../app/templates/components/bundle-config.hbs  |  129 ++
 .../components/bundle-coord-config.hbs          |   58 +
 .../templates/components/bundle-job-details.hbs |   17 +-
 .../components/conditional-data-input.hbs       |   64 +
 .../components/confirmation-dialog.hbs          |   34 +
 .../app/templates/components/coord-config.hbs   |  352 ++++
 .../templates/components/coord-job-details.hbs  |   17 +-
 .../templates/components/credentials-config.hbs |   33 +-
 .../components/data-input-output-config.hbs     |   68 +
 .../ui/app/templates/components/data-input.hbs  |   40 +
 .../app/templates/components/dataset-config.hbs |   70 +
 .../app/templates/components/date-with-expr.hbs |   41 +
 .../components/decision-add-branch.hbs          |    4 +-
 .../templates/components/decision-config.hbs    |    2 +-
 .../templates/components/designer-workspace.hbs |  106 ++
 .../templates/components/distcp-action-info.hbs |   35 +
 .../templates/components/email-action-info.hbs  |   28 +
 .../app/templates/components/email-action.hbs   |   10 +-
 .../ui/app/templates/components/field-error.hbs |    3 +
 .../app/templates/components/flow-designer.hbs  |  300 ++--
 .../app/templates/components/fs-action-info.hbs |   33 +
 .../ui/app/templates/components/fs-action.hbs   |    3 +-
 .../app/templates/components/fsaction-info.hbs  |   39 +
 .../app/templates/components/hdfs-browser.hbs   |    2 +-
 .../templates/components/hive-action-info.hbs   |   47 +
 .../ui/app/templates/components/hive-action.hbs |    6 +-
 .../templates/components/hive2-action-info.hbs  |   49 +
 .../app/templates/components/hive2-action.hbs   |    6 +-
 .../ui/app/templates/components/info-header.hbs |   18 +
 .../components/instance-list-config.hbs         |   35 +
 .../templates/components/java-action-info.hbs   |   52 +
 .../ui/app/templates/components/java-action.hbs |    4 +-
 .../ui/app/templates/components/job-config.hbs  |  126 ++
 .../ui/app/templates/components/job-details.hbs |    2 +-
 .../templates/components/killnode-config.hbs    |   67 +
 .../templates/components/killnode-manager.hbs   |   69 +
 .../components/map-reduce-action-info.hbs       |   41 +
 .../templates/components/name-value-info.hbs    |   22 +
 .../templates/components/named-properties.hbs   |    2 +-
 .../templates/components/pig-action-info.hbs    |   47 +
 .../ui/app/templates/components/pig-action.hbs  |    2 +-
 .../templates/components/prepare-config-fs.hbs  |   46 +-
 .../components/prepare-config-info.hbs          |   22 +
 .../app/templates/components/preview-dialog.hbs |   33 +
 .../components/property-value-config.hbs        |   22 +
 .../ui/app/templates/components/save-wf.hbs     |   79 +
 .../templates/components/shell-action-info.hbs  |   48 +
 .../app/templates/components/shell-action.hbs   |    4 +-
 .../ui/app/templates/components/sla-info.hbs    |   17 +-
 .../templates/components/spark-action-info.hbs  |   46 +
 .../app/templates/components/spark-action.hbs   |    6 +-
 .../templates/components/sqoop-action-info.hbs  |   41 +
 .../templates/components/ssh-action-info.hbs    |   32 +
 .../ui/app/templates/components/ssh-action.hbs  |    4 +-
 .../components/sub-workflow-action-info.hbs     |   29 +
 .../app/templates/components/sub-workflow.hbs   |    2 +-
 .../templates/components/transition-config.hbs  |   23 +-
 .../templates/components/version-settings.hbs   |    2 +-
 .../templates/components/workflow-actions.hbs   |    5 +
 .../templates/components/workflow-config.hbs    |    2 +-
 .../components/workflow-credentials.hbs         |   34 +-
 .../components/workflow-job-action-info.hbs     |   80 +
 .../components/workflow-job-details.hbs         |  158 +-
 .../app/templates/components/workflow-node.hbs  |    3 +-
 .../components/workflow-parameters.hbs          |   23 +-
 .../resources/ui/app/templates/dashboard.hbs    |    2 +-
 .../main/resources/ui/app/templates/design.hbs  |    2 +-
 .../main/resources/ui/app/utils/constants.js    |   43 +-
 .../app/validators/decission-node-validator.js  |   58 +
 .../app/validators/duplicate-data-node-name.js  |   60 +
 .../validators/duplicate-flattened-node-name.js |   66 +
 .../app/validators/duplicate-kill-node-name.js  |   58 +
 .../ui/app/validators/fs-action-validator.js    |   76 +
 .../ui/app/validators/job-params-validator.js   |   54 +
 .../ui/app/validators/operand-length.js         |   46 +
 .../resources/ui/app/validators/unique-name.js  |   59 +
 .../wfmanager/src/main/resources/ui/bower.json  |    5 +-
 .../src/main/resources/ui/ember-cli-build.js    |   10 +
 .../hdfs-directory-viewer/addon/.gitkeep        |    0
 .../hdfs-directory-viewer/app/.gitkeep          |    0
 .../tests/dummy/app/components/.gitkeep         |    0
 .../tests/dummy/app/controllers/.gitkeep        |    0
 .../tests/dummy/app/helpers/.gitkeep            |    0
 .../tests/dummy/app/models/.gitkeep             |    0
 .../tests/dummy/app/routes/.gitkeep             |    0
 .../dummy/app/templates/components/.gitkeep     |    0
 .../tests/integration/.gitkeep                  |    0
 .../hdfs-directory-viewer/tests/unit/.gitkeep   |    0
 .../hdfs-directory-viewer/vendor/.gitkeep       |    0
 .../resources/ui/mock-service/mock-server.js    |   52 +
 .../main/resources/ui/mock-service/mockData.js  |  316 ++++
 .../src/main/resources/ui/package.json          |   18 +-
 .../main/resources/ui/public/assets/favicon.ico |  Bin 0 -> 1150 bytes
 .../main/resources/ui/public/assets/join.png    |  Bin 0 -> 331 bytes
 .../main/resources/ui/public/assets/logo.png    |  Bin 0 -> 4568 bytes
 .../main/resources/ui/public/assets/play.png    |  Bin 0 -> 1164 bytes
 .../main/resources/ui/public/assets/sitemap.png |  Bin 0 -> 317 bytes
 .../main/resources/ui/public/assets/stop.png    |  Bin 0 -> 1164 bytes
 .../src/main/resources/ui/public/loader.gif     |  Bin 0 -> 42435 bytes
 .../resources/ui/public/sampledata/bundle.xml   |   32 +
 .../ui/public/sampledata/coordinator.xml        |  113 ++
 .../resources/ui/tests/integration/.gitkeep     |    0
 .../components/bundle-config-test.js            |   40 +
 .../components/bundle-coord-config-test.js      |   40 +
 .../components/conditional-data-input-test.js   |   40 +
 .../components/confirmation-dialog-test.js      |   40 +
 .../integration/components/coord-config-test.js |   40 +
 .../components/data-input-output-config-test.js |   40 +
 .../integration/components/data-input-test.js   |   40 +
 .../components/dataset-config-test.js           |   40 +
 .../components/date-with-expr-test.js           |   40 +
 .../components/designer-workspace-test.js       |   40 +
 .../components/distcp-action-info-test.js       |   41 +
 .../components/email-action-info-test.js        |   41 +
 .../components/fs-action-info-test.js           |   41 +
 .../components/fsaction-info-test.js            |   41 +
 .../components/hive-action-info-test.js         |   41 +
 .../components/hive2-action-info-test.js        |   41 +
 .../integration/components/info-header-test.js  |   41 +
 .../components/instance-list-config-test.js     |   41 +
 .../components/java-action-info-test.js         |   41 +
 .../integration/components/job-config-test.js   |   41 +
 .../components/killnode-config-test.js          |   41 +
 .../components/killnode-manager-test.js         |   41 +
 .../components/map-reduce-action-info-test.js   |   41 +
 .../components/name-value-info-test.js          |   41 +
 .../components/pig-action-info-test.js          |   41 +
 .../components/prepare-config-info-test.js      |   41 +
 .../components/preview-dialog-test.js           |   40 +
 .../components/property-value-config-test.js    |   41 +
 .../integration/components/save-wf-test.js      |   40 +
 .../components/shell-action-info-test.js        |   41 +
 .../components/spark-action-info-test.js        |   41 +
 .../components/sqoop-action-info-test.js        |   41 +
 .../components/ssh-action-info-test.js          |   41 +
 .../components/sub-workflow-action-info-test.js |   41 +
 .../src/main/resources/ui/tests/unit/.gitkeep   |    0
 .../unit/services/workflow-clipboard-test.js    |   29 +
 .../unit/services/workspace-manager-test.js     |   29 +
 .../validators/decission-node-validator-test.js |   26 +
 .../validators/duplicate-data-node-name-test.js |   27 +
 .../duplicate-flattened-node-name-test.js       |   27 +
 .../validators/duplicate-kill-node-name-test.js |   27 +
 .../unit/validators/fs-action-validator-test.js |   26 +
 .../validators/job-params-validator-test.js     |   26 +
 .../unit/validators/operand-length-test.js      |   27 +
 .../tests/unit/validators/unique-name-test.js   |   27 +
 259 files changed, 13407 insertions(+), 1980 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/HDFSFileUtils.java
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/HDFSFileUtils.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/HDFSFileUtils.java
new file mode 100644
index 0000000..58c3980
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/HDFSFileUtils.java
@@ -0,0 +1,87 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.
+ */
+package org.apache.oozie.ambari.view;
+
+import java.io.IOException;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.utils.hdfs.HdfsApi;
+import org.apache.ambari.view.utils.hdfs.HdfsUtil;
+import org.apache.hadoop.fs.FSDataInputStream;
+import org.apache.hadoop.fs.FSDataOutputStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HDFSFileUtils {
+	private final static Logger LOGGER = LoggerFactory
+			.getLogger(HDFSFileUtils.class);
+	private ViewContext viewContext;
+
+	public HDFSFileUtils(ViewContext viewContext) {
+		super();
+		this.viewContext = viewContext;
+	}
+	public boolean fileExists(String path) {
+		boolean fileExists;
+		try {
+			fileExists = getHdfsgetApi().exists(path);
+		} catch (IOException e) {
+			LOGGER.error(e.getMessage(), e);
+			throw new RuntimeException(e);
+		} catch (InterruptedException e) {
+			LOGGER.error(e.getMessage(), e);
+			throw new RuntimeException(e);
+		}
+		LOGGER.info("FILE exists for [" + path + "] returned [" + fileExists
+				+ "]");
+		return fileExists;
+	}
+	public FSDataInputStream read(String filePath)throws IOException{
+		FSDataInputStream is;
+		try {
+			is = getHdfsgetApi().open(filePath);
+		} catch (InterruptedException e) {
+			throw new RuntimeException(e);
+		}
+		return is;
+	}
+	public String createWorkflowFile( String workflowFile,String postBody,
+			boolean overwrite) throws IOException {
+		FSDataOutputStream fsOut;
+		try {
+			fsOut = getHdfsgetApi().create(workflowFile,
+					overwrite);
+		} catch (InterruptedException e) {
+			throw new RuntimeException(e);
+		}
+		fsOut.write(postBody.getBytes());
+		fsOut.close();
+		return workflowFile;
+	}
+	private HdfsApi getHdfsgetApi() {
+		try {
+			return HdfsUtil.connectToHDFSApi(viewContext);
+		} catch (Exception ex) {
+			LOGGER.error("Error in getting HDFS Api", ex);
+			throw new RuntimeException(
+					"HdfsApi connection failed. Check \"webhdfs.url\" property",
+					ex);
+		}
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/JobType.java
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/JobType.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/JobType.java
new file mode 100644
index 0000000..5a47b68
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/JobType.java
@@ -0,0 +1,22 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.
+ */
+package org.apache.oozie.ambari.view;
+
+public enum JobType {
+	WORKFLOW, COORDINATOR, BUNDLE
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieProxyImpersonator.java
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieProxyImpersonator.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieProxyImpersonator.java
index 3ed6352..0533f04 100644
--- a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieProxyImpersonator.java
+++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieProxyImpersonator.java
@@ -20,14 +20,10 @@ package org.apache.oozie.ambari.view;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.io.StringReader;
-import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
 
 import javax.inject.Inject;
 import javax.ws.rs.Consumes;
@@ -48,522 +44,550 @@ import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.StreamingOutput;
 import javax.ws.rs.core.UriInfo;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.TransformerFactoryConfigurationError;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
 
 import org.apache.ambari.view.URLStreamProvider;
 import org.apache.ambari.view.ViewContext;
-import org.apache.ambari.view.utils.ambari.AmbariApi;
-import org.apache.ambari.view.utils.hdfs.HdfsApi;
-import org.apache.ambari.view.utils.hdfs.HdfsUtil;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.exception.ExceptionUtils;
 import org.apache.hadoop.fs.FSDataInputStream;
-import org.apache.hadoop.fs.FSDataOutputStream;
+import org.apache.hadoop.security.AccessControlException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
+
+import com.google.inject.Singleton;
 
 /**
  * This is a class used to bridge the communication between the and the Oozie
  * API executing inside ambari.
  */
+@Singleton
 public class OozieProxyImpersonator {
-
-  private static final String OOZIE_WF_APPLICATION_PATH_CONF_KEY = "oozie.wf.application.path";
-  private static final String OOZIE_WF_RERUN_FAILNODES_CONF_KEY = "oozie.wf.rerun.failnodes";
-  private static final String OOZIE_USE_SYSTEM_LIBPATH_CONF_KEY = "oozie.use.system.libpath";
-  private static final String XML_INDENT_SPACES = "4";
-  private static final String XML_INDENT_AMT_PROP_NAME = "{http://xml.apache.org/xslt}indent-amount";
-  private ViewContext viewContext;
-  private AmbariApi ambariApi;
-  private HdfsApi _hdfsApi = null;
-
-  private static final String USER_NAME_HEADER = "user.name";
-  private static final String USER_OOZIE_SUPER = "oozie";
-  private static final String DO_AS_HEADER = "doAs";
-
-  private static final String SERVICE_URI_PROP = "oozie.service.uri";
-  private static final String DEFAULT_SERVICE_URI = "http://sandbox.hortonworks.com:11000/oozie";
-
-  private final static Logger LOGGER = LoggerFactory
-    .getLogger(OozieProxyImpersonator.class);
-
-  @Inject
-  public OozieProxyImpersonator(ViewContext viewContext) {
-    this.viewContext = viewContext;
-    this.ambariApi = new AmbariApi(viewContext);
-    LOGGER.info(String.format(
-      "OozieProxyImpersonator initialized for instance: %s",
-      viewContext.getInstanceName()));
-  }
-
-  @Path("/fileServices")
-  public FileServices fileServices() {
-    return new FileServices(viewContext);
-  }
-
-  @POST
-  @Path("/submitWorkflow")
-  @Consumes({MediaType.TEXT_PLAIN + "," + MediaType.TEXT_XML})
-  public Response submitWorkflow(String postBody, @Context HttpHeaders headers,
-                                 @Context UriInfo ui, @QueryParam("app.path") String appPath,
-                                 @DefaultValue("false") @QueryParam("overwrite") Boolean overwrite) {
-    LOGGER.info("submit workflow job called");
-    try {
-      if (StringUtils.isEmpty(appPath)) {
-        throw new RuntimeException("app path can't be empty.");
-      }
-      appPath = appPath.trim();
-      if (!overwrite) {
-        boolean fileExists = getHdfsgetApi().exists(appPath);
-        LOGGER.info("FILE exists for [" + appPath + "] returned [" + fileExists
-          + "]");
-        if (fileExists) {
-          HashMap<String, String> resp = new HashMap<String, String>();
-          resp.put("status", "workflow.folder.exists");
-          resp.put("message", "Workflow Folder exists");
-          return Response.status(Response.Status.BAD_REQUEST).entity(resp)
-            .build();
-        }
-      }
-      String workflowFile = null;
-      if (appPath.endsWith(".xml")) {
-        workflowFile = appPath;
-      } else {
-        workflowFile = appPath + (appPath.endsWith("/") ? "" : "/")
-          + "workflow.xml";
-      }
-      postBody = formatXml(postBody);
-      try {
-        String filePath = createWorkflowFile(postBody, workflowFile, overwrite);
-        LOGGER.info(String.format("submit workflow job done. filePath=[%s]",
-          filePath));
-      } catch (org.apache.hadoop.security.AccessControlException ace) {
-        HashMap<String, String> resp = new HashMap<String, String>();
-        resp.put("status", "workflow.oozie.error");
-        resp.put("message", "You dont seem to have access to folder path.");
-        return Response.status(Response.Status.BAD_REQUEST).entity(resp)
-          .build();
-      }
-
-      String response = submitWorkflowJobToOozie(headers, appPath,
-        ui.getQueryParameters());
-      if (response != null && response.trim().startsWith("{")) {
-        // dealing with oozie giving error but with 200 response.
-        return Response.status(Response.Status.OK).entity(response).build();
-      } else {
-        HashMap<String, String> resp = new HashMap<String, String>();
-        resp.put("status", "workflow.oozie.error");
-        resp.put("message", response);
-        return Response.status(Response.Status.BAD_REQUEST).entity(resp)
-          .build();
-      }
-    } catch (InterruptedException e) {
-      throw new RuntimeException(e);
-    } catch (Exception e) {
-      LOGGER.error("Error in submit workflow", e);
-      throw new RuntimeException(e);
-    }
-  }
-
-  @GET
-  @Path("/readWorkflowXml")
-  public Response readWorkflowXxml(
-      @QueryParam("workflowXmlPath") String workflowPath) {
-    if (StringUtils.isEmpty(workflowPath)) {
-      throw new RuntimeException("workflowXmlPath can't be empty.");
-    }
-    try {
-      final FSDataInputStream is = getHdfsgetApi().open(workflowPath);
-      StreamingOutput streamer = new StreamingOutput() {
-
-        @Override
-        public void write(OutputStream os) throws IOException,
-            WebApplicationException {
-          IOUtils.copy(is, os);
-          is.close();
-          os.close();
-        }
-      };
-      return Response.ok(streamer).status(200).build();
-    } catch (org.apache.hadoop.security.AccessControlException ace) {
-      HashMap<String, String> resp = new HashMap<String, String>();
-      resp.put("status", "workflow.oozie.error");
-      resp.put("message", "Access denied to file path");
-      return Response.status(Response.Status.FORBIDDEN).entity(resp).build();
-    } catch (IOException e) {
-      LOGGER.error("Error in read worfklow file", e);
-      throw new RuntimeException(e);
-    } catch (InterruptedException e) {
-      LOGGER.error("Error in read worfklow file", e);
-      throw new RuntimeException(e);
-    }
-  }
-
-  @GET
-  @Path("/getDag")
-  @Produces("image/png")
-  public Response submitWorkflow(@Context HttpHeaders headers,
-                                 @Context UriInfo ui, @QueryParam("jobid") String jobid) {
-    String imgUrl = getServiceUri() + "/v2/job/" + jobid + "?show=graph";
-    Map<String, String> newHeaders = getHeaders(headers);
-    final InputStream is = readFromOozie(headers, imgUrl, HttpMethod.GET, null,
-      newHeaders);
-    StreamingOutput streamer = new StreamingOutput() {
-
-      @Override
-      public void write(OutputStream os) throws IOException,
-        WebApplicationException {
-        IOUtils.copy(is, os);
-        is.close();
-        os.close();
-      }
-
-    };
-    return Response.ok(streamer).status(200).build();
-  }
-
-  @GET
-  @Path("/{path: .*}")
-  public Response handleGet(@Context HttpHeaders headers, @Context UriInfo ui) {
-    try {
-      String serviceURI = buildURI(ui);
-      return consumeService(headers, serviceURI, HttpMethod.GET, null);
-    } catch (Exception ex) {
-      LOGGER.error("Error in GET proxy", ex);
-      return Response.status(Response.Status.BAD_REQUEST).entity(ex.toString())
-        .build();
-    }
-  }
-
-  @POST
-  @Path("/{path: .*}")
-  public Response handlePost(String xml, @Context HttpHeaders headers, @Context UriInfo ui) {
-    try {
-      String serviceURI = buildURI(ui);
-      return consumeService(headers, serviceURI, HttpMethod.POST, xml);
-    } catch (Exception ex) {
-      LOGGER.error("Error in POST proxy", ex);
-      return Response.status(Response.Status.BAD_REQUEST).entity(ex.toString())
-        .build();
-    }
-  }
-
-  @DELETE
-  @Path("/{path: .*}")
-  public Response handleDelete(@Context HttpHeaders headers, @Context UriInfo ui) {
-    try {
-      String serviceURI = buildURI(ui);
-      return consumeService(headers, serviceURI, HttpMethod.POST, null);
-    } catch (Exception ex) {
-      LOGGER.error("Error in DELETE proxy", ex);
-      return Response.status(Response.Status.BAD_REQUEST).entity(ex.toString())
-        .build();
-    }
-  }
-
-  @PUT
-  @Path("/{path: .*}")
-  public Response handlePut(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
-
-    try {
-      String serviceURI = buildURI(ui);
-      return consumeService(headers, serviceURI, HttpMethod.PUT, body);
-    } catch (Exception ex) {
-      LOGGER.error("Error in PUT proxy", ex);
-      return Response.status(Response.Status.BAD_REQUEST).entity(ex.toString())
-        .build();
-    }
-  }
-
-  private String submitWorkflowJobToOozie(HttpHeaders headers, String filePath,
-                                          MultivaluedMap<String, String> queryParams) {
-    String nameNode = "hdfs://" + viewContext.getCluster().getConfigurationValue("hdfs-site", "dfs.namenode.rpc-address");
-
-    if (!queryParams.containsKey("config.nameNode")) {
-      ArrayList<String> nameNodes = new ArrayList<String>();
-      LOGGER.info("Namenode===" + nameNode);
-      nameNodes.add(nameNode);
-      queryParams.put("config.nameNode", nameNodes);
-    }
-
-    HashMap<String, String> workflowConigs = new HashMap<String, String>();
-    if (queryParams.containsKey("resourceManager")
-      && "useDefault".equals(queryParams.getFirst("resourceManager"))) {
-      String jobTrackerNode = viewContext.getCluster().getConfigurationValue(
-        "yarn-site", "yarn.resourcemanager.address");
-      LOGGER.info("jobTrackerNode===" + jobTrackerNode);
-      workflowConigs.put("resourceManager", jobTrackerNode);
-      workflowConigs.put("jobTracker", jobTrackerNode);
-    }
-    if (queryParams != null) {
-      for (Map.Entry<String, List<String>> entry : queryParams.entrySet()) {
-        if (entry.getKey().startsWith("config.")) {
-          if (entry.getValue() != null && entry.getValue().size() > 0) {
-            workflowConigs.put(entry.getKey().substring(7), entry.getValue()
-              .get(0));
-          }
-        }
-      }
-    }
-
-    if (queryParams.containsKey("oozieconfig.useSystemLibPath")) {
-      String useSystemLibPath = queryParams
-        .getFirst("oozieconfig.useSystemLibPath");
-      workflowConigs.put(OOZIE_USE_SYSTEM_LIBPATH_CONF_KEY, useSystemLibPath);
-    } else {
-      workflowConigs.put(OOZIE_USE_SYSTEM_LIBPATH_CONF_KEY, "true");
-    }
-    if (queryParams.containsKey("oozieconfig.rerunOnFailure")) {
-      String rerunFailnodes = queryParams
-        .getFirst("oozieconfig.rerunOnFailure");
-      workflowConigs.put(OOZIE_WF_RERUN_FAILNODES_CONF_KEY, rerunFailnodes);
-    } else {
-      workflowConigs.put(OOZIE_WF_RERUN_FAILNODES_CONF_KEY, "true");
-    }
-
-    workflowConigs.put("user.name", viewContext.getUsername());
-    workflowConigs.put(OOZIE_WF_APPLICATION_PATH_CONF_KEY, nameNode + filePath);
-    String configXMl = generateConigXml(workflowConigs);
-    LOGGER.info("Config xml==" + configXMl);
-    HashMap<String, String> customHeaders = new HashMap<String, String>();
-    customHeaders.put("Content-Type", "application/xml;charset=UTF-8");
-    Response serviceResponse = consumeService(headers, getServiceUri()
-      + "/v2/jobs", HttpMethod.POST, configXMl, customHeaders);
-
-    LOGGER
-      .info("REsp from oozie status entity==" + serviceResponse.getEntity());
-    if (serviceResponse.getEntity() instanceof String) {
-      return (String) serviceResponse.getEntity();
-    } else {
-      return "success";
-    }
-
-  }
-
-  private String createWorkflowFile(String postBody, String workflowFile, boolean overwrite) throws IOException, InterruptedException {
-    FSDataOutputStream fsOut = getHdfsgetApi().create(workflowFile, overwrite);
-    fsOut.write(postBody.getBytes());
-    fsOut.close();
-    return workflowFile;
-  }
-
-  private String buildURI(UriInfo ui) {
-    String uiURI = ui.getAbsolutePath().getPath();
-    int index = uiURI.indexOf("proxy/") + 5;
-    uiURI = uiURI.substring(index);
-    String serviceURI = getServiceUri();
-    serviceURI += uiURI;
-
-    MultivaluedMap<String, String> parameters = ui.getQueryParameters();
-    StringBuilder urlBuilder = new StringBuilder(serviceURI);
-    boolean firstEntry = true;
-    for (Map.Entry<String, List<String>> entry : parameters.entrySet()) {
-      if ("user.name".equals(entry.getKey())) {
-        ArrayList<String> vals = new ArrayList<String>();
-        vals.add(viewContext.getUsername());
-        entry.setValue(vals);
-      }
-      if (firstEntry) {
-        urlBuilder.append("?");
-      } else {
-        urlBuilder.append("&");
-      }
-      boolean firstVal = true;
-      for (String val : entry.getValue()) {
-        urlBuilder.append(firstVal ? "" : "&").append(entry.getKey())
-          .append("=").append(val);
-        firstVal = false;
-      }
-      firstEntry = false;
-    }
-    return urlBuilder.toString();
-  }
-
-  private String getServiceUri() {
-    String serviceURI = viewContext.getProperties().get(SERVICE_URI_PROP) != null ? viewContext
-      .getProperties().get(SERVICE_URI_PROP) : DEFAULT_SERVICE_URI;
-    return serviceURI;
-  }
-
-  public Response consumeService(HttpHeaders headers, String urlToRead,
-                                 String method, String body, Map<String, String> customHeaders) {
-    Response response = null;
-    InputStream stream = readFromOozie(headers, urlToRead, method, body,
-      customHeaders);
-    String stringResponse = null;
-    try {
-      stringResponse = IOUtils.toString(stream);
-    } catch (IOException e) {
-      LOGGER.error("Error while converting stream to string", e);
-      throw new RuntimeException(e);
-    }
-    if (stringResponse.contains(Response.Status.BAD_REQUEST.name())) {
-      response = Response.status(Response.Status.BAD_REQUEST)
-        .entity(stringResponse).type(MediaType.TEXT_PLAIN).build();
-    } else {
-      response = Response.status(Response.Status.OK).entity(stringResponse)
-        .type(deduceType(stringResponse)).build();
-    }
-    return response;
-  }
-
-  private InputStream readFromOozie(HttpHeaders headers, String urlToRead,
-                                    String method, String body, Map<String, String> customHeaders) {
-    URLStreamProvider streamProvider = viewContext.getURLStreamProvider();
-    Map<String, String> newHeaders = getHeaders(headers);
-    newHeaders.put(USER_NAME_HEADER, USER_OOZIE_SUPER);
-
-    newHeaders.put(DO_AS_HEADER, viewContext.getUsername());
-    newHeaders.put("Accept", MediaType.APPLICATION_JSON);
-    if (customHeaders != null) {
-      newHeaders.putAll(customHeaders);
-    }
-    LOGGER.info(String.format("Proxy request for url: [%s] %s", method,
-      urlToRead));
-    boolean securityEnabled = isSecurityEnabled();
-    LOGGER.debug(String.format("IS security enabled:[%b]", securityEnabled));
-    InputStream stream = null;
-    try {
-      if (securityEnabled) {
-        stream = streamProvider.readAsCurrent(urlToRead, method, body, newHeaders);
-
-      } else {
-        stream = streamProvider.readFrom(urlToRead, method, body, newHeaders);
-      }
-    } catch (IOException e) {
-      LOGGER.error("error talking to oozie", e);
-      throw new RuntimeException(e);
-    }
-    return stream;
-  }
-
-  public Response consumeService(HttpHeaders headers, String urlToRead,
-                                 String method, String body) throws Exception {
-    return consumeService(headers, urlToRead, method, body, null);
-  }
-
-  public Map<String, String> getHeaders(HttpHeaders headers) {
-    MultivaluedMap<String, String> requestHeaders = headers.getRequestHeaders();
-    Set<Entry<String, List<String>>> headerEntrySet = requestHeaders.entrySet();
-    HashMap<String, String> headersMap = new HashMap<String, String>();
-    for (Entry<String, List<String>> headerEntry : headerEntrySet) {
-      String key = headerEntry.getKey();
-      List<String> values = headerEntry.getValue();
-      headersMap.put(key, strJoin(values, ","));
-    }
-    return headersMap;
-  }
-
-  public String strJoin(List<String> strings, String separator) {
-    StringBuilder stringBuilder = new StringBuilder();
-    for (int i = 0, il = strings.size(); i < il; i++) {
-      if (i > 0) {
-        stringBuilder.append(separator);
-      }
-      stringBuilder.append(strings.get(i));
-    }
-    return stringBuilder.toString();
-  }
-
-  private MediaType deduceType(String stringResponse) {
-    if (stringResponse.startsWith("{")) {
-      return MediaType.APPLICATION_JSON_TYPE;
-    } else if (stringResponse.startsWith("<")) {
-      return MediaType.TEXT_XML_TYPE;
-    } else {
-      return MediaType.APPLICATION_JSON_TYPE;
-    }
-  }
-
-  private HdfsApi getHdfsgetApi() {
-    if (_hdfsApi == null) {
-      try {
-        _hdfsApi = HdfsUtil.connectToHDFSApi(viewContext);
-      } catch (Exception ex) {
-        LOGGER.error("Error in getting HDFS Api", ex);
-        throw new RuntimeException("HdfsApi connection failed. Check \"webhdfs.url\" property", ex);
-      }
-    }
-    return _hdfsApi;
-  }
-
-  private String generateConigXml(Map<String, String> map) {
-    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
-    DocumentBuilder db;
-    try {
-      db = dbf.newDocumentBuilder();
-      Document doc = db.newDocument();
-      Element configElement = doc.createElement("configuration");
-      doc.appendChild(configElement);
-      for (Map.Entry<String, String> entry : map.entrySet()) {
-        Element propElement = doc.createElement("property");
-        configElement.appendChild(propElement);
-        Element nameElem = doc.createElement("name");
-        nameElem.setTextContent(entry.getKey());
-        Element valueElem = doc.createElement("value");
-        valueElem.setTextContent(entry.getValue());
-        propElement.appendChild(nameElem);
-        propElement.appendChild(valueElem);
-      }
-      DOMSource domSource = new DOMSource(doc);
-      StringWriter writer = new StringWriter();
-      StreamResult result = new StreamResult(writer);
-      TransformerFactory tf = TransformerFactory.newInstance();
-      Transformer transformer = tf.newTransformer();
-      transformer.setOutputProperty(OutputKeys.INDENT, "yes");
-      transformer
-        .setOutputProperty(XML_INDENT_AMT_PROP_NAME, XML_INDENT_SPACES);
-      transformer.transform(domSource, result);
-      return writer.toString();
-    } catch (ParserConfigurationException | TransformerException e) {
-      LOGGER.error("error in generating config xml", e);
-      throw new RuntimeException(e);
-    }
-
-  }
-
-  private String formatXml(String xml) {
-    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
-    try {
-      DocumentBuilder db = dbf.newDocumentBuilder();
-      StreamResult result = new StreamResult(new StringWriter());
-      Document document = db.parse(new InputSource(new StringReader(xml)));
-      Transformer transformer = TransformerFactory.newInstance()
-        .newTransformer();
-      transformer.setOutputProperty(OutputKeys.INDENT, "yes");
-      transformer
-        .setOutputProperty(XML_INDENT_AMT_PROP_NAME, XML_INDENT_SPACES);
-      DOMSource source = new DOMSource(document);
-      transformer.transform(source, result);
-      return result.getWriter().toString();
-    } catch (ParserConfigurationException | SAXException | IOException
-      | TransformerFactoryConfigurationError | TransformerException e) {
-      LOGGER.error("Error in formatting xml", e);
-      throw new RuntimeException(e);
-    }
-  }
-
-  private boolean isSecurityEnabled() {
-    boolean securityEnabled = Boolean.valueOf(getHadoopConfigs().get(
-      "security_enabled"));
-    return securityEnabled;
-  }
-
-  private Map<String, String> getHadoopConfigs() {
-    return viewContext.getInstanceData();
-  }
-
-}
+	private final static Logger LOGGER = LoggerFactory
+			.getLogger(OozieProxyImpersonator.class);
+
+	private static final String OOZIEPARAM_PREFIX = "oozieparam.";
+	private static final int OOZIEPARAM_PREFIX_LENGTH = OOZIEPARAM_PREFIX
+			.length();
+	private static final String EQUAL_SYMBOL = "=";
+	private static final String OOZIE_WF_RERUN_FAILNODES_CONF_KEY = "oozie.wf.rerun.failnodes";
+	private static final String OOZIE_USE_SYSTEM_LIBPATH_CONF_KEY = "oozie.use.system.libpath";
+
+	private ViewContext viewContext;
+
+	private static final String USER_NAME_HEADER = "user.name";
+	private static final String USER_OOZIE_SUPER = "oozie";
+	private static final String DO_AS_HEADER = "doAs";
+
+	private static final String SERVICE_URI_PROP = "oozie.service.uri";
+	private static final String DEFAULT_SERVICE_URI = "http://sandbox.hortonworks.com:11000/oozie";
+	private Utils utils=new Utils();
+	private OozieUtils oozieUtils=new OozieUtils();
+	private HDFSFileUtils hdfsFileUtils;
+	private static enum ErrorCodes {
+		OOZIE_SUBMIT_ERROR("error.oozie.submit", "Oozie Submit error"), OOZIE_IO_ERROR(
+				"error.oozie.io", "Oozie I/O error"), FILE_ACCESS_ACL_ERROR(
+				"error.file.access.control",
+				"Access Error to file due to access control"), FILE_ACCESS_UNKNOWN_ERROR(
+				"error.file.access", "Error accessing file"), WORKFLOW_PATH_EXISTS(
+				"error.workflow.path.exists", "Worfklow path exists");
+		private String errorCode;
+		private String description;
+
+		ErrorCodes(String errorCode, String description) {
+			this.errorCode = errorCode;
+			this.description = description;
+		}
+
+		public String getErrorCode() {
+			return errorCode;
+		}
+
+		public String getDescription() {
+			return description;
+		}
+	}
+
+	@Inject
+	public OozieProxyImpersonator(ViewContext viewContext) {
+		this.viewContext = viewContext;
+		hdfsFileUtils=new HDFSFileUtils(viewContext);
+		LOGGER.info(String.format(
+				"OozieProxyImpersonator initialized for instance: %s",
+				viewContext.getInstanceName()));
+	}
+
+	@Path("/fileServices")
+	public FileServices fileServices() {
+		return new FileServices(viewContext);
+	}
+
+	@GET
+	@Path("/getCurrentUserName")
+	public Response getCurrentUserName() {
+		return Response.ok(viewContext.getUsername()).build();
+	}
+
+	@POST
+	@Path("/submitJob")
+	@Consumes({ MediaType.TEXT_PLAIN + "," + MediaType.TEXT_XML })
+	public Response submitJob(String postBody, @Context HttpHeaders headers,
+			@Context UriInfo ui, @QueryParam("app.path") String appPath,
+			@DefaultValue("false") @QueryParam("overwrite") Boolean overwrite,
+			@QueryParam("jobType") String jobType) {
+		LOGGER.info("submit workflow job called");
+		return submitJobInternal(postBody, headers, ui, appPath, overwrite,
+				JobType.valueOf(jobType));
+	}
+
+	@POST
+	@Path("/submitWorkflow")
+	@Consumes({ MediaType.TEXT_PLAIN + "," + MediaType.TEXT_XML })
+	public Response submitWorkflow(String postBody,
+			@Context HttpHeaders headers, @Context UriInfo ui,
+			@QueryParam("app.path") String appPath,
+			@DefaultValue("false") @QueryParam("overwrite") Boolean overwrite) {
+		LOGGER.info("submit workflow job called");
+		return submitJobInternal(postBody, headers, ui, appPath, overwrite,
+				JobType.WORKFLOW);
+	}
+
+	@POST
+	@Path("/saveWorkflow")
+	@Consumes({ MediaType.TEXT_PLAIN + "," + MediaType.TEXT_XML })
+	public Response saveWorkflow(String postBody, @Context HttpHeaders headers,
+			@Context UriInfo ui, @QueryParam("app.path") String appPath,
+			@DefaultValue("false") @QueryParam("overwrite") Boolean overwrite) {
+		LOGGER.info("save workflow  called");
+		if (StringUtils.isEmpty(appPath)) {
+			throw new RuntimeException("app path can't be empty.");
+		}
+		appPath = appPath.trim();
+		if (!overwrite) {
+			boolean fileExists = hdfsFileUtils.fileExists(appPath);
+			if (fileExists) {
+				return getFileExistsResponse();
+			}
+		}
+		postBody = utils.formatXml(postBody);
+		try {
+			String filePath = hdfsFileUtils.createWorkflowFile(getWorkflowFileName(appPath),postBody, overwrite);
+			LOGGER.info(String.format(
+					"submit workflow job done. filePath=[%s]", filePath));
+			return Response.ok().build();
+		} catch (Exception ex) {
+			LOGGER.error(ex.getMessage(), ex);
+			return getRespCodeForException(ex);
+
+		}
+	}
+
+	private Response submitJobInternal(String postBody, HttpHeaders headers,
+			UriInfo ui, String appPath, Boolean overwrite, JobType jobType) {
+		if (StringUtils.isEmpty(appPath)) {
+			throw new RuntimeException("app path can't be empty.");
+		}
+		appPath = appPath.trim();
+		if (!overwrite) {
+			boolean fileExists = hdfsFileUtils.fileExists(appPath);
+			if (fileExists) {
+				return getFileExistsResponse();
+			}
+		}
+		postBody = utils.formatXml(postBody);
+		try {
+			String filePath = hdfsFileUtils.createWorkflowFile(getWorkflowFileName(appPath),postBody,overwrite);
+			LOGGER.info(String.format(
+					"submit workflow job done. filePath=[%s]", filePath));
+		} catch (Exception ex) {
+			LOGGER.error(ex.getMessage(), ex);
+			return getRespCodeForException(ex);
+
+		}
+		String response = submitWorkflowJobToOozie(headers, appPath,
+				ui.getQueryParameters(), jobType);
+		if (response != null && response.trim().startsWith("{")) {
+			// dealing with oozie giving error but with 200 response.
+			return Response.status(Response.Status.OK).entity(response).build();
+		} else {
+			HashMap<String, String> resp = new HashMap<String, String>();
+			resp.put("status", ErrorCodes.OOZIE_SUBMIT_ERROR.getErrorCode());
+			resp.put("message", response);
+			return Response.status(Response.Status.BAD_REQUEST).entity(resp)
+					.build();
+		}
+
+	}
+
+	private Response getRespCodeForException(Exception ex) {
+		if (ex instanceof AccessControlException) {
+			HashMap<String, String> errorDetails = getErrorDetails(
+					ErrorCodes.FILE_ACCESS_ACL_ERROR.getErrorCode(),
+					ErrorCodes.FILE_ACCESS_ACL_ERROR.getDescription(), ex);
+			return Response.status(Response.Status.BAD_REQUEST)
+					.entity(errorDetails).build();
+		}else if (ex instanceof IOException){
+			HashMap<String, String> errorDetails = getErrorDetails(
+					ErrorCodes.FILE_ACCESS_UNKNOWN_ERROR.getErrorCode(),
+					ErrorCodes.FILE_ACCESS_UNKNOWN_ERROR.getDescription(), ex);
+			return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
+					.entity(errorDetails).build();
+		}else {
+			HashMap<String, String> errorDetails = getErrorDetails(
+					ErrorCodes.FILE_ACCESS_UNKNOWN_ERROR.getErrorCode(),
+					ErrorCodes.FILE_ACCESS_UNKNOWN_ERROR.getDescription(), ex);
+			return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
+					.entity(errorDetails).build();
+		}
+		
+		
+	}
+
+	private Response getFileExistsResponse() {
+		HashMap<String, String> resp = new HashMap<String, String>();
+		resp.put("status", ErrorCodes.WORKFLOW_PATH_EXISTS.getErrorCode());
+		resp.put("message", ErrorCodes.WORKFLOW_PATH_EXISTS.getDescription());
+		return Response.status(Response.Status.BAD_REQUEST).entity(resp)
+				.build();
+	}
+
+	private String getWorkflowFileName(String appPath) {
+		String workflowFile = null;
+		if (appPath.endsWith(".xml")) {
+			workflowFile = appPath;
+		} else {
+			workflowFile = appPath + (appPath.endsWith("/") ? "" : "/")
+					+ "workflow.xml";
+		}
+		return workflowFile;
+	}
+
+	@GET
+	@Path("/readWorkflowXml")
+	public Response readWorkflowXxml(
+			@QueryParam("workflowXmlPath") String workflowPath) {
+		if (StringUtils.isEmpty(workflowPath)) {
+			throw new RuntimeException("workflowXmlPath can't be empty.");
+		}
+		try {
+			final FSDataInputStream is = hdfsFileUtils.read(workflowPath);
+			StreamingOutput streamer = new StreamingOutput() {
+				@Override
+				public void write(OutputStream os) throws IOException,
+						WebApplicationException {
+					IOUtils.copy(is, os);
+					is.close();
+					os.close();
+				}
+			};
+			return Response.ok(streamer).status(200).build();
+		} catch(IOException e){
+			return getRespCodeForException(e);
+		}
+	}
+
+	private HashMap<String, String> getErrorDetails(String status,
+			String message, Exception ex) {
+		HashMap<String, String> resp = new HashMap<String, String>();
+		resp.put("status", status);
+		if (message != null) {
+			resp.put("message", message);
+		}
+		if (ex != null) {
+			resp.put("stackTrace", ExceptionUtils.getFullStackTrace(ex));
+		}
+		return resp;
+	}
+
+	@GET
+	@Path("/getDag")
+	@Produces("image/png")
+	public Response submitWorkflow(@Context HttpHeaders headers,
+			@Context UriInfo ui, @QueryParam("jobid") String jobid) {
+		String imgUrl = getServiceUri() + "/v2/job/" + jobid + "?show=graph";
+		Map<String, String> newHeaders = utils.getHeaders(headers);
+		final InputStream is = readFromOozie(headers, imgUrl, HttpMethod.GET,
+				null, newHeaders);
+		StreamingOutput streamer = new StreamingOutput() {
+
+			@Override
+			public void write(OutputStream os) throws IOException,
+					WebApplicationException {
+				IOUtils.copy(is, os);
+				is.close();
+				os.close();
+			}
+
+		};
+		return Response.ok(streamer).status(200).build();
+	}
+
+	@GET
+	@Path("/{path: .*}")
+	public Response handleGet(@Context HttpHeaders headers, @Context UriInfo ui) {
+		try {
+			String serviceURI = buildURI(ui);
+			return consumeService(headers, serviceURI, HttpMethod.GET, null);
+		} catch (Exception ex) {
+			LOGGER.error("Error in GET proxy", ex);
+			return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
+					.entity(getErrorDetailsForException("Oozie", ex)).build();
+		}
+	}
+
+	@POST
+	@Path("/{path: .*}")
+	public Response handlePost(String xml, @Context HttpHeaders headers,
+			@Context UriInfo ui) {
+		try {
+			String serviceURI = buildURI(ui);
+			return consumeService(headers, serviceURI, HttpMethod.POST, xml);
+		} catch (Exception ex) {
+			LOGGER.error("Error in POST proxy", ex);
+			return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
+					.entity(getErrorDetailsForException("Oozie", ex)).build();
+		}
+	}
+
+	@DELETE
+	@Path("/{path: .*}")
+	public Response handleDelete(@Context HttpHeaders headers,
+			@Context UriInfo ui) {
+		try {
+			String serviceURI = buildURI(ui);
+			return consumeService(headers, serviceURI, HttpMethod.POST, null);
+		} catch (Exception ex) {
+			LOGGER.error("Error in DELETE proxy", ex);
+			return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
+					.entity(getErrorDetailsForException("Oozie", ex)).build();
+		}
+	}
+
+	@PUT
+	@Path("/{path: .*}")
+	public Response handlePut(String body, @Context HttpHeaders headers,
+			@Context UriInfo ui) {
+		try {
+			String serviceURI = buildURI(ui);
+			return consumeService(headers, serviceURI, HttpMethod.PUT, body);
+		} catch (Exception ex) {
+			LOGGER.error("Error in PUT proxy", ex);
+			return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
+					.entity(getErrorDetailsForException("Oozie", ex)).build();
+		}
+	}
+
+	private Map<String, String> getErrorDetailsForException(String component,
+			Exception ex) {
+		String errorCode = component + "exception";
+		String errorMessage = component + " Exception";
+		if (ex instanceof RuntimeException) {
+			Throwable cause = ex.getCause();
+			if (cause instanceof IOException) {
+				errorCode = component + "io.exception";
+				errorMessage = component + "IO Exception";
+			}
+		}
+		return getErrorDetails(errorCode, errorMessage, ex);
+	}
+
+	private String submitWorkflowJobToOozie(HttpHeaders headers,
+			String filePath, MultivaluedMap<String, String> queryParams,
+			JobType jobType) {
+		String nameNode = "hdfs://"
+				+ viewContext.getCluster().getConfigurationValue("hdfs-site",
+						"dfs.namenode.rpc-address");
+
+		if (!queryParams.containsKey("config.nameNode")) {
+			ArrayList<String> nameNodes = new ArrayList<String>();
+			LOGGER.info("Namenode===" + nameNode);
+			nameNodes.add(nameNode);
+			queryParams.put("config.nameNode", nameNodes);
+		}
+
+		HashMap<String, String> workflowConigs = getWorkflowConfigs(filePath,
+				queryParams, jobType, nameNode);
+		String configXMl = oozieUtils.generateConfigXml(workflowConigs);
+		LOGGER.info("Config xml==" + configXMl);
+		HashMap<String, String> customHeaders = new HashMap<String, String>();
+		customHeaders.put("Content-Type", "application/xml;charset=UTF-8");
+		Response serviceResponse = consumeService(headers, getServiceUri()
+				+ "/v2/jobs?" + getJobSumbitOozieParams(queryParams),
+				HttpMethod.POST, configXMl, customHeaders);
+
+		LOGGER.info("REsp from oozie status entity=="
+				+ serviceResponse.getEntity());
+		if (serviceResponse.getEntity() instanceof String) {
+			return (String) serviceResponse.getEntity();
+		} else {
+			return "success";
+		}
+
+	}
+
+	private HashMap<String, String> getWorkflowConfigs(String filePath,
+			MultivaluedMap<String, String> queryParams, JobType jobType,
+			String nameNode) {
+		HashMap<String, String> workflowConigs = new HashMap<String, String>();
+		if (queryParams.containsKey("resourceManager")
+				&& "useDefault".equals(queryParams.getFirst("resourceManager"))) {
+			String jobTrackerNode = viewContext.getCluster()
+					.getConfigurationValue("yarn-site",
+							"yarn.resourcemanager.address");
+			LOGGER.info("jobTrackerNode===" + jobTrackerNode);
+			workflowConigs.put("resourceManager", jobTrackerNode);
+			workflowConigs.put("jobTracker", jobTrackerNode);
+		}
+		if (queryParams != null) {
+			for (Map.Entry<String, List<String>> entry : queryParams.entrySet()) {
+				if (entry.getKey().startsWith("config.")) {
+					if (entry.getValue() != null && entry.getValue().size() > 0) {
+						workflowConigs.put(entry.getKey().substring(7), entry
+								.getValue().get(0));
+					}
+				}
+			}
+		}
+
+		if (queryParams.containsKey("oozieconfig.useSystemLibPath")) {
+			String useSystemLibPath = queryParams
+					.getFirst("oozieconfig.useSystemLibPath");
+			workflowConigs.put(OOZIE_USE_SYSTEM_LIBPATH_CONF_KEY,
+					useSystemLibPath);
+		} else {
+			workflowConigs.put(OOZIE_USE_SYSTEM_LIBPATH_CONF_KEY, "true");
+		}
+		if (queryParams.containsKey("oozieconfig.rerunOnFailure")) {
+			String rerunFailnodes = queryParams
+					.getFirst("oozieconfig.rerunOnFailure");
+			workflowConigs.put(OOZIE_WF_RERUN_FAILNODES_CONF_KEY,
+					rerunFailnodes);
+		} else {
+			workflowConigs.put(OOZIE_WF_RERUN_FAILNODES_CONF_KEY, "true");
+		}
+		workflowConigs.put("user.name", viewContext.getUsername());
+		workflowConigs.put(oozieUtils.getJobPathPropertyKey(jobType), nameNode + filePath);
+		return workflowConigs;
+	}
+
+	private String getJobSumbitOozieParams(
+			MultivaluedMap<String, String> queryParams) {
+		StringBuilder query = new StringBuilder();
+		if (queryParams != null) {
+			for (Map.Entry<String, List<String>> entry : queryParams.entrySet()) {
+				if (entry.getKey().startsWith(OOZIEPARAM_PREFIX)) {
+					if (entry.getValue() != null && entry.getValue().size() > 0) {
+						for (String val : entry.getValue()) {
+							query.append(
+									entry.getKey().substring(
+											OOZIEPARAM_PREFIX_LENGTH))
+									.append(EQUAL_SYMBOL).append(val)
+									.append("&");
+						}
+					}
+				}
+			}
+		}
+		return query.toString();
+	}
+
+	private String buildURI(UriInfo ui) {
+		String uiURI = ui.getAbsolutePath().getPath();
+		int index = uiURI.indexOf("proxy/") + 5;
+		uiURI = uiURI.substring(index);
+		String serviceURI = getServiceUri();
+		serviceURI += uiURI;
+		MultivaluedMap<String, String> params = addOrReplaceUserName(ui.getQueryParameters());
+		return serviceURI+utils.convertParamsToUrl(params);
+	}
+	private MultivaluedMap<String, String> addOrReplaceUserName(MultivaluedMap<String, String> parameters){
+		for (Map.Entry<String, List<String>> entry : parameters.entrySet()) {
+			if ("user.name".equals(entry.getKey())) {
+				ArrayList<String> vals = new ArrayList<String>(1);
+				vals.add(viewContext.getUsername());
+				entry.setValue(vals);
+			}
+		}
+		return parameters;
+	}
+
+	private String getServiceUri() {
+		String serviceURI = viewContext.getProperties().get(SERVICE_URI_PROP) != null ? viewContext
+				.getProperties().get(SERVICE_URI_PROP) : DEFAULT_SERVICE_URI;
+		return serviceURI;
+	}
+
+	private Response consumeService(HttpHeaders headers, String urlToRead,
+			String method, String body) throws Exception {
+		return consumeService(headers, urlToRead, method, body, null);
+	}
+	
+	private Response consumeService(HttpHeaders headers, String urlToRead,
+			String method, String body, Map<String, String> customHeaders) {
+		Response response = null;
+		InputStream stream = readFromOozie(headers, urlToRead, method, body,
+				customHeaders);
+		String stringResponse = null;
+		try {
+			stringResponse = IOUtils.toString(stream);
+		} catch (IOException e) {
+			LOGGER.error("Error while converting stream to string", e);
+			throw new RuntimeException(e);
+		}
+		if (stringResponse.contains(Response.Status.BAD_REQUEST.name())) {
+			response = Response.status(Response.Status.BAD_REQUEST)
+					.entity(stringResponse).type(MediaType.TEXT_PLAIN).build();
+		} else {
+			response = Response.status(Response.Status.OK)
+					.entity(stringResponse).type(utils.deduceType(stringResponse))
+					.build();
+		}
+		return response;
+	}
+
+	private InputStream readFromOozie(HttpHeaders headers, String urlToRead,
+			String method, String body, Map<String, String> customHeaders) {
+
+		Map<String, String> newHeaders = utils.getHeaders(headers);
+		newHeaders.put(USER_NAME_HEADER, USER_OOZIE_SUPER);
+
+		newHeaders.put(DO_AS_HEADER, viewContext.getUsername());
+		newHeaders.put("Accept", MediaType.APPLICATION_JSON);
+		if (customHeaders != null) {
+			newHeaders.putAll(customHeaders);
+		}
+		LOGGER.info(String.format("Proxy request for url: [%s] %s", method,
+				urlToRead));
+		
+		return readFromUrl(urlToRead, method, body, newHeaders);
+	}
+
+	private InputStream readFromUrl(String urlToRead, String method, String body,
+			Map<String, String> newHeaders) {
+		URLStreamProvider streamProvider = viewContext.getURLStreamProvider();
+		InputStream stream = null;
+		try {
+			if (isSecurityEnabled()) {
+				stream = streamProvider.readAsCurrent(urlToRead, method, body,
+						newHeaders);
+
+			} else {
+				stream = streamProvider.readFrom(urlToRead, method, body,
+						newHeaders);
+			}
+		} catch (IOException e) {
+			LOGGER.error("error talking to oozie", e);
+			throw new RuntimeException(e);
+		}
+		return stream;
+	}
+
+	
+	private boolean isSecurityEnabled() {
+		String authType = viewContext.getCluster().getConfigurationValue(
+				"core-site", "hadoop.security.authentication");
+		LOGGER.info("Auth Type=" + authType);
+		return !"simple".equalsIgnoreCase(authType);
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieUtils.java
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieUtils.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieUtils.java
new file mode 100644
index 0000000..170132f
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieUtils.java
@@ -0,0 +1,71 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.
+ */
+package org.apache.oozie.ambari.view;
+
+import java.util.Map;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class OozieUtils {
+	private final static Logger LOGGER = LoggerFactory
+			.getLogger(OozieUtils.class);
+	private Utils utils = new Utils();
+
+	public String generateConfigXml(Map<String, String> map) {
+		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+		DocumentBuilder db;
+		try {
+			db = dbf.newDocumentBuilder();
+			Document doc = db.newDocument();
+			Element configElement = doc.createElement("configuration");
+			doc.appendChild(configElement);
+			for (Map.Entry<String, String> entry : map.entrySet()) {
+				Element propElement = doc.createElement("property");
+				configElement.appendChild(propElement);
+				Element nameElem = doc.createElement("name");
+				nameElem.setTextContent(entry.getKey());
+				Element valueElem = doc.createElement("value");
+				valueElem.setTextContent(entry.getValue());
+				propElement.appendChild(nameElem);
+				propElement.appendChild(valueElem);
+			}
+			return utils.generateXml(doc);
+		} catch (ParserConfigurationException e) {
+			LOGGER.error("error in generating config xml", e);
+			throw new RuntimeException(e);
+		}
+	}
+	public String getJobPathPropertyKey(JobType jobType) {
+		switch (jobType) {
+		case WORKFLOW:
+			return "oozie.wf.application.path";
+		case COORDINATOR:
+			return "oozie.coord.application.path";
+		case BUNDLE:
+			return "oozie.bundle.application.path";
+		}
+		throw new RuntimeException("Unknown Job Type");
+	}
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/Utils.java
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/Utils.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/Utils.java
new file mode 100644
index 0000000..61d878e
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/Utils.java
@@ -0,0 +1,154 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.
+ */
+package org.apache.oozie.ambari.view;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+public class Utils {
+	private static final String XML_INDENT_SPACES = "4";
+	private static final String XML_INDENT_AMT_PROP_NAME = "{http://xml.apache.org/xslt}indent-amount";
+	private final static Logger LOGGER = LoggerFactory
+			.getLogger(Utils.class);
+	public String formatXml(String xml) {
+		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+		try {
+			DocumentBuilder db = dbf.newDocumentBuilder();
+			StreamResult result = new StreamResult(new StringWriter());
+			Document document = db
+					.parse(new InputSource(new StringReader(xml)));
+			Transformer transformer = TransformerFactory.newInstance()
+					.newTransformer();
+			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+			transformer.setOutputProperty(XML_INDENT_AMT_PROP_NAME,
+					XML_INDENT_SPACES);
+			DOMSource source = new DOMSource(document);
+			transformer.transform(source, result);
+			return result.getWriter().toString();
+		} catch (ParserConfigurationException | SAXException | IOException
+				| TransformerFactoryConfigurationError | TransformerException e) {
+			LOGGER.error("Error in formatting xml", e);
+			throw new RuntimeException(e);
+		}
+	}
+	public String generateXml(Document doc){
+		DOMSource domSource = new DOMSource(doc);
+		StringWriter writer = new StringWriter();
+		StreamResult result = new StreamResult(writer);
+		TransformerFactory tf = TransformerFactory.newInstance();
+		Transformer transformer;
+		try {
+			transformer = tf.newTransformer();
+			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+			transformer.setOutputProperty(XML_INDENT_AMT_PROP_NAME,
+					XML_INDENT_SPACES);
+			try {
+				transformer.transform(domSource, result);
+			} catch (TransformerException e) {
+				throw new RuntimeException(e);
+			}
+			return writer.toString();
+		} catch (TransformerConfigurationException tce) {
+			throw new RuntimeException(tce);
+		}
+		
+	}
+
+	public Map<String, String> getHeaders(HttpHeaders headers) {
+		MultivaluedMap<String, String> requestHeaders = headers
+				.getRequestHeaders();
+		Set<Entry<String, List<String>>> headerEntrySet = requestHeaders
+				.entrySet();
+		HashMap<String, String> headersMap = new HashMap<String, String>();
+		for (Entry<String, List<String>> headerEntry : headerEntrySet) {
+			String key = headerEntry.getKey();
+			List<String> values = headerEntry.getValue();
+			headersMap.put(key, strJoin(values, ","));
+		}
+		return headersMap;
+	}
+
+	public String strJoin(List<String> strings, String separator) {
+		StringBuilder stringBuilder = new StringBuilder();
+		for (int i = 0, il = strings.size(); i < il; i++) {
+			if (i > 0) {
+				stringBuilder.append(separator);
+			}
+			stringBuilder.append(strings.get(i));
+		}
+		return stringBuilder.toString();
+	}
+	public MediaType deduceType(String stringResponse) {
+		if (stringResponse.startsWith("{")) {
+			return MediaType.APPLICATION_JSON_TYPE;
+		} else if (stringResponse.startsWith("<")) {
+			return MediaType.TEXT_XML_TYPE;
+		} else {
+			return MediaType.APPLICATION_JSON_TYPE;
+		}
+	}
+
+	public String convertParamsToUrl(MultivaluedMap<String, String> parameters) {
+		StringBuilder urlBuilder = new StringBuilder();
+		boolean firstEntry = true;
+		for (Map.Entry<String, List<String>> entry : parameters.entrySet()) {
+			if (firstEntry) {
+				urlBuilder.append("?");
+			} else {
+				urlBuilder.append("&");
+			}
+			boolean firstVal = true;
+			for (String val : entry.getValue()) {
+				urlBuilder.append(firstVal ? "" : "&").append(entry.getKey())
+						.append("=").append(val);
+				firstVal = false;
+			}
+			firstEntry = false;
+		}
+		return urlBuilder.toString();
+	}
+
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/.jshintrc
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/.jshintrc b/contrib/views/wfmanager/src/main/resources/ui/.jshintrc
new file mode 100644
index 0000000..ed9a144
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/.jshintrc
@@ -0,0 +1,38 @@
+{
+  "predef": [
+    "document",
+    "window",
+    "-Promise",
+	"vkbeautify",
+	"moment",
+	"X2JS",
+	"jsPlumb",
+	"cytoscape",
+	"dagre"
+  ],
+  "browser": true,
+  "boss": true,
+  "curly": true,
+  "debug": false,
+  "devel": true,
+  "eqeqeq": true,
+  "evil": true,
+  "forin": false,
+  "immed": false,
+  "laxbreak": false,
+  "newcap": true,
+  "noarg": true,
+  "noempty": false,
+  "nonew": false,
+  "nomen": false,
+  "onevar": false,
+  "plusplus": false,
+  "regexp": false,
+  "undef": true,
+  "sub": true,
+  "strict": false,
+  "white": false,
+  "eqnull": true,
+  "esnext": true,
+  "unused": true
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/.gitkeep b/contrib/views/wfmanager/src/main/resources/ui/app/components/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/archive-config.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/archive-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/archive-config.js
index d53b459..7ea46c4 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/archive-config.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/archive-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({
   fileBrowser : Ember.inject.service('file-browser'),
   initialize : function(){
     this.on('fileSelected',function(fileName){

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js
new file mode 100644
index 0000000..2799db5
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js
@@ -0,0 +1,262 @@
+/*
+*    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 {Bundle} from '../domain/bundle/bundle';
+import {BundleGenerator} from '../domain/bundle/bundle-xml-generator';
+import {BundleXmlImporter} from '../domain/bundle/bundle-xml-importer';
+import { validator, buildValidations } from 'ember-cp-validations';
+import Constants from '../utils/constants';
+
+const Validations = buildValidations({
+  'bundle.name': validator('presence', {
+    presence : true
+  }),
+  'bundle.coordinators': {
+    validators: [
+      validator('operand-length', {
+        min : 1,
+        dependentKeys: ['bundle','bundle.coordinators.[]'],
+        message : 'Alteast one coordinator is required',
+        disabled(model, attribute) {
+          return !model.get('bundle');
+        }
+      })
+    ]
+  }
+});
+
+export default Ember.Component.extend(Ember.Evented, Validations, {
+  bundle : null,
+  propertyExtractor : Ember.inject.service('property-extractor'),
+  fileBrowser : Ember.inject.service('file-browser'),
+  workspaceManager : Ember.inject.service('workspace-manager'),
+  initialize : function(){
+    var draftBundle = this.get('workspaceManager').restoreWorkInProgress(this.get('tabInfo.id'));
+    if(draftBundle){
+      this.set('bundle', JSON.parse(draftBundle));
+    }else{
+      this.set('bundle', this.createBundle());
+    }
+    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));
+    if(Ember.isBlank(this.get('bundle.name'))){
+      this.set('bundle.name', Ember.copy(this.get('tabInfo.name')));
+    }
+    this.set('showErrorMessage', false);
+    this.schedulePersistWorkInProgress();
+  }.on('init'),
+  onDestroy : function(){
+    Ember.run.cancel(this.schedulePersistWorkInProgress);
+    this.persistWorkInProgress();
+  }.on('willDestroyElement'),
+  observeFilePath : Ember.observer('bundleFilePath', function(){
+    if(!this.get('bundleFilePath') || null === this.get('bundleFilePath')){
+      return;
+    }else{
+      this.sendAction('changeFilePath', this.get('tabInfo'), this.get('bundleFilePath'));
+    }
+  }),
+  nameObserver : Ember.observer('bundle.name', function(){
+    if(!this.get('bundle')){
+      return;
+    }else if(this.get('bundle') && Ember.isBlank(this.get('bundle.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('bundle.name'));
+    }
+  }),
+  schedulePersistWorkInProgress (){
+    Ember.run.later(function(){
+      this.persistWorkInProgress();
+      this.schedulePersistWorkInProgress();
+    }.bind(this), Constants.persistWorkInProgressInterval);
+  },
+  persistWorkInProgress (){
+    if(!this.get('bundle')){
+      return;
+    }
+    var json = JSON.stringify(this.get("bundle"));
+    this.get('workspaceManager').saveWorkInProgress(this.get('tabInfo.id'), json);
+  },
+  createBundle (){
+    return Bundle.create({
+      name : '',
+      kickOffTime : {
+        value : '',
+        displayValue : '',
+        type : 'date'
+      },
+      coordinators : null
+    });
+  },
+  importSampleBundle (){
+    var deferred = Ember.RSVP.defer();
+    Ember.$.ajax({
+      url: "/sampledata/bundle.xml",
+      dataType: "text",
+      cache:false,
+      success: function(data) {
+        deferred.resolve(data);
+      }.bind(this),
+      failure : function(data){
+        deferred.reject(data);
+      }
+    });
+    return deferred;
+  },
+  importBundle (filePath){
+    this.set("bundleFilePath", filePath);
+    this.set("isImporting", false);
+    var deferred = this.getBundleFromHdfs(filePath);
+    deferred.promise.then(function(data){
+      this.getBundleFromXml(data);
+      this.set("isImporting", false);
+    }.bind(this)).catch(function(){
+      this.set("isImporting", false);
+      this.set("isImportingSuccess", false);
+    }.bind(this));
+  },
+  getBundleFromHdfs(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;
+  },
+  getBundleFromXml(bundleXml){
+    var bundleXmlImporter = BundleXmlImporter.create({});
+    var bundle = bundleXmlImporter.importBundle(bundleXml);
+    this.set("bundle", bundle);
+  },
+  actions : {
+    closeFileBrowser(){
+      this.set("showingFileBrowser", false);
+      this.get('fileBrowser').getContext().trigger('fileSelected', this.get('filePath'));
+      if(this.get('bundleFilePath')){
+        this.importBundle(Ember.copy(this.get('bundleFilePath')));
+        this.set('bundleFilePath', null);
+      }
+    },
+    openFileBrowser(model, context){
+      if(!context){
+        context = this;
+      }
+      this.get('fileBrowser').trigger('fileBrowserOpened',context);
+      this.set('filePathModel', model);
+      this.set('showingFileBrowser', true);
+    },
+    createCoordinator(){
+      this.set('coordinatorEditMode', false);
+      this.set('coordinatorCreateMode', true);
+      this.set('currentCoordinator',{
+        name : undefined,
+        appPath : undefined,
+        configuration : {
+          property : Ember.A([])
+        }
+      });
+    },
+    editCoordinator(index){
+      this.set('coordinatorEditMode', true);
+      this.set('coordinatorCreateMode', false);
+      this.set('currentCoordinatorIndex', index);
+      this.set('currentCoordinator', Ember.copy(this.get('bundle.coordinators').objectAt(index)));
+    },
+    addCoordinator(){
+      if(!this.get('bundle.coordinators')){
+        this.set('bundle.coordinators', Ember.A([]));
+      }
+      this.get('bundle.coordinators').pushObject(Ember.copy(this.get('currentCoordinator')));
+      this.set('coordinatorCreateMode', false);
+    },
+    updateCoordinator(){
+      this.get('bundle.coordinators').replace(this.get('currentCoordinatorIndex'), 1, Ember.copy(this.get('currentCoordinator')));
+      this.set('coordinatorEditMode', false);
+    },
+    deleteCoordinator(index){
+      this.get('bundle.coordinators').removeAt(index);
+      if(index === this.get('currentCoordinatorIndex')){
+        this.set('coordinatorEditMode', false);
+      }
+    },
+    cancelCoordinatorOperation(){
+      this.set('coordinatorCreateMode', false);
+      this.set('coordinatorEditMode', false);
+    },
+    confirmReset(){
+      this.set('showingResetConfirmation', true);
+    },
+    resetBundle(){
+      this.set('bundle', this.createBundle());
+    },
+    closeBundleSubmitConfig(){
+      this.set("showingJobConfig", false);
+    },
+    submitBundle(){
+      if(this.get('validations.isInvalid')) {
+        this.set('showErrorMessage', true);
+        return;
+      }
+      var bundleGenerator = BundleGenerator.create({bundle:this.get("bundle")});
+      var bundleXml = bundleGenerator.process();
+      var dynamicProperties = this.get('propertyExtractor').getDynamicProperties(bundleXml);
+      var configForSubmit = {props : dynamicProperties, xml : bundleXml, params : this.get('bundle.parameters')};
+      this.set("bundleConfigs", configForSubmit);
+      this.set("showingJobConfig", true);
+    },
+    preview(){
+      if(this.get('validations.isInvalid')) {
+        this.set('showErrorMessage', true);
+        return;
+      }
+      this.set("showingPreview", false);
+      var bundleGenerator = BundleGenerator.create({bundle:this.get("bundle")});
+      var bundleXml = bundleGenerator.process();
+      this.set("previewXml", vkbeautify.xml(bundleXml));
+      this.set("showingPreview", true);
+    },
+    importBundleTest(){
+      var deferred = this.importSampleBundle();
+      deferred.promise.then(function(data){
+        this.getBundleFromXml(data);
+      }.bind(this)).catch(function(e){
+        throw new Error(e);
+      });
+    },
+    openTab(type, path){
+      this.sendAction('openTab', type, path);
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-coord-config.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-coord-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-coord-config.js
new file mode 100644
index 0000000..229b2cc
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-coord-config.js
@@ -0,0 +1,108 @@
+/*
+*    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({
+  'coordinator.name': validator('presence', {
+    presence : true
+  }),
+  'coordinator.appPath': validator('presence', {
+    presence : true
+  })
+});
+export default Ember.Component.extend(Validations, {
+  initialize : function(){
+    this.on('fileSelected',function(fileName){
+      this.set(this.get('filePathModel'), fileName);
+    }.bind(this));
+    this.set('showErrorMessage', false);
+  }.on('init'),
+  isValid(){
+      if(this.get('validations.isInvalid')) {
+        this.set('showErrorMessage', true);
+        return false;
+      }
+      return true;
+  },
+  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;
+  },
+  importSampleCoordinator (){
+    var deferred = Ember.RSVP.defer();
+    Ember.$.ajax({
+      url: "/sampledata/coordinator.xml",
+      dataType: "text",
+      cache:false,
+      success: function(data) {
+        deferred.resolve(data);
+      }.bind(this),
+      failure : function(data){
+        deferred.reject(data);
+      }
+    });
+    return deferred;
+  },
+  actions : {
+    openFileBrowser(model){
+      this.set('filePathModel', model);
+      this.sendAction("openFileBrowser", model, this);
+    },
+    addCoordinator(){
+      if(this.isValid()){
+        this.sendAction('add');
+      }
+    },
+    updateCoordinator(){
+      if(this.isValid()){
+        this.sendAction('update');
+      }
+    },
+    cancelCoordinatorOperation(){
+      this.sendAction('cancel');
+    },
+    openTab(type, path){
+      this.sendAction('openTab', type, path);
+    },
+    showCoordinatorName(){
+      this.set('coordinatorName', null);
+      var deferred = this.readFromHdfs(this.get('coordinator.appPath'));
+      deferred.promise.then(function(data){
+        var x2js = new X2JS();
+        var coordJson = x2js.xml_str2json(data);
+        this.set('coordinatorName', coordJson["coordinator-app"]._name);
+      }.bind(this)).catch(function(){
+        this.set('coordinatorName', null);
+      }.bind(this));
+    }
+  }
+});


[07/10] ambari git commit: AMBARI-18691. Improve and Update Workflow designer to support coordinators and bundles. (Belliraj HB via dipayanb)

Posted by db...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/map-reduce-action-info.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/map-reduce-action-info.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/map-reduce-action-info.js
new file mode 100644
index 0000000..3192c72
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/map-reduce-action-info.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 : {    
+	  hideNotification(){
+       	  this.sendAction("hideNotification");
+	  }
+   }
+});
+ 
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/name-value-config.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/name-value-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/name-value-config.js
index 45dea7a..ae453a0 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/name-value-config.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/name-value-config.js
@@ -33,9 +33,12 @@ export default Ember.Component.extend({
     }
   }.on('willDestroyElement'),
   addProperty (){
+    alert(this.get("validations"));
     this.get('configuration.property').pushObject({name:this.get('propertyName'),value:this.get('propertyValue')});
-    this.set('propertyName', "");
-    this.set('propertyValue', "");
+    //if(this.get("doNotInitialize")){
+      this.set('propertyName', "");
+      this.set('propertyValue', "");
+    //}
   },
   actions : {
     addProperty () {

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/name-value-info.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/name-value-info.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/name-value-info.js
new file mode 100644
index 0000000..7a7c38d
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/name-value-info.js
@@ -0,0 +1,21 @@
+/*
+*    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({
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/named-properties.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/named-properties.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/named-properties.js
index 067d643..f235018 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/named-properties.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/named-properties.js
@@ -15,18 +15,25 @@
 *    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({
+  'property.value': validator('presence', {
+    presence : true,
+    disabled(model){
+      return !model.get('required');
+    },
+    message : 'Required'
+  })
+});
+
+export default Ember.Component.extend(Validations, {
   initialize : function () {
     this.sendAction('register', this, this);
   }.on('init'),
-  validations : {
-    'property.value': {
-      presence: {
-        'if' :'required',
-        'message' : 'Required'
-      }
+  onDestroy : function () {
+    if(this.get('unregisterRequired')){
+      this.sendAction('unregister', this, this);
     }
-  }
+  }.on('willDestroyElement')
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/pig-action-info.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/pig-action-info.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/pig-action-info.js
new file mode 100644
index 0000000..3192c72
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/pig-action-info.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 : {    
+	  hideNotification(){
+       	  this.sendAction("hideNotification");
+	  }
+   }
+});
+ 
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/pig-action.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/pig-action.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/pig-action.js
index ee24871..be983a9 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/pig-action.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/pig-action.js
@@ -16,9 +16,14 @@
 */
 
 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.script': validator('presence', {
+    presence : true
+  })
+});
+export default Ember.Component.extend(Validations,{
   setUp : function(){
     if(this.get('actionModel.jobXml') === undefined){
       this.set("actionModel.jobXml", Ember.A([]));
@@ -54,13 +59,6 @@ export default Ember.Component.extend(EmberValidations,{
       this.$('#collapseOne').collapse('show');
     }
   }.on('didUpdate'),
-  validations : {
-    'actionModel.script': {
-      presence: {
-        'message' : 'You need to provide a value for Script',
-      }
-    }
-  },
   actions : {
     openFileBrowser(model, context){
       if(undefined === context){

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/prepare-config-fs.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/prepare-config-fs.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/prepare-config-fs.js
index 9437c25..3c425d9 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/prepare-config-fs.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/prepare-config-fs.js
@@ -15,9 +15,8 @@
 *    limitations under the License.
 */
 import Ember from 'ember';
-import EmberValidations from 'ember-validations';
 
-export default Ember.Component.extend(EmberValidations, {
+export default Ember.Component.extend({
   mkdirORdeleteORtouchz: true,
   mkdir: 1,
   delete: 0,
@@ -96,8 +95,8 @@ export default Ember.Component.extend(EmberValidations, {
       var gPerm = this.formPermissions(this.get("gread"), this.get("gwrite"), this.get("gexecute"), "g");
       var rPerm = this.formPermissions(this.get("rread"), this.get("rwrite"), this.get("rexecute"), "r");
       var permissionsObj = {};
-      permissionsObj = $.extend(true, oPerm, gPerm);
-      permissionsObj = $.extend(true, permissionsObj, rPerm);
+      permissionsObj = Ember.$.extend(true, oPerm, gPerm);
+      permissionsObj = Ember.$.extend(true, permissionsObj, rPerm);
       var perm = oPerm.operm + ""+ gPerm.gperm + ""+ rPerm.rperm;
       this.get('fsOps').pushObject({
         settings: {

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/prepare-config-info.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/prepare-config-info.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/prepare-config-info.js
new file mode 100644
index 0000000..7a7c38d
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/prepare-config-info.js
@@ -0,0 +1,21 @@
+/*
+*    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({
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/prepare-config.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/prepare-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/prepare-config.js
index 038428f..6bb2ee4 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/prepare-config.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/prepare-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,
   prepareType : 'mkdir',
   fileBrowser : Ember.inject.service('file-browser'),

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/preview-dialog.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/preview-dialog.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/preview-dialog.js
new file mode 100644
index 0000000..31f9df8
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/preview-dialog.js
@@ -0,0 +1,20 @@
+/*
+*    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({
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/property-value-config.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/property-value-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/property-value-config.js
new file mode 100644
index 0000000..7a7c38d
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/property-value-config.js
@@ -0,0 +1,21 @@
+/*
+*    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({
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/save-wf.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/save-wf.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/save-wf.js
new file mode 100644
index 0000000..b41f743
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/save-wf.js
@@ -0,0 +1,170 @@
+/*
+*    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 Constants from '../utils/constants';
+import { validator, buildValidations } from 'ember-cp-validations';
+
+const Validations = buildValidations({
+  'filePath': validator('presence', {
+    presence : true
+  })
+});
+
+
+export default Ember.Component.extend(Validations, {
+  showingFileBrowser : false,
+  jobXml : "",
+  overwritePath : false,
+  savingInProgress : false,
+  isStackTraceVisible: false,
+  isStackTraceAvailable: false,
+  alertType : "",
+  alertMessage : "",
+  alertDetails : "",
+  filePath : "",
+  showErrorMessage: false,
+  displayName : Ember.computed('type', function(){
+    if(this.get('type') === 'wf'){
+      return "Workflow";
+    }else if(this.get('type') === 'coord'){
+      return "Coordinator";
+    }else{
+      return "Bundle";
+    }
+  }),
+  initialize :function(){
+    this.set("jobXml", this.get("jobConfigs").xml);
+    this.set('filePath', Ember.copy(this.get('jobFilePath')));
+  }.on('init'),
+  rendered : function(){
+    this.$("#configureJob").on('hidden.bs.modal', function () {
+      this.sendAction('closeJobConfigs');
+    }.bind(this));
+    this.$("#configureJob").modal("show");    
+  }.on('didInsertElement'),
+  showNotification(data){
+    if (!data){
+      return;
+    }
+    if (data.type === "success"){
+      this.set("alertType", "success");
+    }
+    if (data.type === "error"){
+      this.set("alertType", "danger");
+    }
+    this.set("alertDetails", data.details);
+    this.set("alertMessage", data.message);
+    if(data.stackTrace.length){
+      this.set("stackTrace", data.stackTrace);
+      this.set("isStackTraceAvailable", true);
+    } else {
+      this.set("isStackTraceAvailable", false);
+    }
+  },
+  saveJob(){
+    var url = Ember.ENV.API_URL + "/saveWorkflow?app.path=" + this.get("filePath") + "&overwrite=" + this.get("overwritePath");
+    Ember.$.ajax({
+      url: url,
+      method: "POST",
+      dataType: "text",
+      contentType: "text/plain;charset=utf-8",
+      beforeSend: function(request) {
+        request.setRequestHeader("X-XSRF-HEADER", Math.round(Math.random()*100000));
+        request.setRequestHeader("X-Requested-By", "workflow-designer");
+      },
+      data: this.get("jobXml"),
+      success: function(response) {
+        //var result=JSON.parse(response);
+        this.showNotification({
+          "type": "success",
+          "message": "Workflow have been saved"
+        });
+        this.set("savingInProgress",false);
+      }.bind(this),
+      error: function(response) {
+        console.log(response);
+        this.set("savingInProgress",false);
+        this.set("isStackTraceVisible",true);
+        this.showNotification({
+          "type": "error",
+          "message": "Error occurred while saving "+ this.get('displayName').toLowerCase(),
+          "details": this.getParsedErrorResponse(response),
+          "stackTrace": this.getStackTrace(response.responseText)
+        });
+      }.bind(this)
+    });
+  },
+  getStackTrace(data){
+    if(data){
+     try{
+      var stackTraceMsg = JSON.parse(data).stackTrace;
+      if(!stackTraceMsg){
+        return "";
+      }
+     if(stackTraceMsg instanceof Array){
+       return stackTraceMsg.join("").replace(/\tat /g, '<br/>&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;');
+     } else {
+       return stackTraceMsg.replace(/\tat /g, '<br/>&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;');
+     }
+     } catch(err){
+       return "";
+     }
+    }
+    return "";
+  },
+  getParsedErrorResponse (response){
+    var detail;
+    if (response.responseText && response.responseText.charAt(0)==="{"){
+      var jsonResp=JSON.parse(response.responseText);
+      if (jsonResp.status==="workflow.oozie.error"){
+        detail="Oozie error. Please check the workflow.";
+      }else if(jsonResp.message && jsonResp.message.indexOf("<html>") > -1){
+        detail= "";
+      }else{
+        detail=jsonResp.message;
+      }
+    }else{
+      detail=response; 
+    }
+    return detail;
+  },
+  actions: {
+    selectFile(){
+      this.set("showingFileBrowser",true);
+    },
+    showStackTrace(){
+      this.set("isStackTraceVisible", true);
+    },
+    hideStackTrace(){
+      this.set("isStackTraceVisible", false);
+    },
+    closeFileBrowser(){
+      this.set("showingFileBrowser",false);
+    },
+    saveWorkflow(){
+		if(!this.get("validations.isInvalid")){
+	      this.sendAction("setFilePath", this.get("filePath"));
+	      this.set('showErrorMessage', true);
+	      this.saveJob();
+		}
+    },
+    closePreview(){
+      this.set("showingPreview",false);
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/shell-action-info.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/shell-action-info.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/shell-action-info.js
new file mode 100644
index 0000000..3192c72
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/shell-action-info.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 : {    
+	  hideNotification(){
+       	  this.sendAction("hideNotification");
+	  }
+   }
+});
+ 
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/shell-action.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/shell-action.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/shell-action.js
index a1445dc..e4e33dd 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/shell-action.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/shell-action.js
@@ -16,9 +16,18 @@
 */
 
 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.exec': validator('presence', {
+    presence : true
+  }),
+  'actionModel.jobTracker': validator('presence', {
+    presence : true
+  })  
+});
+
+export default Ember.Component.extend(Validations,{
   initialize : function(){
     this.sendAction('register','shellAction', this);
     this.on('fileSelected',function(fileName){
@@ -47,13 +56,6 @@ export default Ember.Component.extend(EmberValidations,{
       this.set("actionModel.configuration.property", Ember.A([]));
     }
   }.on('didInsertElement'),
-  validations : {
-    'actionModel.exec': {
-      presence: {
-        'message' : 'You need to provide a value for Exec'
-      }
-    }
-  },
   observeError :function(){
     if(this.$('#collapseOne label.text-danger').length > 0 && !this.$('#collapseOne').hasClass("in")){
       this.$('#collapseOne').collapse('show');

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/sla-info.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/sla-info.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/sla-info.js
index a1bad85..7390205 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/sla-info.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/sla-info.js
@@ -15,12 +15,92 @@
 *    limitations under the License.
 */
 import Ember from 'ember';
-import EmberValidations from 'ember-validations';
+import { validator, buildValidations } from 'ember-cp-validations';
+import { v1, v4 } from "ember-uuid";
 
-export default Ember.Component.extend(EmberValidations, {
+const Validations = buildValidations({
+  'nominalTime': {
+    validators: [
+      validator('presence', {
+        presence : true,
+        disabled(model, attribute) {
+          return !model.get('slaEnabled');
+        },
+        dependentKeys : ['slaEnabled']
+      }),
+      validator('date', {
+        disabled(model, attribute) {
+          return !model.get('slaEnabled');
+        },
+        format: 'MM/DD/YYYY hh:mm A',
+        dependentKeys : ['slaEnabled']
+      }),
+    ]
+  },
+  'slaInfo.shouldEnd.time': {
+    validators: [
+      validator('presence', {
+        presence : true,
+        disabled(model, attribute) {
+          return !model.get('slaEnabled');
+        },
+        dependentKeys : ['slaEnabled']
+      }),
+      validator('number', {
+        disabled(model) {
+          return !model.get('slaEnabled');
+        },
+        allowString : true,
+        allowBlank : true,
+        integer : true,
+        dependentKeys : ['slaEnabled']
+      }),
+    ]
+  },
+  'slaInfo.shouldStart.time': validator('number', {
+    disabled(model) {
+      return !model.get('slaEnabled');
+    },
+    allowString : true,
+    allowBlank : true,
+    integer : true,
+    dependentKeys : ['slaEnabled']
+  }),
+  'slaInfo.maxDuration.time': validator('number', {
+    disabled(model) {
+      return !model.get('slaEnabled');
+    },
+    allowString : true,
+    allowBlank : true,
+    integer : true,
+    dependentKeys : ['slaEnabled']
+  }),
+  'slaInfo.shouldStart.unit':validator('presence', {
+    presence : true,
+    disabled(model) {
+      return !model.get('slaEnabled') || !model.get('slaInfo.shouldStart.time');
+    },
+    dependentKeys : ['slaEnabled', 'slaInfo.shouldStart.time']
+  }),
+  'slaInfo.shouldEnd.unit':validator('presence', {
+    presence : true,
+    disabled(model) {
+      return !model.get('slaEnabled') || !model.get('slaInfo.shouldEnd.time');
+    },
+    dependentKeys : ['slaEnabled', 'slaInfo.shouldEnd.time']
+  }),
+  'slaInfo.maxDuration.unit':validator('presence', {
+    presence : true,
+    disabled(model) {
+      return !model.get('slaEnabled') || !model.get('slaInfo.maxDuration.time');
+    },
+    dependentKeys : ['slaEnabled', 'slaInfo.maxDuration.time']
+  })
+});
+
+export default Ember.Component.extend(Validations, {
   alertEvents: Ember.A([]),
   timeUnitOptions : Ember.A([]),
-  nominalTime : '',
   initialize : function(){
     this.set('alertEvents', Ember.A([]));
     this.get('alertEvents').pushObject({eventType:'start_miss', alertEnabled:false, displayName :'Start Miss'});
@@ -53,6 +133,7 @@ export default Ember.Component.extend(EmberValidations, {
       }
     }
     Ember.addObserver(this, 'nominalTime', this, this.nominalTimeObserver);
+    this.set('collapseId', v1());
   }.on('init'),
   alertEventsObserver : function(){
     var alerts = this.get('alertEvents').filterBy('alertEnabled',true).mapBy('eventType');
@@ -64,7 +145,7 @@ export default Ember.Component.extend(EmberValidations, {
     Ember.removeObserver(this, 'nominalTime', this, this.nominalTimeObserver);
   }.on('willDestroyElement'),
   elementsInserted : function() {
-    this.$('#nominalTime').datetimepicker({
+    this.$('input[name="nominalTime"]').datetimepicker({
       useCurrent: false,
       showClose : true,
       defaultDate : this.get('slaInfo.nominalTime')
@@ -78,65 +159,6 @@ export default Ember.Component.extend(EmberValidations, {
     var date = new Date(this.get('nominalTime'));
     this.set('slaInfo.nominalTime',moment(date).format("YYYY-MM-DDTHH:mm")+'Z');
   },
-  shouldEnd : Ember.computed.alias('slaInfo.shouldEnd'),
-  shouldStart : Ember.computed.alias('slaInfo.shouldStart'),
-  maxDuration : Ember.computed.alias('slaInfo.maxDuration'),
-  validations : {
-    'nominalTime': {
-      presence: {
-        'if': 'slaEnabled',
-        'message' : 'Required',
-      }
-    },
-    'shouldEnd.time': {
-      presence: {
-        'if': 'slaEnabled',
-        'message' : 'Required',
-      },
-      numericality: {
-        'if': 'slaEnabled',
-        onlyInteger: true,
-        greaterThan: 0,
-        'message' : 'Number Only'
-      }
-    },
-    'shouldStart.time': {
-      numericality: {
-        'if': 'slaEnabled',
-        allowBlank :true,
-        onlyInteger: true,
-        greaterThan: 0,
-        message : 'Number Only'
-      }
-    },
-    'maxDuration.time': {
-      numericality: {
-        'if': 'slaEnabled',
-        allowBlank :true,
-        onlyInteger: true,
-        greaterThan: 0,
-        message : 'Number Only'
-      }
-    },
-    'shouldStart.unit': {
-      presence: {
-        'if': 'shouldStart.time',
-        'message' : 'Required',
-      }
-    },
-    'shouldEnd.unit': {
-      presence: {
-        'if': 'slaEnabled',
-        'message' : 'Required',
-      }
-    },
-    'maxDuration.unit': {
-      presence: {
-        'if': 'maxDuration.time',
-        'message' : 'Required',
-      }
-    }
-  },
   slaObserver : function(){
     if(this.get('slaEnabled')){
       this.$('#slaCollapse').collapse('show');

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/spark-action-info.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/spark-action-info.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/spark-action-info.js
new file mode 100644
index 0000000..3192c72
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/spark-action-info.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 : {    
+	  hideNotification(){
+       	  this.sendAction("hideNotification");
+	  }
+   }
+});
+ 
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/spark-action.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/spark-action.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/spark-action.js
index 4cb74d8..1a778c4 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/spark-action.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/spark-action.js
@@ -16,10 +16,20 @@
 */
 
 import Ember from 'ember';
-import EmberValidations from 'ember-validations';
+import { validator, buildValidations } from 'ember-cp-validations';
 import Constants from '../utils/constants';
-
-export default Ember.Component.extend(EmberValidations,{
+const Validations = buildValidations({
+  'actionModel.master': validator('presence', {
+    presence : true
+  }),
+  'actionModel.jar': validator('presence', {
+    presence : true
+  }),
+  'actionModel.sparkName': validator('presence', {
+    presence : true
+  })    
+});
+export default Ember.Component.extend(Validations,{
   setup : function(){
     if(this.get('actionModel.jobXml') === undefined){
       this.set("actionModel.jobXml", Ember.A([]));
@@ -41,6 +51,7 @@ export default Ember.Component.extend(EmberValidations,{
       this.set("actionModel.configuration.property", Ember.A([]));
     }
     this.set('mastersList',Ember.copy(Constants.sparkMasterList));
+    this.set('isJar', this.get('actionModel.jar') && this.get('actionModel.jar').endsWith('.jar'));
     this.sendAction('register','sparkAction', this);
   }.on('init'),
   initialize : function(){
@@ -68,27 +79,27 @@ export default Ember.Component.extend(EmberValidations,{
       this.set('actionModel.class', undefined);
     }
   }),
-  validations : {
-    'actionModel.master': {
-      presence: {
-        'message' : 'You need to provide a value for Runs on (Master)'
-      }
-    },
-    'actionModel.jar': {
-      presence: {
-        'message' : 'You need to provide a value for Application'
-      },
-      format : {
-        'with' : /\.jar$|\.py$/i,
-        'message' : 'You need to provide a .jar or .py file'
-      }
-    },
-    'actionModel.sparkName': {
-      presence: {
-        'message' : 'You need to provide a value for Name'
-      }
-    }
-  },
+  // validations : {
+  //   'actionModel.master': {
+  //     presence: {
+  //       'message' : 'You need to provide a value for Runs on (Master)'
+  //     }
+  //   },
+  //   'actionModel.jar': {
+  //     presence: {
+  //       'message' : 'You need to provide a value for Application'
+  //     },
+  //     format : {
+  //       'with' : /\.jar$|\.py$/i,
+  //       'message' : 'You need to provide a .jar or .py file'
+  //     }
+  //   },
+  //   'actionModel.sparkName': {
+  //     presence: {
+  //       'message' : 'You need to provide a value for Name'
+  //     }
+  //   }
+  // },
   observeError :function(){
     if(this.$('#collapseOne label.text-danger').length > 0 && !this.$('#collapseOne').hasClass("in")){
       this.$('#collapseOne').collapse('show');

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/sqoop-action-info.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/sqoop-action-info.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/sqoop-action-info.js
new file mode 100644
index 0000000..3192c72
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/sqoop-action-info.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 : {    
+	  hideNotification(){
+       	  this.sendAction("hideNotification");
+	  }
+   }
+});
+ 
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/sqoop-action.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/sqoop-action.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/sqoop-action.js
index 847cccd..13eb6e5 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/sqoop-action.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/sqoop-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({
   sqoopSendType : Ember.observer('isArg',function(){
     if(this.get('isArg')){
       this.set("actionModel.command", undefined);
@@ -61,8 +60,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/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/ssh-action-info.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/ssh-action-info.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/ssh-action-info.js
new file mode 100644
index 0000000..3192c72
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/ssh-action-info.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 : {    
+	  hideNotification(){
+       	  this.sendAction("hideNotification");
+	  }
+   }
+});
+ 
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/ssh-action.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/ssh-action.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/ssh-action.js
index 3ae1f12..d879a0c 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/ssh-action.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/ssh-action.js
@@ -16,9 +16,17 @@
 */
 
 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.host': validator('presence', {
+    presence : true
+  }),
+  'actionModel.command': validator('presence', {
+    presence : true
+  })
+});
+export default Ember.Component.extend(Validations, {
   fileBrowser : Ember.inject.service('file-browser'),
   javaOptsObserver : Ember.observer('isSingle',function(){
     if(this.get('isSingle')){
@@ -54,18 +62,6 @@ export default Ember.Component.extend(EmberValidations, {
       this.$('#collapseOne').collapse('show');
     }
   }.on('didUpdate'),
-  validations : {
-    'actionModel.host': {
-      presence: {
-        'message' : 'You need to provide a value for host',
-      }
-    },
-    'actionModel.command': {
-      presence: {
-        'message' : 'You need to provide a value for command',
-      }
-    }
-  },
   actions : {
     openFileBrowser(model, context){
       if(undefined === context){

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/sub-workflow-action-info.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/sub-workflow-action-info.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/sub-workflow-action-info.js
new file mode 100644
index 0000000..3192c72
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/sub-workflow-action-info.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 : {    
+	  hideNotification(){
+       	  this.sendAction("hideNotification");
+	  }
+   }
+});
+ 
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/sub-workflow.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/sub-workflow.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/sub-workflow.js
index 50ac5bd..06cec22 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/sub-workflow.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/sub-workflow.js
@@ -16,9 +16,15 @@
 */
 
 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.appPath': validator('presence', {
+    presence : true
+  })
+});
+
+export default Ember.Component.extend(Validations,{
   setUp : function(){
     if(this.get('actionModel.configuration') === undefined){
       this.set("actionModel.configuration",{});
@@ -36,13 +42,6 @@ export default Ember.Component.extend(EmberValidations,{
       this.$('#collapseOne').collapse('show');
     }
   }.on('didUpdate'),
-  validations : {
-    'actionModel.appPath': {
-      presence: {
-        'message' : 'You need to provide a value for app path'
-      }
-    }
-  },
   actions : {
     openFileBrowser(model, context){
       if(undefined === context){

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/transition-config.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/transition-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/transition-config.js
index ccf69de..ca45b1f 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/transition-config.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/transition-config.js
@@ -16,32 +16,31 @@
 */
 
 import Ember from 'ember';
-import EmberValidations,{ validator } from 'ember-validations';
+import { validator, buildValidations } from 'ember-cp-validations';
 import {FindNodeMixin} from '../domain/findnode-mixin';
 
-export default Ember.Component.extend(FindNodeMixin, EmberValidations, {
+const Validations = buildValidations({
+  'transition.errorNode.name': validator('presence', {
+    presence : true
+  })
+});
+
+export default Ember.Component.extend(FindNodeMixin, Validations, {
   selectedKillNode : '',
   initialize : function(){
     this.set('descendantNodes',this.getDesendantNodes(this.get('currentNode')));
-    this.set('okToNode', this.getOKToNode(this.get('currentNode')));
+    if(!this.get('transition.okToNode')){
+      var defaultOkToNode = this.getOKToNode(this.get('currentNode'));
+      this.set('transition.okToNode', defaultOkToNode);
+      this.set('defaultOkToNode', defaultOkToNode);
+    }
     this.sendAction('register','transition', this);
     if(Ember.isBlank(this.get('transition.errorNode.name'))){
       this.set('transition.errorNode', this.get('killNodes').objectAt(0));
     }
   }.on('init'),
-  //Work-around : Issue in ember-validations framework
-  errorNode : Ember.computed.alias('transition.errorNode'),
-  validations : {
-    'errorNode.name': {
-      inline : validator(function() {
-        if(!this.get('transition.errorNode.name') || this.get('transition.errorNode.name') === ""){
-          return "You need to provide an error-to transition";
-        }
-      })
-    }
-  },
   actions : {
-    onSelectChange (value){
+    errorToHandler (value){
       this.set('selectedKillNode', value);
       if(this.get('selectedKillNode') === 'createNew'){
         this.set('transition.errorNode.name', "");
@@ -60,8 +59,19 @@ export default Ember.Component.extend(FindNodeMixin, EmberValidations, {
         }
       }
     },
-    okNodeHandler (value){
-
+    okToHandler (name){
+      var validOkToNodes = this.get('currentNode.validOkToNodes');
+      var node = validOkToNodes.findBy('name',name);
+      if(node.id !== this.get('defaultOkToNode').id){
+        this.set('showWarning', true);
+      }else{
+        this.set('showWarning', false);
+      }
+      this.set('transition.okToNode', node);
+    },
+    undoChangeOkTo(){
+      this.set('transition.okToNode', this.get('defaultOkToNode'));
+      this.set('showWarning', false);
     }
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-action-editor.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-action-editor.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-action-editor.js
index 502fe50..8ee5a0a 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-action-editor.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-action-editor.js
@@ -16,11 +16,10 @@
 */
 
 import Ember from 'ember';
-import EmberValidations from 'ember-validations';
 import Constants from '../utils/constants';
 import {SlaInfo} from '../domain/sla-info';
 
-export default Ember.Component.extend(EmberValidations, Ember.Evented,{
+export default Ember.Component.extend( Ember.Evented,{
   actionIcons : {
     "hive": "server",
     "hive2": "server",
@@ -111,30 +110,14 @@ export default Ember.Component.extend(EmberValidations, Ember.Evented,{
     }
   }.on('didUpdate'),
   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);
-      });
-    }
-    return deferred;
+    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;
   },
   processMultivaluedComponents(){
     this.get('childComponents').forEach((childComponent)=>{
@@ -157,19 +140,16 @@ export default Ember.Component.extend(EmberValidations, Ember.Evented,{
       this.sendAction('close');
     },
     save () {
-      var isFormValid = this.validateChildrenComponents();
-      isFormValid.promise.then(function(){
-        this.validate().then(function(){
-          this.processMultivaluedComponents();
-          this.processStaticProps();
-          this.$('#action_properties_dialog').modal('hide');
-          this.sendAction('addKillNode', this.get('transition.errorNode'));
-          this.set('saveClicked', true);
-        }.bind(this)).catch(function(e){
-        }.bind(this));
-      }.bind(this)).catch(function (e) {
-      });
-
+      var isChildComponentsValid = this.validateChildrenComponents();
+      if(this.get('validations.isInvalid') || !isChildComponentsValid) {
+        this.set('showErrorMessage', true);
+        return;
+      }
+      this.processMultivaluedComponents();
+      this.processStaticProps();
+      this.$('#action_properties_dialog').modal('hide');
+      this.sendAction('setNodeTransitions', this.get('transition'));
+      this.set('saveClicked', true);
     },
     openFileBrowser(model, context){
       if(!context){

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-actions.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-actions.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-actions.js
index 95a7f08..7fc1c94 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-actions.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-actions.js
@@ -17,12 +17,19 @@
 
 import Ember from 'ember';
 export default Ember.Component.extend({
+  clipboardHasContents : Ember.computed.oneWay('clipboard', function(){
+    return !Ember.isEmpty(this.get('clipboard'));
+  }),
   actions : {
     addAction : function(type){
       this.$(".dr_action").css("background-color", "#fff");
       this.$("[data-type="+type+"]").css("background-color", "#538EC0");
       this.$(this.get('element')).popover('hide');
       this.sendAction("addNode", type);
+    },
+    pasteNode(){
+      this.$(this.get('element')).popover('hide');
+      this.sendAction("pasteNode");
     }
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-credentials.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-credentials.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-credentials.js
index ae24770..1072ca4 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-credentials.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-credentials.js
@@ -42,51 +42,44 @@ export default Ember.Component.extend(Ember.Evented, {
       }
     });
   },
-  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);
-      });
-    }
-    return deferred;
-  },
   actions : {
     register(component, context){
       this.get('childComponents').set(component, context);
     },
+    createCredentials(){
+      this.set('editMode', false);
+      this.set('createMode',true);
+    },
+    editCredentials(index){
+      this.set('createMode', false);
+      this.set('editMode',true);
+      this.set('currentCredentialIndex', index);
+      this.set('currentCredentials', Ember.copy(this.get('credentialsList').objectAt(index)));
+    },
+    updateCredentials(){
+      this.set('editMode', false);
+      this.get('credentialsList').replace(this.get('currentCredentialIndex'), 1, Ember.copy(this.get('currentCredentials')));
+    },
     addCredentials (credentialsInfo){
       this.get('credentialsList').pushObject(credentialsInfo);
+      this.set('createMode', false);
+    },
+    deleteCredentials(index){
+      this.get('credentialsList').removeAt(index);
+      if(index === this.get('currentCredentialIndex')){
+        this.set('editMode', false);
+      }
+    },
+    cancelCreateMode(){
+      this.set('createMode', false);
     },
-    deleteCredentials(name){
-      var credentials = this.get('credentialsList').findBy('name', name);
-      this.get('credentialsList').removeObject(credentials);
+    cancelEditMode(){
+      this.set('editMode', false);
     },
     saveCredentials (){
-      var isFormValid = this.validateChildrenComponents();
-      isFormValid.promise.then(function(){
-        this.processMultivaluedComponents();
-        this.set('workflowCredentials', Ember.copy(this.get('credentialsList')));
-        this.$('#workflow_credentials_dialog').modal('hide');
-      }.bind(this)).catch(function (e) {
-      });
+      this.processMultivaluedComponents();
+      this.set('workflowCredentials', Ember.copy(this.get('credentialsList')));
+      this.$('#workflow_credentials_dialog').modal('hide');
     }
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-job-action-info.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-job-action-info.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-job-action-info.js
new file mode 100644
index 0000000..9a2c9cc
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-job-action-info.js
@@ -0,0 +1,22 @@
+/*
+*    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 : {
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-node.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-node.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-node.js
index e51135e..0718152 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-node.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-node.js
@@ -72,6 +72,12 @@ export default Ember.Component.extend(Ember.Evented,{
     registerAddBranchAction(component){
       this.set("addBranchListener",component);
     },
+    showNotification(node){
+       this.sendAction("showNotification", node);
+    },
+    // hideNotification(){
+    //    this.sendAction("hideNotification");
+    // },    
     openEditor (){
       this.sendAction("openEditor", this.get('node'));
     },
@@ -86,6 +92,9 @@ export default Ember.Component.extend(Ember.Evented,{
     },
     addDecisionBranch(settings){
       this.sendAction("addDecisionBranch",settings);
+    },
+    copyNode(){
+      this.sendAction("copyNode", this.get('node'));
     }
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-parameters.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-parameters.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-parameters.js
index 1f75e64..f3a25ac 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-parameters.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-parameters.js
@@ -15,9 +15,19 @@
 *    limitations under the License.
 */
 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({
+  'parameters.configuration.property': {
+    validators: [
+      validator('unique-name', {
+        dependentKeys: ['parameters.configuration.property.[]']
+      })
+    ]
+  }
+});
+export default Ember.Component.extend(Validations, {
+  saveClicked : false,
   initialize : function(){
     if(this.get('parameters') === undefined || this.get('parameters') === null){
       this.set('parameters',{});
@@ -29,27 +39,15 @@ export default Ember.Component.extend(EmberValidations, {
     this.sendAction('register','workflowParameters',this);
 
   }.on('init'),
-  validations : {
-    'parameters': {
-      inline : validator(function() {
-        var nameMap = [], errorMsg = undefined;
-        if(this.get('parameters.configuration.property')){
-          this.get('parameters.configuration.property').forEach(function(item, index){
-            if(!item.name){
-              errorMsg = "Name cannot be blank";
-            } else if(nameMap.indexOf(item.name) > -1){
-              errorMsg = "Name cannot be duplicate";
-            } else{
-              nameMap.push(item.name);
-            }
-          });
-          if(errorMsg){
-            return errorMsg;
-          }
-        }
-      })
+  displayName : Ember.computed('type', function(){
+    if(this.get('type') === 'wf'){
+      return "Workflow";
+    }else if(this.get('type') === 'coord'){
+      return "Coordinator";
+    }else{
+      return "Bundle";
     }
-  },
+  }),
   rendered : function(){
     this.$('#workflow_parameters_dialog').modal({
       backdrop: 'static',
@@ -57,24 +55,28 @@ export default Ember.Component.extend(EmberValidations, {
     });
     this.$('#workflow_parameters_dialog').modal('show');
     this.$('#workflow_parameters_dialog').modal().on('hidden.bs.modal', function() {
-      if(this.get('saveClicked')){
-        this.sendAction('saveWorkFlowParam');
-      }else{
-        this.sendAction('closeWorkFlowParam');
-      }
+    if(this.get('saveClicked')){
+      this.sendAction('saveWorkFlowParam');
+    }else{
+      this.sendAction('closeWorkFlowParam');
+    }
     }.bind(this));
   }.on('didInsertElement'),
   actions : {
     register(component, context){
       this.set('nameValueContext', context);
     },
+    close (){
+      this.$('#workflow_parameters_dialog').modal('hide');
+      this.set('saveClicked', false);
+    },
     saveParameters (){
-      this.get("nameValueContext").trigger("bindInputPlaceholder");
-      this.validate().then(function(){
+      if(!this.get('validations.isInvalid')){
+        this.get("nameValueContext").trigger("bindInputPlaceholder");
         this.set('saveClicked', true);
         this.$('#workflow_parameters_dialog').modal('hide');
-      }.bind(this)).catch(function(e){
-      }.bind(this));
+        return ;
+      }
     }
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-sla.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-sla.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-sla.js
index dac325f..6d504c6 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-sla.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-sla.js
@@ -15,10 +15,9 @@
 *    limitations under the License.
 */
 import Ember from 'ember';
-import {SlaInfo} from '../domain/sla-info'
-import EmberValidations from 'ember-validations';
+import {SlaInfo} from '../domain/sla-info';
 
-export default Ember.Component.extend(EmberValidations,{
+export default Ember.Component.extend({
   slaInfo : {},
   initialize : function(){
     this.set('slaInfo',Ember.copy(this.get('workflowSla')));
@@ -35,13 +34,13 @@ export default Ember.Component.extend(EmberValidations,{
   }.on('didInsertElement'),
   actions : {
     saveWorkflowSla () {
-      this.get('slaContext').validate().then(()=>{
+      if(this.get('slaContext').get('validations.isInvalid')){
+        this.get('slaContext').set('showErrorMessage', true);
+        return;
+      }else{
         this.set('workflowSla', this.get('slaInfo'));
         this.$('#workflow_sla_dialog').modal('hide');
-      }.bind(this)). catch(()=>{
-
-      });
-
+      }
     },
     register (name, context) {
       this.set('slaContext', context);

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/controllers/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/controllers/.gitkeep b/contrib/views/wfmanager/src/main/resources/ui/app/controllers/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/controllers/design.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/controllers/design.js b/contrib/views/wfmanager/src/main/resources/ui/app/controllers/design.js
index 285ad19..689ec0d 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/controllers/design.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/controllers/design.js
@@ -18,9 +18,4 @@
 import Ember from 'ember';
 
 export default Ember.Controller.extend({
-  queryParams: "appPath",
-  appPath : null,
-  model: function(params) {
-    return {};
-  }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/action-type-resolver.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/action-type-resolver.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/action-type-resolver.js
new file mode 100644
index 0000000..c25b953
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/action-type-resolver.js
@@ -0,0 +1,62 @@
+/*
+*    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 * as actionJobHandler from '../domain/actionjob_hanlder';
+
+var ActionTypeResolver=Ember.Object.extend({
+  actionJobHandlerMap:null,
+  validStandardActionProps:["ok","error","info"],
+  init(){
+    var settings={schemaVersions:this.schemaVersions};
+    this.actionJobHandlerMap=new Map();
+    this.actionJobHandlerMap.set("java",actionJobHandler.JavaActionJobHandler.create(settings));
+    this.actionJobHandlerMap.set("pig",actionJobHandler.PigActionJobHandler.create(settings));
+    this.actionJobHandlerMap.set("hive",actionJobHandler.HiveActionJobHandler.create(settings));
+    this.actionJobHandlerMap.set("hive2",actionJobHandler.Hive2ActionJobHandler.create(settings));
+    this.actionJobHandlerMap.set("sqoop",actionJobHandler.SqoopActionJobHandler.create(settings));
+    this.actionJobHandlerMap.set("shell",actionJobHandler.ShellActionJobHandler.create(settings));
+    this.actionJobHandlerMap.set("spark",actionJobHandler.SparkActionJobHandler.create(settings));
+    this.actionJobHandlerMap.set("map-reduce",actionJobHandler.MapRedActionJobHandler.create(settings));
+    this.actionJobHandlerMap.set("sub-workflow",actionJobHandler.SubWFActionJobHandler.create(settings));
+    this.actionJobHandlerMap.set("distcp",actionJobHandler.DistCpJobHandler.create(settings));
+    this.actionJobHandlerMap.set("ssh",actionJobHandler.SshActionJobHandler.create(settings));
+    this.actionJobHandlerMap.set("email",actionJobHandler.EmailActionJobHandler.create(settings));
+    this.actionJobHandlerMap.set("fs",actionJobHandler.FSActionJobHandler.create(settings));
+  },
+  getActionType(json){
+    var self=this;
+    var resolvedType=null;
+    var problaleActionsTypes=[];
+    Object.keys(json).forEach(function functionName(key) {
+      if (!self.validStandardActionProps.contains(key) && !key.startsWith("_")){
+        problaleActionsTypes.push(key);
+      }
+    });
+    if (problaleActionsTypes.length===1){
+      return problaleActionsTypes[0];
+    }else{
+      console.error("Invalid Action spec..",json);
+    }
+    return resolvedType;
+  },
+  getActionJobHandler(jobType){
+    return this.actionJobHandlerMap.get(jobType);
+  }
+});
+
+export {ActionTypeResolver};

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/actionjob_hanlder.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/actionjob_hanlder.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/actionjob_hanlder.js
index 33204ea..2ce0ab4 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/actionjob_hanlder.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/actionjob_hanlder.js
@@ -44,6 +44,7 @@ var ActionJobHandler=Ember.Object.extend(MappingMixin,{
     }
     this.handleMapping(nodeDomain,actionObj,this.mapping,nodeName);
   },
+  /* jshint unused:vars */
   validate(nodeDomain){
     //overwrite in implmentations and return array of errors object.
   },

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/bundle/bundle-xml-generator.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/bundle/bundle-xml-generator.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/bundle/bundle-xml-generator.js
new file mode 100644
index 0000000..957d1c0
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/bundle/bundle-xml-generator.js
@@ -0,0 +1,55 @@
+/*
+*    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';
+var BundleGenerator= Ember.Object.extend({
+  x2js : new X2JS({useDoubleQuotes:true}),
+  bundle: null,
+  process (){
+    var xmlJson={"bundle-app":{}};
+    console.log(this.bundle);
+    var bundleApp=xmlJson["bundle-app"];
+    bundleApp._xmlns = "uri:oozie:bundle:0.1";
+    bundleApp._name = this.bundle.name;
+    if(!Ember.isEmpty(this.bundle.kickOffTime.value)){
+      bundleApp["control"] = {};
+      bundleApp["control"]["kick-off-time"] = this.bundle.kickOffTime.value;
+    }
+    this.generateCoordinatorsJson(bundleApp);
+    var xmlAsStr = this.get("x2js").json2xml_str(xmlJson);
+    return xmlAsStr;
+  },
+  generateCoordinatorsJson(bundleApp){
+    if (this.bundle.coordinators && this.bundle.coordinators.length>0){
+      bundleApp["coordinator"] = [];
+      this.bundle.coordinators.forEach((coordinator)=>{
+        var coordinatorJson = {"_name":coordinator.name};
+        coordinatorJson["app-path"] = coordinator.appPath;
+        if (coordinator.configuration &&
+          coordinator.configuration.property &&
+          coordinator.configuration.property.length > 0){
+            coordinatorJson["configuration"]={"property":[]};
+            var propertiesJson=coordinatorJson.configuration.property;
+            coordinator.configuration.property.forEach((prop) =>{
+              propertiesJson.push({"name" : prop.name, "value" : prop.value});
+            });
+          }
+          bundleApp["coordinator"].push(coordinatorJson);
+      }, this);
+    }
+  }
+});
+export {BundleGenerator};

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/bundle/bundle-xml-importer.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/bundle/bundle-xml-importer.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/bundle/bundle-xml-importer.js
new file mode 100644
index 0000000..aa96221
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/bundle/bundle-xml-importer.js
@@ -0,0 +1,87 @@
+/*
+*    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 { Bundle } from '../bundle/bundle';
+
+var BundleXmlImporter= Ember.Object.extend({
+  x2js : new X2JS(),
+  importBundle (xml){
+    var bundleJson = this.get("x2js").xml_str2json(xml);
+    return this.processBundleXML(bundleJson);
+  },
+  processBundleXML(bundleJson){
+    var bundle = Bundle.create({
+      name : '',
+      kickOffTime : {
+        value : '',
+        displayValue : '',
+        type : 'date'
+      },
+      coordinators : Ember.A([])
+    });
+    var bundleApp=bundleJson["bundle-app"];
+    bundle.name = bundleApp._name;
+    if(bundleApp.control && bundleApp.control["kick-off-time"]) {
+      bundle.kickOffTime = this.extractDateField(bundleApp["control"]["kick-off-time"]);
+    }else{
+
+    }
+    this.processCoordinatorsJson(bundleApp, bundle);
+    return bundle;
+  },
+  processCoordinatorsJson(bundleApp, bundle){
+    if (bundleApp.coordinator){
+      bundle.coordinators = Ember.A([]);
+      if(Array.isArray(bundleApp.coordinator)){
+        bundleApp.coordinator.forEach((coordinator)=>{
+          bundle.coordinators.push(this.extractCoordinator(coordinator));
+        }, this);
+      }else{
+        bundle.coordinators.push(this.extractCoordinator(bundleApp.coordinator));
+      }
+    }
+  },
+  extractDateField(value){
+    var dateField = {};
+    var date = new Date(value);
+    dateField.value = value;
+    if(isNaN(date.getTime())){
+      dateField.displayValue = value;
+      dateField.type = 'expr';
+    }else{
+      dateField.type = 'date';
+      var utcDate = new Date(date.getTime() + date.getTimezoneOffset()*60*1000);
+      dateField.displayValue = moment(utcDate).format("MM/DD/YYYY hh:mm A");
+    }
+    return dateField;
+  },
+  extractCoordinator(coordinator) {
+    var coordinatorJson = {"name":coordinator._name};
+    coordinatorJson.appPath =  coordinator["app-path"];
+    if (coordinator.configuration &&
+    coordinator.configuration.property &&
+    coordinator.configuration.property.length > 0){
+      coordinatorJson.configuration = {};
+      coordinatorJson.configuration.property = Ember.A([]);
+      coordinator.configuration.property.forEach(function(prop){
+        coordinatorJson.configuration.property.push({"name" : prop.name, "value" : prop.value});
+      });
+    }
+    return coordinatorJson;
+  }
+});
+export {BundleXmlImporter};

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/bundle/bundle.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/bundle/bundle.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/bundle/bundle.js
new file mode 100644
index 0000000..2b4bf59
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/bundle/bundle.js
@@ -0,0 +1,22 @@
+/*
+*    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';
+var Bundle = Ember.Object.extend({
+
+});
+export {Bundle};

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/coordinator/coordinator-xml-generator.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/coordinator/coordinator-xml-generator.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/coordinator/coordinator-xml-generator.js
new file mode 100644
index 0000000..a657706
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/coordinator/coordinator-xml-generator.js
@@ -0,0 +1,204 @@
+/*
+*    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';
+var CoordinatorGenerator= Ember.Object.extend({
+  x2js : new X2JS({useDoubleQuotes:true}),
+  coordinator: null,
+  init(){
+  },
+  process(){
+    var xmlJson={"coordinator-app":{}};
+    console.log(this.coordinator);
+    var coordinatorApp=xmlJson["coordinator-app"];
+    coordinatorApp._name = this.coordinator.name;
+    if(this.coordinator.frequency.type !== 'cron'){
+      coordinatorApp._frequency = "${coord:"+this.coordinator.frequency.type+"("+this.coordinator.frequency.value+")}";
+    }else{
+      coordinatorApp._frequency = this.coordinator.frequency.value;
+    }
+    coordinatorApp._start = this.coordinator.start.value;
+    coordinatorApp._end = this.coordinator.end.value;
+    coordinatorApp._timezone = this.coordinator.timezone;
+    coordinatorApp._xmlns = "uri:oozie:coordinator:0.4";
+    this.generateDataSets(coordinatorApp);
+    if(this.coordinator.dataInputType === 'simple'){
+      this.generateInputEvents(coordinatorApp);
+    }else{
+      this.generateConditionalInputEvents(coordinatorApp);
+    }
+    if(this.coordinator.inputLogic){
+      this.generateInputLogic(coordinatorApp);
+    }
+    this.generateOutputEvents(coordinatorApp);
+    this.generateAction(coordinatorApp);
+    this.generateParameters(coordinatorApp);
+    this.generateControls(coordinatorApp);
+    var xmlAsStr = this.get("x2js").json2xml_str(xmlJson);
+    return xmlAsStr;
+  },
+  generateDataSets(coordinatorApp){
+    if (this.coordinator.datasets && this.coordinator.datasets.length>0){
+      var datasets=[];
+      coordinatorApp["datasets"]={"dataset":datasets};
+      this.coordinator.datasets.forEach(function(dataset){
+        var dataSetJson={_name:dataset.name,
+          "_initial-instance":dataset.initialInstance.value,
+          _timezone:dataset.timezone
+        };
+        if(dataset.frequency.type !== 'cron'){
+          dataSetJson._frequency = "${coord:"+ dataset.frequency.type + "("+dataset.frequency.value + ")}";
+        }else{
+          dataSetJson._frequency = dataset.frequency.value;
+        }
+        dataSetJson["uri-template"]=dataset.uriTemplate;
+        if (dataset.doneFlag){
+          dataSetJson["done-flag"]=dataset.doneFlag;
+        }
+        datasets.push(dataSetJson);
+      });
+    }
+  },
+  generateInputEvents(coordinatorApp){
+    if (this.coordinator.dataInputs && this.coordinator.dataInputs.length>0){
+      coordinatorApp["input-events"]={"data-in":[]};
+      var dataInListJson=coordinatorApp["input-events"]["data-in"];
+      this.coordinator.dataInputs.forEach(function(datain){
+        var datainJson={_name:datain.name,_dataset:datain.dataset};
+        if (datain.instances && datain.instances.length>0){
+          var instancesJson=[];
+          datain.instances.forEach(function(instance){
+            if (instance&& instance.value){
+              instancesJson.push(instance.value);
+            }
+          });
+          datainJson["instance"]=instancesJson;
+        }else if (datain.start && datain.end){
+          datainJson["start-instance"]=datain.start.value;
+          datainJson["end-instance"]=datain.end.value;
+        }
+        dataInListJson.push(datainJson);
+      });
+    }
+  },
+  generateConditionalInputEvents(coordinatorApp){
+    if(this.coordinator.conditionalDataInput){
+      var condition = this.coordinator.conditionalDataInput;
+      coordinatorApp["input-events"] = {};
+      var inputEventJson = coordinatorApp["input-events"];
+      inputEventJson[condition.operator] = {};
+      var conditionJson = inputEventJson[condition.operator];
+      this.parseConditionTree(conditionJson, condition);
+    }
+  },
+  generateInputLogic(coordinatorApp){
+    var condition = this.coordinator.inputLogic;
+    coordinatorApp["input-logic"] = {};
+    var inputLogicJson = coordinatorApp["input-logic"];
+    inputLogicJson[condition.operator] = {};
+    var conditionJson = inputLogicJson[condition.operator];
+    this.parseConditionTree(conditionJson, condition);
+  },
+  parseConditionTree(conditionJson, condition){
+    if(!condition) {
+      return;
+    }
+    conditionJson._name = condition.name;
+    if(condition.min){
+      conditionJson._min = condition.min;
+    }
+    if(condition.wait){
+      conditionJson._wait = condition.wait;
+    }
+    if(condition.name){
+      conditionJson._name = condition.name;
+    }
+    if(!condition.operands){
+      return;
+    }
+    condition.operands.forEach((operand)=>{
+      if(operand.type === 'dataInput'){
+        if(!conditionJson["data-in"]){
+          conditionJson["data-in"] = [];
+        }
+        var dataInJson = {_dataset:operand.dataset};
+        if(operand.min){
+          dataInJson._min = operand.min;
+        }
+        if(operand.wait){
+          dataInJson._wait = operand.wait;
+        }
+        if(operand.name){
+          dataInJson._name = operand.name;
+        }
+        conditionJson["data-in"].push(dataInJson);
+      }else if(operand.type === 'condition'){
+        conditionJson[operand.operator] = {};
+        this.parseConditionTree(conditionJson[operand.operator], operand);
+      }
+    }, this);
+  },
+  generateOutputEvents(coordinatorApp){
+    if (this.coordinator.dataOutputs && this.coordinator.dataOutputs.length>0){
+      coordinatorApp["output-events"]={"data-out":[]};
+      var dataOutputsJson=  coordinatorApp["output-events"]["data-out"];
+      this.coordinator.dataOutputs.forEach(function(dataOut){
+        var dataOutJson={_dataset:dataOut.dataset,_name:dataOut.name,instance:dataOut.instance.value};
+        dataOutputsJson.push(dataOutJson);
+      });
+    }
+  },
+  generateAction(coordinatorApp){
+    var actionJson={"workflow":{"app-path":this.coordinator.workflow.appPath}};
+    coordinatorApp.action=actionJson;
+    if (this.coordinator.workflow.configuration &&
+      this.coordinator.workflow.configuration.property &&
+      this.coordinator.workflow.configuration.property.length>0){
+        actionJson.workflow["configuration"]={"property":[]};
+        var propertiesJson=actionJson.workflow.configuration.property;
+        this.coordinator.workflow.configuration.property.forEach(function(prop){
+          propertiesJson.push({"name":prop.name,"value":prop.value});
+        });
+      }
+    },
+    generateParameters(coordinatorApp){
+      if (this.coordinator.parameters.configuration &&
+        this.coordinator.parameters.configuration.property &&
+        this.coordinator.parameters.configuration.property.length>0){
+          coordinatorApp["parameters"] = {};
+          var paramJson = coordinatorApp["parameters"];
+          paramJson["configuration"]={"property":[]};
+          var propertiesJson=paramJson.configuration.property;
+          this.coordinator.parameters.configuration.property.forEach(function(prop){
+            propertiesJson.push({"name":prop.name,"value":prop.value});
+          });
+        }
+    },
+    generateControls(coordinatorApp) {
+      if(this.coordinator.controls && this.coordinator.controls.length > 0){
+          coordinatorApp["controls"] = {};
+          this.coordinator.controls.forEach((control)=>{
+            if(control.value){
+              coordinatorApp["controls"][control.name] = control.value;
+            }
+          }, this);
+          if(Object.keys(coordinatorApp["controls"]).length === 0){
+            delete coordinatorApp["controls"];
+          }
+      }
+    }
+  });
+  export {CoordinatorGenerator};


[06/10] ambari git commit: AMBARI-18691. Improve and Update Workflow designer to support coordinators and bundles. (Belliraj HB via dipayanb)

Posted by db...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/coordinator/coordinator-xml-importer.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/coordinator/coordinator-xml-importer.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/coordinator/coordinator-xml-importer.js
new file mode 100644
index 0000000..fca90b3
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/coordinator/coordinator-xml-importer.js
@@ -0,0 +1,272 @@
+/*
+*    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 '../coordinator/coordinator';
+
+var CoordinatorXmlImporter= Ember.Object.extend({
+  x2js : new X2JS(),
+  importCoordinator (xml){
+    var coordinatorJson = this.get("x2js").xml_str2json(xml);
+    return this.processCoordinatorXML(coordinatorJson);
+  },
+  createNewCoordinator(){
+    return Coordinator.create({
+      workflow : {
+        appPath : '',
+        configuration :{
+          property : Ember.A([])
+        }
+      },
+      frequency : {
+        type : '',
+        value : ''
+      },
+      start : {
+        value : '',
+        displayValue : '',
+        type : 'date'
+      },
+      end : {
+        value : '',
+        displayValue : '',
+        type : 'date'
+      },
+      timezone : '',
+      datasets : Ember.A([]),
+      dataInputs : Ember.A([]),
+      dataOutputs : Ember.A([]),
+      dataInputType : 'simple',
+      parameters : {
+        configuration :{
+          property : Ember.A([])
+        }
+      },
+      controls : Ember.A([])
+    });
+  },
+  processCoordinatorXML(coordinatorJson){
+    var coordinatorApp = coordinatorJson["coordinator-app"];
+    var coordinator = this.createNewCoordinator();
+    coordinator.name = coordinatorApp._name;
+    var frequency = coordinatorApp._frequency;
+    if(frequency.startsWith('${coord:')){
+      coordinator.frequency.type = frequency.substring(frequency.indexOf(':')+1, frequency.indexOf('('));
+      coordinator.frequency.value = frequency.substring(frequency.indexOf('(')+1, frequency.indexOf(')'));
+    }else{
+      coordinator.frequency.type = 'cron';
+      coordinator.frequency.value = frequency;
+    }
+    coordinator.start = this.extractDateField(coordinatorApp._start);
+    coordinator.end = this.extractDateField(coordinatorApp._end);
+    coordinator.timezone = coordinatorApp._timezone;
+    this.extractDataSets(coordinatorApp, coordinator);
+    if(coordinatorApp['input-events'] && coordinatorApp['input-events']['data-in']){
+      coordinator.dataInputType = 'simple';
+      this.extractInputEvents(coordinatorApp, coordinator);
+    }else{
+      coordinator.dataInputType = 'logical';
+      coordinator.supportsConditionalDataInput = true;
+      this.extractLogicalInputEvents(coordinatorApp, coordinator);
+    }
+    this.extractOutputEvents(coordinatorApp, coordinator);
+    this.extractAction(coordinatorApp, coordinator);
+    this.extractParameters(coordinatorApp, coordinator);
+    this.extractControls(coordinatorApp, coordinator);
+    return coordinator;
+  },
+  extractDateField(value){
+    var dateField = {};
+    var date = new Date(value);
+    dateField.value = value;
+    if(isNaN(date.getTime())){
+      dateField.displayValue = value;
+      dateField.type = 'expr';
+    }else{
+      dateField.type = 'date';
+      var utcDate = new Date(date.getTime() + date.getTimezoneOffset()*60*1000);
+      dateField.displayValue = moment(utcDate).format("MM/DD/YYYY hh:mm A");
+    }
+    return dateField;
+  },
+  extractDataSet(dataset){
+    var dataSetJson = {
+      name : dataset._name,
+      frequency : {},
+      initialInstance :this.extractDateField( dataset['_initial-instance']),
+      timezone : dataset._timezone
+    };
+    var frequency = dataset._frequency;
+    if(frequency.startsWith('${coord:')){
+      dataSetJson.frequency.type = frequency.substring(frequency.indexOf(':')+1, frequency.indexOf('('));
+      dataSetJson.frequency.value = frequency.substring(frequency.indexOf('(')+1, frequency.indexOf(')'));
+    }else{
+      dataSetJson.frequency.type = 'cron';
+      dataSetJson.frequency.value = frequency;
+    }
+    dataSetJson["uriTemplate"] = dataset['uri-template'];
+    if (dataset['done-flag']){
+      dataSetJson.doneFlag = dataset['done-flag'];
+    }
+    return dataSetJson;
+  },
+  extractDataSets(coordinatorApp, coordinator){
+    if (coordinatorApp.datasets && coordinatorApp.datasets.dataset){
+      if(Array.isArray(coordinatorApp.datasets.dataset)) {
+        coordinatorApp.datasets.dataset.forEach(function(dataset){
+          coordinator.datasets.push(this.extractDataSet(dataset));
+        }, this);
+      }else{
+        coordinator.datasets.push(this.extractDataSet(coordinatorApp.datasets.dataset));
+      }
+    }
+  },
+  extractDataInput(datain){
+    var datainJson = {
+      name : datain._name,
+      dataset : datain._dataset
+    };
+    if (datain.instance && datain.instance.length>0){
+      datainJson.instances = Ember.A([]);
+      if(Array.isArray(datain.instance)) {
+        datain.instance.forEach(function(instance){
+          datainJson.instances.pushObject(this.extractDateField(instance));
+        }, this);
+      }else{
+        datainJson.instances.pushObject(this.extractDateField(datain.instance));
+      }
+      datainJson.isList = true;
+    }else if (datain["start-instance"] && ["end-instance"]){
+      datainJson.start = this.extractDateField(datain["start-instance"]);
+      datainJson.end = this.extractDateField(datain["end-instance"]);
+      datainJson.isList = false;
+    }
+    return datainJson;
+  },
+  extractInputEvents(coordinatorApp, coordinator){
+    if(Array.isArray(coordinatorApp['input-events']['data-in'])){
+      coordinatorApp['input-events']['data-in'].forEach(function(datain){
+        coordinator.dataInputs.push(this.extractDataInput(datain));
+      }, this);
+    }else{
+      coordinator.dataInputs.push(this.extractDataInput(coordinatorApp['input-events']['data-in']));
+    }
+  },
+  extractLogicalInputEvents(coordinatorApp, coordinator){
+    var conditionJson = coordinatorApp['input-events'];
+    var condition = {};
+    coordinator.conditionalDataInput = condition;
+    Object.keys(conditionJson).forEach((key)=>{
+      condition.operator = key;
+      this.parseConditionTree(conditionJson[key], condition);
+    }, this);
+  },
+  extractDataInputOperand(operandJson){
+    var operand = {};
+    operand.name = operandJson._name;
+    operand.type = 'dataInput';
+    operand.dataset = operandJson._dataset;
+    if(operandJson._min) {
+      operand.min = operandJson._min;
+    }
+    if(operandJson._wait) {
+      operand.wait = operandJson._wait;
+    }
+    return operand;
+  },
+  parseConditionTree(conditionJson, condition) {
+    condition.name = conditionJson._name;
+    condition.operands = Ember.A([]);
+    Object.keys(conditionJson).forEach( (key) => {
+      var operandsJson = conditionJson[key];
+      if(key === 'data-in') {
+        if(Array.isArray(operandsJson) ) {
+          operandsJson.forEach((json) => {
+            condition.operands.pushObject(this.extractDataInputOperand(json));
+          }, this);
+        }else{
+          condition.operands.pushObject(this.extractDataInputOperand(operandsJson));
+        }
+      }else if(key !== '_name') {
+        var operand = {};
+        operand.operator = key;
+        operand.type = 'condition';
+        condition.operands.pushObject(operand);
+        this.parseConditionTree(operandsJson, operand);
+      }
+    }, this);
+  },
+  extractDataOutput(dataOutJson){
+    return {
+      dataset:dataOutJson._dataset,
+      name:dataOutJson._name,
+      instance:this.extractDateField(dataOutJson.instance)
+    };
+  },
+  extractOutputEvents(coordinatorApp, coordinator){
+    if (coordinatorApp['output-events'] && coordinatorApp['output-events']['data-out']){
+      var dataOutputsJson = coordinatorApp["output-events"]["data-out"];
+      if(Array.isArray(dataOutputsJson)){
+        dataOutputsJson.forEach(function(dataOutJson){
+          coordinator.dataOutputs.pushObject(this.extractDataOutput(dataOutJson));
+        }, this);
+      }else{
+        coordinator.dataOutputs.pushObject(this.extractDataOutput(dataOutputsJson));
+      }
+    }
+  },
+  extractAction(coordinatorApp, coordinator){
+    var actionJson = coordinatorApp['action']['workflow'];
+    coordinator.workflow.appPath = actionJson['app-path'];
+    if(actionJson.configuration && actionJson.configuration.property){
+      if(Array.isArray(actionJson.configuration.property)){
+        actionJson.configuration.property.forEach(function(prop){
+          coordinator.workflow.configuration.property.push(this.extractConfigProperty(prop));
+        }, this);
+      }else{
+        coordinator.workflow.configuration.property.push(this.extractConfigProperty(actionJson.configuration.property));
+      }
+
+    }
+  },
+  extractConfigProperty(propJson){
+    return {"name" : propJson.name, "value" : propJson.value};
+  },
+  extractParameters(coordinatorApp, coordinator){
+    var paramJson = coordinatorApp['parameters'];
+    if(!paramJson) {
+      return;
+    }
+    if(paramJson.configuration && paramJson.configuration.property){
+      if(Array.isArray(paramJson.configuration.property)){
+        paramJson.configuration.property.forEach(function(prop){
+          coordinator.parameters.configuration.property.push(this.extractConfigProperty(prop));
+        }, this);
+      }else{
+        coordinator.parameters.configuration.property.push(this.extractConfigProperty(paramJson.configuration.property));
+      }
+    }
+  },
+  extractControls(coordinatorApp, coordinator) {
+    var controls = coordinatorApp["controls"];
+    if(controls && Object.keys(controls).length > 0){
+      Object.keys(controls).forEach((controlName)=>{
+        coordinator.controls.pushObject({'name':controlName, 'value':controls[controlName]});
+      }, this);
+    }
+  }
+});
+export { CoordinatorXmlImporter };

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/coordinator/coordinator.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/coordinator/coordinator.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/coordinator/coordinator.js
new file mode 100644
index 0000000..58396d7
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/coordinator/coordinator.js
@@ -0,0 +1,22 @@
+/*
+*    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';
+var Coordinator = Ember.Object.extend({
+
+});
+export {Coordinator};

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/cytoscape-flow-renderer.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/cytoscape-flow-renderer.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/cytoscape-flow-renderer.js
new file mode 100644
index 0000000..086916f
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/cytoscape-flow-renderer.js
@@ -0,0 +1,348 @@
+/*
+*    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 CytoscapeStyles from '../domain/cytoscape-style';
+var CytoscapeRenderer= Ember.Object.extend({
+  currentCyNode: null,
+  staticNodes: ['start', 'end', 'join', 'placeholder'],
+  dataNodes: [],
+  cyOverflow: {},
+  cy: null,
+  layoutConfigs: { name: 'dagre', fit: false, edgeSep: 100 },
+  _initCY(settings){
+    this.get("context").$('#'+this.id).height(settings.canvasHeight);
+    this.cy = cytoscape({
+      container: this.get("context").$('#'+this.id),
+      elements: [],
+      style: CytoscapeStyles.style,
+      layout: this.get("layoutConfigs")
+    });
+
+    // the default values of each option are outlined below:
+    var defaults = {
+      zoomFactor: 2.0, // zoom factor per zoom tick
+      minZoom: 0.1, // min zoom level
+      maxZoom: 10, // max zoom level
+
+      // icon class names
+      sliderHandleIcon: 'fa fa-minus',
+      zoomInIcon: 'fa fa-plus',
+      zoomOutIcon: 'fa fa-minus',
+      resetIcon: 'fa fa-expand'
+    };
+
+    this.cy.panzoom( defaults );
+    //this.cy.center();
+    this.cy.pan({x:200,y:50});
+    this._addEvents(this.cy);
+    var self = this;
+    this.get("context").$('.overlay-transition-content').popover({
+      html : true,
+      title : "Add Node <button type='button' class='close'>&times;</button>",
+      placement: 'right',
+      trigger : 'focus',
+      content : function(){
+        return self.get("context").$('#workflow-actions').html();
+      }
+    });
+
+    this.get("context").$("#cyRenderer").on('click','.popover .close',function(){
+      this.get("context").$('.popover').popover('hide');
+    }.bind(this));
+  },
+  _setCyOverflow() {
+    Ember.set(this.get("cyOverflow"), "overflown", this.cy.elements().renderedBoundingBox().y2 > this.cy.height());
+  },
+  _getShape(nodeType) {
+    switch(nodeType) {
+      case 'start' :
+      case 'end' :
+      case 'kill' :
+      case 'placeholder' :
+        return 'ellipse';
+      case 'action' :
+        return 'roundrectangle';
+      case 'fork' :
+      case 'join' :
+        return 'rectangle';
+      case 'decision' :
+        return 'diamond';
+      default :
+        return 'star';
+    }
+  },
+
+  _getCyDataNodes(workflow){
+    this.get('dataNodes').clear();
+    var self=this;
+    workflow.nodeVisitor.process(workflow.startNode, function(node) {
+      if (node.type === 'kill') {
+        return;
+      }
+      self.get('dataNodes').pushObject({
+        data: {
+          id: node.id, name: node.name, type: node.type,
+          shape: self._getShape(node.type),
+          node: node
+        },
+        dataNodeName: Ember.computed.alias('data.node.name')
+      });
+      if (node.transitions.length > 0) {
+        node.transitions.forEach(function(transition){
+          if (transition.isOnError()){
+            return;
+          }
+          self.get('dataNodes').pushObject(
+            {
+              data: {
+                id: transition.sourceNodeId + '_to_' + transition.targetNode.id,
+                source:transition.sourceNodeId,
+                target: transition.targetNode.id,
+                transition: transition,
+                transitionCount: node.getOkTransitionCount()
+              }
+            }
+          );
+        });
+      }
+    });
+  },
+
+  _showNodeEditor(node, nodeObj){
+    if (nodeObj && this.get("currentCyNode") && (nodeObj.data().id === this.get("currentCyNode").data().id)) {
+      if (this.staticNodes.contains(node.data().type)) {
+        return;
+      }
+      this.get("context").$("#"+ node.data().id  + " :input").show();
+      this.get("context").$("#"+ node.data().id  + " :input").css({
+        top: nodeObj.renderedPosition().y  - (nodeObj.outerHeight()/2),
+        left: nodeObj.renderedPosition().x  - (nodeObj.outerWidth()/2)
+      });
+    }
+    this.set("currentCyNode", nodeObj);
+  },
+
+  _showNodeTooltip(event){
+    var node = event.cyTarget;
+    var nodeObj = this.cy.$('#' + node.id());
+    if (this.staticNodes.contains(node.data().type)) {
+      return;
+    }
+    this.get("context").$(".overlay-node-label").css({
+      top: nodeObj.renderedPosition().y - (nodeObj.outerHeight() - ((node.data().type === 'decision')?20:0)),
+      left: nodeObj.renderedPosition().x + (nodeObj.outerWidth()/2 - 30)
+    });
+    this.get("context").$(".overlay-node-label").text(node.data().node.name);
+    this.get("context").$(".overlay-node-label").show();
+  },
+
+  _addEvents(cy){
+    cy.on('pan', function() {
+      this.get("context").$(".overlay_node_editor, .overlay-node-actions, .overlay-fork-icon, .overlay-trash-icon, .overlay-settings-icon").hide();
+      this.get("context").$(".overlay-transition-content").hide();
+      this._setCyOverflow();
+    }.bind(this));
+
+    cy.on('click', function(event) {
+      if (event.cyTarget === cy) {
+        this.get("context").$(".overlay_node_editor, .overlay-node-actions, .overlay-fork-icon, .overlay-trash-icon, .overlay-settings-icon").hide();
+        this.get("context").$(".overlay-transition-content").hide();
+      }
+    }.bind(this));
+
+    cy.on('mousemove', 'node', function(event) {
+      event.cyTarget.css({'border-color': '#5bb75b'});
+      this.get("context").actionInfo(event.cyTarget.data().node);
+      this._showNodeTooltip(event);
+    }.bind(this));
+
+    cy.on('mouseout', 'node',function(event) {
+      event.cyTarget.css({'border-color': '#ABABAB'});
+      this.get("context").$(".overlay-node-label").hide();
+    }.bind(this));
+
+    cy.on('mousemove', 'edge', function(event) {
+      event.cyTarget.css({'line-color': '#5bb75b', 'target-arrow-color': '#5bb75b'});
+    }.bind(this));
+
+    cy.on('mouseout', 'edge',function(event) {
+      event.cyTarget.css({'line-color': '#ABABAB', 'target-arrow-color': '#ABABAB'});
+    }.bind(this));
+
+    cy.on('click', 'node', function(event) {
+      this.get("context").$(".overlay-node-actions span").hide();
+      this.get("context").$(".overlay-transition-content").hide();
+      var node = event.cyTarget;
+      var nodeObj = cy.$('#' + node.id());
+      this._showNodeEditor(node, nodeObj);
+      if (!(node.data().type === 'start' || node.data().type === 'end' || node.data().type === 'placeholder')) {
+        this.get("context").$(".overlay-node-actions, .overlay-trash-icon").show();
+      }
+      if (node.data().type === 'action' || node.data().type === 'decision') {
+        this.get("context").$(".overlay-settings-icon").show();
+      }
+      if (node.data().type === 'action') {
+        this.get("context").$(".overlay-copy-icon").show();
+        this.get("context").$(".overlay-cut-icon").show();
+        if(this.get('context').get('clipboard')){
+          this.get("context").$(".overlay-paste-icon").show();
+        }
+      }
+      if (node.data().type === 'fork' || node.data().type === 'decision') {
+        this.get("context").$(".overlay-fork-icon").show();
+      }
+      this.get("context").$(".overlay-node-actions").css({
+        top: nodeObj.renderedPosition().y - (nodeObj.outerHeight()) + 20,
+        left: nodeObj.renderedPosition().x + (nodeObj.outerWidth()/3) + 50
+      });
+      this.get("context").$(".overlay-trash-icon, .overlay-fork-icon, .overlay-settings-icon, .overlay-copy-icon, .overlay-paste-icon, .overlay-cut-icon").data("node", node.data().node);
+    }.bind(this));
+
+    cy.on('click', 'edge', function(event) {
+      this.get("context").$(".decision-condition-label").hide();
+      this.get("context").$(".overlay-transition-content").hide();
+      this.get("context").$(".overlay_node_editor, .overlay-node-actions, .overlay-fork-icon, .overlay-trash-icon, .overlay-settings-icon").hide();
+      this.get("context").$(".overlay-transition-content").show();
+      this.get("context").$(".overlay-transition-content").css({
+        top: event.originalEvent.offsetY + 10,
+        left: event.originalEvent.offsetX + 15
+      });
+      if (event.cyTarget.data().transitionCount>1){
+            this.get("context").$(".overlay-trash-transition-icon").show();
+      }else{
+          this.get("context").$(".overlay-trash-transition-icon").hide();
+      }
+      this.get("context").$(".overlay-transition-content").data("transition",event.cyTarget.data().transition);
+
+      if (event.cyTarget.data().transition && event.cyTarget.data().transition.condition) {
+        this.get("context").$(".decision-condition-body").html(event.cyTarget.data().transition.condition);
+        this.get("context").$(".decision-condition-label").css({
+          top: event.originalEvent.offsetY,
+          left: event.originalEvent.offsetX + 10
+        });
+        this.get("context").$(".decision-condition-label").show();
+      }
+    }.bind(this));
+
+    this.get("context").$('.overlay-plus-icon').off('click');
+    this.get("context").$('.overlay-plus-icon').on('click',function(){
+      this.get("context").$(".overlay-transition-content").popover("show");
+      this.get("context").set('popOverElement', this.get("context").$('.overlay-transition-content'));
+      this.get("context").setCurrentTransition(this.get("context").$(".overlay-transition-content").data("transition"));
+      Ember.run.later(this, function() {
+        this.get("context").$('.overlay-transition-content').hide();
+      }, 1000);
+    }.bind(this));
+
+    this.get("context").$('.overlay-trash-transition-icon').off('click');
+    this.get("context").$('.overlay-trash-transition-icon').on('click',function(){
+      this.get("context").deleteTransition(this.get("context").$(".overlay-transition-content").data("transition"));
+      this.get("context").$('.overlay-transition-content').hide();
+    }.bind(this));
+
+    this.get("context").$('.overlay-trash-icon i').off('click');
+    this.get("context").$('.overlay-trash-icon i').on('click',function(){
+      this.get("context").deleteWorkflowNode(this.get("context").$(".overlay-trash-icon").data("node"));
+      this.get("context").$('.overlay-node-actions').hide();
+    }.bind(this));
+
+    this.get("context").$('.overlay-copy-icon i').off('click');
+    this.get("context").$('.overlay-copy-icon i').on('click',function(){
+      this.get("context").copyNode(this.get("context").$(".overlay-copy-icon").data("node"));
+      this.get("context").$('.overlay-node-actions').hide();
+    }.bind(this));
+
+    this.get("context").$('.overlay-paste-icon i').off('click');
+    this.get("context").$('.overlay-paste-icon i').on('click',function(){
+      this.get("context").replaceNode(this.get("context").$(".overlay-paste-icon").data("node"));
+      this.get("context").$('.overlay-node-actions').hide();
+    }.bind(this));
+
+    this.get("context").$('.overlay-cut-icon i').off('click');
+    this.get("context").$('.overlay-cut-icon i').on('click',function(){
+      this.get("context").cutNode(this.get("context").$(".overlay-cut-icon").data("node"));
+      this.get("context").$('.overlay-node-actions').hide();
+    }.bind(this));
+
+    this.get("context").$('.overlay-fork-icon i').off('click');
+    this.get("context").$('.overlay-fork-icon i').on('click',function(){
+      var node = this.get("context").$(".overlay-fork-icon").data("node");
+
+      if (node.isDecisionNode()) {
+        this.get("context").openDecisionEditor(this.get("context").$(".overlay-fork-icon").data("node"));
+        this.get("context").$("#selector-content").css({
+          top: this.get("currentCyNode").renderedPosition().y - (this.get("currentCyNode").outerHeight()),
+          left: this.get("currentCyNode").renderedPosition().x + (this.get("currentCyNode").outerWidth()/2)
+        });
+      } else if (node.isForkNode()) {
+        this.get("context").addWorkflowBranch(this.get("context").$(".overlay-fork-icon").data("node"));
+      }
+      this.get("context").$('.overlay-node-actions').hide();
+    }.bind(this));
+
+    this.get("context").$('.overlay-settings-icon i').off('click');
+    this.get("context").$('.overlay-settings-icon i').on('click',function(){
+      this.get("context").openWorkflowEditor(this.get("context").$(".overlay-settings-icon").data("node"));
+      this.get("context").$('.overlay-node-actions').hide();
+    }.bind(this));
+  },
+
+  renderWorkflow(workflow){
+    this._getCyDataNodes(workflow);
+    this.cy.$('node').remove();
+    this.cy.add(this.get('dataNodes'));
+    this.cy.layout(this.get("layoutConfigs"));
+    this._setCyOverflow();
+  },
+
+  initRenderer(callback, settings){
+    this.context=settings.context;
+    this.dataNodes=settings.dataNodes;
+    this.cyOverflow=settings.cyOverflow;
+    this._initCY(settings);
+    callback();
+  },
+  reset(){
+
+  },
+  resetLayout() {
+    this.cy.layout();
+  },
+  refresh(){
+
+  },
+  onDidUpdate(){
+    return true;
+  },
+  cleanup(){
+  },
+  resize(){
+    if (this.cy){
+      Ember.run.later(this, function() {
+        this.cy.resize();
+      },50);
+    }
+  },
+  getBottomPosition() {
+    return {
+      top: this.get("context").$('#'+this.id).offset().top + this.get("context").$('#'+this.id).height,
+      left: this.get("context").$('#'+this.id).offset().left + 100
+    };
+  }
+});
+export {CytoscapeRenderer};

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/cytoscape-style.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/cytoscape-style.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/cytoscape-style.js
new file mode 100644
index 0000000..92820f9
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/cytoscape-style.js
@@ -0,0 +1,123 @@
+/*
+ *    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';
+var defaultNodeColor = '#fff';
+var actionNodeColor = '#f5f5f5';
+export default Ember.Object.create({
+  style: [
+    {
+      selector: 'node',
+      style: {
+        shape: 'data(shape)',
+        'background-color': defaultNodeColor,
+        'border-width': 1,
+        'border-color': '#ABABAB',
+        //'text-margin-x': 10,
+        label: function(target) {
+          if (!target.data().node.name) {
+            return "";
+          } else if (target.data().node.name.length>12){
+            return target.data().node.name.slice(0, 12)+"...";
+          } else{
+            return target.data().node.name;
+          }
+        },
+        'text-valign': 'center',
+        'font-size': 14,
+        height: 40,
+        width: 40
+      }
+    },
+    {
+      selector: 'node[type = "fork"]',
+      style: {
+        'background-image': 'assets/sitemap.png',
+        'background-position-x': 10,
+        width: 150
+      }
+    },
+    {
+      selector: 'node[type = "join"]',
+      style: {
+        'background-image': 'assets/join.png',
+        label: '',
+        width: 80
+      }
+    },
+    {
+      selector: 'node[type = "decision"]',
+      style: {
+        height: 60,
+        width: 120
+      }
+    },
+    {
+      selector: 'node[type = "start"]',
+      style: {
+        'background-image': 'assets/play.png',
+        label: ''
+      }
+    },
+    {
+      selector: 'node[type = "end"]',
+      style: {
+        'background-image': 'assets/stop.png',
+        label: ''
+      }
+    },
+    {
+      selector: 'node[type = "placeholder"]',
+      style: {
+        width: 1,
+        height: 1,
+        label: ''
+      }
+    },
+    {
+      selector: 'node[type = "action"]',
+      style: {
+        'background-color': actionNodeColor,
+        width: 150
+      }
+    },
+    {
+      selector: 'edge',
+      style: {
+        'curve-style': 'bezier',
+				'target-arrow-shape': function(target){
+          if (target.data().transition && target.data().transition.getTargetNode(false) && !target.data().transition.getTargetNode(false).isPlaceholder()) {
+            return "triangle";
+          }else{
+            return "none";
+          }
+        },
+        width: 1,
+        'font-size': 12,
+        label: function(target) {
+          if (!target.data().transition || !target.data().transition.condition) {
+            return "";
+          }else if (target.data().transition.condition.length>5){
+            return target.data().transition.condition.slice(0, 5)+"...";
+          }else{
+            return target.data().transition.condition;
+          }
+        }
+      }
+    }
+  ]
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/default-layout-manager.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/default-layout-manager.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/default-layout-manager.js
index e208f83..b7121f4 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/default-layout-manager.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/default-layout-manager.js
@@ -17,13 +17,13 @@
 
 import Ember from 'ember';
 var DefaultLayoutManager= Ember.Object.extend({
-  doDagreLayout(nodes,edges){
+  doDagreLayout(component, nodes,edges){
     var g = new dagre.graphlib.Graph();
     g.setGraph({rankdir:"TB", nodesep:100,edgesep:200,marginx:40,ranksep:130});
     g.setDefaultEdgeLabel(function() { return {}; });
 
     for (var i = 0; i < nodes.length; i++) {
-      var n = Ember.$(nodes[i]);
+      var n = component.$(nodes[i]);
       g.setNode(n.attr("id"), {width: n.width(), height: n.height()});
     }
 
@@ -35,13 +35,13 @@ var DefaultLayoutManager= Ember.Object.extend({
     return g;
   },
   doLayout(component,nodes,edges){
-    var g=this.doDagreLayout(nodes,edges);
+    var g=this.doDagreLayout(component, nodes,edges);
     g.nodes().forEach(function(v) {
       try{
         var nodeWidth=component.$("#" + v).width();
         var displacement=150-Math.floor(nodeWidth/2);
-        Ember.$("#" + v).css("left", g.node(v).x+displacement + "px");
-        Ember.$("#" + v).css("top",g.node(v).y+ "px");
+        component.$("#" + v).css("left", g.node(v).x+displacement + "px");
+        component.$("#" + v).css("top",g.node(v).y+ "px");
       }catch(err){
       }
     });

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/findnode-mixin.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/findnode-mixin.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/findnode-mixin.js
index 0566e06..c770fb0 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/findnode-mixin.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/findnode-mixin.js
@@ -18,22 +18,65 @@
 import Ember from 'ember';
 var FindNodeMixin= Ember.Mixin.create({
   findNodeById(startNode,id){
-
-    return this.findNodeByIdInternal(startNode,id);
+    return this._findNodeById(startNode,id);
+  },
+  findTransition(startNode,sourceId,targetId){
+    return this._findTransition(startNode,sourceId,targetId);
+  },
+  _findTransition(node,sourceId,targetId){
+    if (!node.transitions){
+      return null;
+    }
+    var res;
+    for (var i = 0; i < node.transitions.length; i++) {
+      var tran= node.transitions[i];
+      if (node.id===sourceId && tran.getTargetNode(false).id===targetId){
+        res=tran;
+      }else{
+        res=this._findTransition(tran.getTargetNode(false),sourceId,targetId);
+      }
+      if (res){
+        break;
+      }
+    }
+    return res;
+  },
+  findTransitionTo(startNode,nodeid){
+    return this._findTransitionTo(startNode,nodeid);
+  },
+  _findTransitionTo(node,nodeid){
+    if (!node.transitions){
+      return null;
+    }
+    var res;
+    for (var i = 0; i < node.transitions.length; i++) {
+      var tran= node.transitions[i];
+      if (tran.getTargetNode(false).id===nodeid){
+        res=tran;
+      }else{
+        res=this._findTransitionTo(tran.getTargetNode(false),nodeid);
+      }
+      if (res){
+        break;
+      }
+    }
+    return res;
   },
-  findNodeByIdInternal(node,id){
+  _findNodeById(node,id){
     var self=this;
     if (node.get("id")===id){
       return node;
     }else{
       if (node.transitions){
+        var res;
         for (var i = 0; i < node.transitions.length; i++) {
           var transition=node.transitions[i];
-          var result=self.findNodeByIdInternal(transition.getTargetNode(true),id);
-          if (result){
-            return result;
+          res= self._findNodeById(transition.getTargetNode(false),id);
+          if (res){
+            break;
           }
         }
+        return res;
       }else{
         return null;
       }
@@ -63,7 +106,7 @@ var FindNodeMixin= Ember.Mixin.create({
     for(var i =0; i< nxtPath.length; i++){
       currNode = nxtPath[i];
       do {
-        if(this.insertUniqueNodes(currNode, nodes) && currNode){
+        if(this._insertUniqueNodes(currNode, nodes) && currNode){
           nodes.push(currNode);
         }
         var nodesList = currNode.getTargets();
@@ -74,7 +117,7 @@ var FindNodeMixin= Ember.Mixin.create({
               if(tmp.length){
                 nodes = nodes.concat(tmp);
               }
-            } else if(this.insertUniqueNodes(nodesList[j], nodes) && nodesList[j]){
+            } else if(this._insertUniqueNodes(nodesList[j], nodes) && nodesList[j]){
               nodes.push(nodesList[j]);
               currNode = nodesList[j];
             } else {
@@ -91,7 +134,7 @@ var FindNodeMixin= Ember.Mixin.create({
     }
     return nodes;
   },
-  insertUniqueNodes(currNode, nodes){
+  _insertUniqueNodes(currNode, nodes){
     if(nodes.indexOf(currNode) > -1){
     } else {
       if (!( currNode.isKillNode() || currNode.isPlaceholder() || currNode.isJoinNode() || currNode.isDecisionEnd())){
@@ -99,5 +142,57 @@ var FindNodeMixin= Ember.Mixin.create({
       }
     }
   },
+  _findCommonTargetNodeId(node){
+    var nodeIds = {}, targ, decPath = node.getTargets(), tempId = 0;
+    for(var i =0; i< decPath.length; i++){
+      var currNode = decPath[i];
+      do {
+        if(nodeIds.hasOwnProperty(currNode.get("id"))){
+          nodeIds[currNode.get("id")] = nodeIds[currNode.get("id")] + 1;
+        } else {
+          nodeIds[currNode.get("id")] = 1;
+        }
+        if(currNode.get("id") === "node-end"){
+          break;
+        }
+        currNode = currNode.getTargets()[0];
+      } while(currNode && currNode.get("id"));
+    }
+    for(var j in nodeIds){
+      if(tempId < nodeIds[j]){
+        targ = j;
+        tempId = nodeIds[j];
+      }
+    }
+    return targ;
+  },
+  _findCommonTargetNode(node){
+    var nodeIds = {}, targ, decPath = node.getTargets(), tempId = 0;
+    for(var i =0; i< decPath.length; i++){
+      var currNode = decPath[i];
+      do {
+        if(nodeIds.hasOwnProperty(currNode.get("id"))){
+          nodeIds[currNode.get("id")] = nodeIds[currNode.get("id")] + 1;
+        } else {
+          nodeIds[currNode.get("id")] = 1;
+        }
+        if(currNode.get("id") === "node-end"){
+          break;
+        }
+        currNode = currNode.getTargets()[0];
+      } while(currNode && currNode.get("id"));
+    }
+    for(var j in nodeIds){
+      if(tempId < nodeIds[j]){
+        targ = j;
+        tempId = nodeIds[j];
+      }
+    }
+    return targ;
+  },
+  findCommonTargetNode(startNode,node){
+    var commonTargetId=this._findCommonTargetNodeId(node);
+    return this.findNodeById(startNode,commonTargetId);
+  }
 });
 export{FindNodeMixin};

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/id-gen.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/id-gen.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/id-gen.js
index 0ee985e..ccbfcc3 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/id-gen.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/id-gen.js
@@ -29,6 +29,10 @@ var IdGen = Ember.Object.extend({
   reset(){
     this.nameCount=0;
     this.idCount=0;
+  },
+  resetTo(val){
+    this.nameCount=val;
+    this.idCount=val;
   }
 });
 var idGen=IdGen.create({});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/jsplumb-flow-renderer.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/jsplumb-flow-renderer.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/jsplumb-flow-renderer.js
new file mode 100644
index 0000000..c3e3133
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/jsplumb-flow-renderer.js
@@ -0,0 +1,194 @@
+/*
+*    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 Constants from '../utils/constants';
+import {DefaultLayoutManager as LayoutManager} from '../domain/default-layout-manager';
+var JSPlumbRenderer= Ember.Object.extend({
+  designerPlumb:null,
+  flattenedNodes:null,
+  _createConnection(sourceNode,target,transition){
+    var connectionColor="#777";
+    var lineWidth=1;
+    if (transition.condition){
+      if(transition.condition==="default"){
+        lineWidth=2;
+      }else if (transition.condition==="error"|| transition.errorPath){
+        connectionColor=Constants.globalSetting.errorTransitionColor;
+      }
+    }
+    var connectionObj={
+      source:sourceNode.id,
+      target:target.id,
+      connector:["Straight"],
+      paintStyle:{lineWidth:lineWidth,strokeStyle:connectionColor},
+      endpointStyle:{fillStyle:'rgb(243,229,0)'},
+      endpoint: ["Dot", {
+        radius: 1
+      }],
+      alwaysRespectStubs:true,
+      anchors: [["Bottom"],["Top"]],
+      overlays:[]
+    };
+    return connectionObj;
+  },
+  _getAddNodeOverlay(context,sourceNode,target,transition){
+    var location=target.type==="placeholder"?1:0.5;
+    var transitionCount=sourceNode.transitions.length;
+    return {
+      id: sourceNode.id+"_"+target.id+"_"+"connector",
+      location:location,
+      /* jshint unused:vars */
+      create:function(component) {
+        var container=Ember.$('<div />');
+        var plus= Ember.$('<div class="fa fa-plus connector_overlay_new"></div>');
+        if ((sourceNode.isDecisionNode() && transitionCount>1 ||sourceNode.isForkNode() && transitionCount>2 ) &&
+        target.isPlaceholder() &&
+        !transition.isDefaultCasePath()){
+          var trash=Ember.$('<div class="node_actions node_left"><i class="fa fa-trash-o"></i></div>');
+          trash.on("click",function(){
+            context.deleteTransition(transition);
+          });
+          plus.append(trash);
+        }
+        container.append(plus);
+        return container;
+      },
+      events:{
+        click:function(labelOverlay, originalEvent) {
+          var element = originalEvent.target;
+          context.set('popOverElement', element);
+          context.setCurrentTransition(transition);
+          context.showWorkflowActionSelect(element);
+        }
+      }
+    };
+  },
+
+  _renderNodes(node,visitedNodes){
+    if (!node || node.isKillNode()){
+      return;
+    }
+    if (visitedNodes.contains(node)){
+      return;
+    }
+    visitedNodes.push(node);
+    if(!this.get("flattenedNodes").contains(node)){
+      this.get("flattenedNodes").pushObject(node);
+    }
+    if (node.transitions.length > 0){
+      node.transitions.forEach(function(transition) {
+        var target = transition.targetNode;
+        this._renderNodes(target,visitedNodes);
+      }.bind(this));
+    }
+  },
+  _connectNodes(context,sourceNode){
+    var connections=[];
+    var visitedNodes=[];
+    this._renderTransitions(sourceNode,connections,visitedNodes,context);
+    this._layout(connections);
+    this.designerPlumb.setSuspendDrawing(true);
+    this.designerPlumb.batch(function(){
+      connections.forEach(function(conn){
+        this.designerPlumb.connect(conn);
+      }.bind(this));
+    }.bind(this));
+    this.designerPlumb.setSuspendDrawing(false,true);
+
+  },
+  _renderTransitions(sourceNode,connections,visitedNodes,context){
+    var self=this;
+    if(!sourceNode){
+      return;
+    }
+    if (visitedNodes.contains(sourceNode)){
+      return;
+    }
+    if (sourceNode.hasTransition() ){
+      sourceNode.transitions.forEach(function(transition) {
+        var target = transition.targetNode;
+        if (target.isKillNode() || !Constants.showErrorTransitions && transition.isOnError()){
+          return;
+        }
+        var connectionObj=self._createConnection(sourceNode,target,transition);
+
+        if (transition.condition){
+          var conditionHTML = "<div class='decision-condition' title='"+transition.condition+"'>"+ transition.condition+"</div>";
+          connectionObj.overlays.push([ "Label", {label:conditionHTML, location:0.75, id:"myLabel" } ]);
+        }
+        if (!target.isPlaceholder()){
+          connectionObj.overlays.push(["PlainArrow",{location:-0.1,width: 7,length: 7}]);
+        }
+        if (!(sourceNode.isPlaceholder() || target.isKillNode())){
+          var addNodeoverlay=["Custom" , self._getAddNodeOverlay(context,sourceNode,target,transition)];
+          connectionObj.overlays.push(addNodeoverlay);
+        }
+        connections.push(connectionObj);
+        self._renderTransitions(target,connections,visitedNodes,context);
+      });
+    }
+  },
+  _layout(edges){
+    var nodes = Ember.$(".nodecontainer");
+    this.layoutManager.doLayout(this.get("context"),nodes,edges,this.get("workflow"));
+  },
+  initRenderer(callback,settings){
+    this.designerPlumb=jsPlumb.getInstance({});
+    this.layoutManager=LayoutManager.create({});
+    this.context=settings.context;
+    this.flattenedNodes=settings.flattenedNodes;
+    this.designerPlumb.ready(function() {
+      callback();
+    }.bind(this));
+    return this.designerPlumb;
+  },
+  refresh(){
+    this.designerPlumb.repaintEverything();
+  },
+  reset(){
+    if(!this.get('flattenedNodes')){
+      return;
+    }
+    this.get("flattenedNodes").clear();
+    this.designerPlumb.reset();
+  },
+  cleanup(){
+    if(!this.get('flattenedNodes')){
+      return;
+    }
+    this.get('flattenedNodes').clear();
+    this.designerPlumb.detachEveryConnection();
+  },
+  onDidUpdate(){
+    this._connectNodes(this.get("context"),this.get("workflow").startNode,this.get("workflow"));
+  },
+  renderWorkflow(workflow){
+    var visitedNodes=[];
+    this.set("workflow",workflow);
+    this._renderNodes(this.get("workflow").startNode,visitedNodes);
+  },
+
+  getBottomPosition(){
+    return {
+      top : this.get("context").$(".nodeEnd").offset().top,
+      left : this.get("context").$(".nodeEnd").offset().left
+    };
+  }
+
+});
+export {JSPlumbRenderer};

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/mapping-utils.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/mapping-utils.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/mapping-utils.js
index 7cb82e1..2962e71 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/mapping-utils.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/mapping-utils.js
@@ -22,7 +22,6 @@ var MappingMixin= Ember.Mixin.create({
   handleMapping(nodeDomain,nodeObj,mappings,nodeName){
     var self=this;
     mappings.forEach(function(mapping){
-      var nodeVals=[];
       if (mapping.mandatory){
         if (!(nodeDomain[mapping.domain] || mapping.customHandler)){
           var msgForVal=mapping.domain;
@@ -113,6 +112,7 @@ var MappingMixin= Ember.Mixin.create({
   }
 });
 var ConfigurationMapper= Ember.Object.extend({
+  /* jshint unused:vars */
   hanldeGeneration(node,nodeObj){
     if (!node || !node.configuration || !node.configuration.property){
       return;
@@ -205,24 +205,25 @@ var SLAMapper= Ember.Object.extend({
   hanldeGeneration(sla,nodeObj){
     if (sla){
       var slaInfo=nodeObj["info"]={};
-      slaInfo["__prefix"]="sla";
+      var slaPrefix="sla";
+      slaInfo["__prefix"]=slaPrefix;
       if (sla.nominalTime){
-        slaInfo["nominal-time"]=sla.nominalTime;
+        slaInfo[slaPrefix+":"+"nominal-time"]=sla.nominalTime;
       }
       if (sla.shouldStart){
-        slaInfo["should-start"]="${"+sla.shouldStart.time+ "*"+sla.shouldStart.unit+"}";
+        slaInfo[slaPrefix+":"+"should-start"]="${"+sla.shouldStart.time+ "*"+sla.shouldStart.unit+"}";
       }
       if (sla.shouldEnd){
-        slaInfo["should-end"]="${"+sla.shouldEnd.time+ "*"+sla.shouldEnd.unit+"}";
+        slaInfo[slaPrefix+":"+"should-end"]="${"+sla.shouldEnd.time+ "*"+sla.shouldEnd.unit+"}";
       }
       if (sla.maxDuration){
-        slaInfo["max-duration"]="${"+sla.maxDuration.time+ "*"+sla.maxDuration.unit+"}";
+        slaInfo[slaPrefix+":"+"max-duration"]="${"+sla.maxDuration.time+ "*"+sla.maxDuration.unit+"}";
       }
       if (sla.alertEvents){
-        slaInfo["alert-events"]=sla.alertEvents;
+        slaInfo[slaPrefix+":"+"alert-events"]=sla.alertEvents;
       }
       if (sla.alertContact){
-        slaInfo["alert-contact"]=sla.alertContact;
+        slaInfo[slaPrefix+":"+"alert-contact"]=sla.alertContact;
       }
 
     }
@@ -230,18 +231,22 @@ var SLAMapper= Ember.Object.extend({
   },
   handleImport(domain,infoJson,key){
     var sla=domain[key]=SlaInfo.create({});
-    if (infoJson["nominal-time"]){
-      sla.nominalTime=infoJson["nominal-time"];
+    if (infoJson["nominal-time"] && infoJson["nominal-time"].__text){
+      sla.nominalTime=infoJson["nominal-time"].__text;
+    }
+    if (infoJson["alert-contact"]&& infoJson["alert-contact"].__text){
+      sla.alertContact=infoJson["alert-contact"].__text;
+    }
+    if (infoJson["alert-events"] && infoJson["alert-events"].__text){
+      sla.alertEvents=infoJson["alert-events"].__text;
     }
-    sla.alertContact=infoJson["alert-contact"];
-    sla.alertEvents=infoJson["alert-events"];
     this.processTimePeriods(sla,infoJson,"should-start","shouldStart");
     this.processTimePeriods(sla,infoJson,"should-end","shouldEnd");
     this.processTimePeriods(sla,infoJson,"max-duration","maxDuration");
   },
   processTimePeriods(sla,infoJson,key,domainKey){
     if (infoJson[key]){
-      var timeParts=this.parseSlaTime(infoJson[key],key);
+      var timeParts=this.parseSlaTime(infoJson[key].__text,key);
       sla[domainKey].time=timeParts[0];
       sla[domainKey].unit=timeParts[1];
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/node-factory.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/node-factory.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/node-factory.js
index c440b8c..b6e2c73 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/node-factory.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/node-factory.js
@@ -21,10 +21,10 @@ import {Node} from '../domain/node';
 import {idGen} from '../domain/id-gen';
 var NodeFactory= Ember.Object.extend({
   createStartNode(){
-    return this.createNode({id:'node-start', type:'start',name:"Start"});
+    return this.createNode({id:this.generateNodeId(), type:'start',name:"Start"});
   },
   createEndNode(name){
-    return this.createNode({id:'node-end', type:'end', name:name});
+    return this.createNode({id:this.generateNodeId(), type:'end', name:name});
   },
   createKillNode(name,message){
     return this.createNode({id:this.generateNodeId(), type:"kill", name:name,killMessage:message});
@@ -108,6 +108,9 @@ var NodeFactory= Ember.Object.extend({
   },
   createNode(settings){
     settings.factory=this;
+	if (!settings.id){
+      settings.id=this.generateNodeId();
+    }
     return Node.create(settings);
   },
   generateNodeId(){
@@ -115,6 +118,9 @@ var NodeFactory= Ember.Object.extend({
   },
   generateName(){
     return idGen.generateNodeName();
+  },
+  resetNodeIdTo(id){
+    return idGen.resetTo(id);
   }
 });
 export{NodeFactory};

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/node-handler.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/node-handler.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/node-handler.js
index 49347d8..6bc305a 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/node-handler.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/node-handler.js
@@ -17,49 +17,8 @@
 
 import Ember from 'ember';
 import {NodeFactory} from '../domain/node-factory';
-import * as actionJobHandler from '../domain/actionjob_hanlder';
-import {SlaInfo} from '../domain/sla-info';
 import {SLAMapper} from "../domain/mapping-utils";
-var ActionTypeResolver=Ember.Object.extend({
-  actionJobHandlerMap:null,
-  validStandardActionProps:["ok","error","info"],
-  init(){
-    var settings={schemaVersions:this.schemaVersions};
-    this.actionJobHandlerMap=new Map();
-    this.actionJobHandlerMap.set("java",actionJobHandler.JavaActionJobHandler.create(settings));
-    this.actionJobHandlerMap.set("pig",actionJobHandler.PigActionJobHandler.create(settings));
-    this.actionJobHandlerMap.set("hive",actionJobHandler.HiveActionJobHandler.create(settings));
-    this.actionJobHandlerMap.set("hive2",actionJobHandler.Hive2ActionJobHandler.create(settings));
-    this.actionJobHandlerMap.set("sqoop",actionJobHandler.SqoopActionJobHandler.create(settings));
-    this.actionJobHandlerMap.set("shell",actionJobHandler.ShellActionJobHandler.create(settings));
-    this.actionJobHandlerMap.set("spark",actionJobHandler.SparkActionJobHandler.create(settings));
-    this.actionJobHandlerMap.set("map-reduce",actionJobHandler.MapRedActionJobHandler.create(settings));
-    this.actionJobHandlerMap.set("sub-workflow",actionJobHandler.SubWFActionJobHandler.create(settings));
-    this.actionJobHandlerMap.set("distcp",actionJobHandler.DistCpJobHandler.create(settings));
-    this.actionJobHandlerMap.set("ssh",actionJobHandler.SshActionJobHandler.create(settings));
-    this.actionJobHandlerMap.set("email",actionJobHandler.EmailActionJobHandler.create(settings));
-    this.actionJobHandlerMap.set("fs",actionJobHandler.FSActionJobHandler.create(settings));
-  },
-  getActionType(json){
-    var self=this;
-    var resolvedType=null;
-    var problaleActionsTypes=[];
-    Object.keys(json).forEach(function functionName(key) {
-      if (!self.validStandardActionProps.contains(key) && !key.startsWith("_")){
-        problaleActionsTypes.push(key);
-      }
-    });
-    if (problaleActionsTypes.length===1){
-      return problaleActionsTypes[0];
-    }else{
-      console.error("Invalid Action spec..",json);
-    }
-    return resolvedType;
-  },
-  getActionJobHandler(jobType){
-    return this.actionJobHandlerMap.get(jobType);
-  }
-});
+
 var NodeHandler=Ember.Object.extend({
   nodeFactory:NodeFactory.create({}),
   context : {},
@@ -75,12 +34,14 @@ var NodeHandler=Ember.Object.extend({
   handleNode(node){
     return {"_name":node.get("name")};
   },
-
+  /* jshint unused:vars */
   handleTransitions(transitions,nodeObj){
 
   },
+  /* jshint unused:vars */
   handleImportNode(type,node){
   },
+    /* jshint unused:vars */
   handleImportTransitions(node,json,nodeMap){
   }
 });
@@ -248,4 +209,4 @@ var JoinNodeHandler= NodeHandler.extend({
     node.addTransitionTo(nodeMap.get(json._to).node);
   }
 });
-export{ActionTypeResolver,NodeHandler,StartNodeHandler,EndNodeHandler,KillNodeHandler,ActionNodeHandler,DecisionNodeHandler,ForkNodeHandler,JoinNodeHandler};
+export{NodeHandler,StartNodeHandler,EndNodeHandler,KillNodeHandler,ActionNodeHandler,DecisionNodeHandler,ForkNodeHandler,JoinNodeHandler};

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/node.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/node.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/node.js
index c7ce003..cda7609 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/node.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/node.js
@@ -100,7 +100,7 @@ var Node = Ember.Object.extend(FindNodeMixin,{
     }
   },
   addTransitionTo(target,condition){
-    var transition = Transition.create({targetNode:target,sourceNode:this,condition:condition});
+    var transition = Transition.create({targetNode:target,sourceNodeId:this.id,condition:condition});
     this.addTransition(transition);
     return transition;
   },
@@ -120,7 +120,6 @@ var Node = Ember.Object.extend(FindNodeMixin,{
   },
 
   removeTransition(transition){
-    var transitions=this.get("transitions");
     if (transition && this.transitions.indexOf(transition) > -1) {
       this.transitions.splice(this.transitions.indexOf(transition), 1);
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/sla-info.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/sla-info.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/sla-info.js
index 76dffbd..9d90280 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/sla-info.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/sla-info.js
@@ -17,43 +17,43 @@
 import Ember from 'ember';
 var SlaInfo = Ember.Object.extend(Ember.Copyable,{
   copy (){
-    var slaInfo = {}
+    var slaInfo = {};
     for (let key in this) {
       slaInfo[key] = Ember.copy(this[key]) ;
     }
     return slaInfo;
   },
   init (){
-    this.nominalTime='';
+    this.nominalTime=undefined;
     this.shouldStart = {
-      time : '',
-      unit : ''
+      time : undefined,
+      unit : undefined
     };
     this.shouldEnd = {
-      time : '',
-      unit : ''
+      time : undefined,
+      unit : undefined
     };
     this.maxDuration = {
-      time : '',
-      unit : ''
+      time : undefined,
+      unit : undefined
     };
-    this.alertEvents = '';
-    this.alertContacts = '';
+    this.alertEvents = undefined;
+    this.alertContacts = undefined;
   },
-  nominalTime:'',
+  nominalTime:undefined,
   shouldStart : {
-    time : '',
-    unit : ''
+    time : undefined,
+    unit : undefined
   },
   shouldEnd : {
-    time : '',
-    unit : ''
+    time : undefined,
+    unit : undefined
   },
   maxDuration : {
-    time : '',
-    unit : ''
+    time : undefined,
+    unit : undefined
   },
-  alertEvents : '',
-  alertContacts : ''
+  alertEvents : undefined,
+  alertContacts : undefined
 });
 export {SlaInfo};

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/transition.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/transition.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/transition.js
index 70d7a81..b14484e 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/transition.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/transition.js
@@ -18,7 +18,6 @@
 import Ember from 'ember';
 var Transition = Ember.Object.extend({
   id:null,
-  sourceNode:null,
   targetNode:null,
   type:null,
   condition:null,
@@ -35,9 +34,7 @@ var Transition = Ember.Object.extend({
   isDefaultCasePath(){
     return this.condition==="default";
   },
-  getSourceNode(){
-    return this.get("sourceNode");
-  },
+
   getTargetNode(skipPlaceholder){
     var currNode=this.targetNode;
     if (skipPlaceholder===false){

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-importer.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-importer.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-importer.js
index f29adb6..7415544 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-importer.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-importer.js
@@ -95,7 +95,7 @@ var WorkflowImporter= Ember.Object.extend({
   },
   getNodeIds(nodeMap){
     var ids=[];
-    nodeMap.forEach(function(entry,key){
+    nodeMap.forEach(function(entry){
       var node=entry.node;
       ids.push(node.id);
     });
@@ -103,7 +103,7 @@ var WorkflowImporter= Ember.Object.extend({
   },
   getNodeNames(nodeMap){
     var names=[];
-    nodeMap.forEach(function(entry,key){
+    nodeMap.forEach(function(entry){
       var node=entry.node;
       names.push(node.id);
     });
@@ -113,7 +113,7 @@ var WorkflowImporter= Ember.Object.extend({
     if (this.containsKillNode(nodeMap)){
       workflow.resetKillNodes();
     }
-    nodeMap.forEach(function(entry,key){
+    nodeMap.forEach(function(entry){
       var node=entry.node;
       if (node.isKillNode()){
         workflow.get("killNodes").pushObject(node);
@@ -122,7 +122,7 @@ var WorkflowImporter= Ember.Object.extend({
   },
   containsKillNode(nodeMap){
     var containsKillNode=false;
-    nodeMap.forEach(function(entry,key){
+    nodeMap.forEach(function(entry){
       var node=entry.node;
       if (node.isKillNode()){
         containsKillNode=true;

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-json-importer.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-json-importer.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-json-importer.js
new file mode 100644
index 0000000..fa428bb
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-json-importer.js
@@ -0,0 +1,92 @@
+/*
+ *    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 {Workflow} from '../domain/workflow';
+import {NodeFactory} from '../domain/node-factory';
+var WorkflowJsonImporter= Ember.Object.extend({
+    nodeFactory:NodeFactory.create({}),
+    importWorkflow(workflowJsonStr){
+      if (!workflowJsonStr){
+        return null;
+      }
+      try{
+        var workflowJson=JSON.parse(workflowJsonStr);
+        var workflow=Workflow.create({});
+        workflow.initialize();
+        workflow.set("name",workflowJson.name);
+        this.restoreKillNodes(workflowJson.killNodes,workflow);
+        var nodeMap= new Map();
+        var startNode=this.visitNode(workflowJson.startNode,nodeMap);
+        workflow.set("startNode",startNode);
+        var maxId=0;
+        for(let value of nodeMap.keys()){
+            console.log("Value in it=",value);
+            var id=Number.parseInt(value.substr(5));
+            if (id>maxId){
+              maxId=id;
+            }
+        }
+        this.nodeFactory.resetNodeIdTo(maxId+1);
+        console.log("imported workflow==",workflow);
+        return workflow;
+      }catch(e){
+        console.error(e);
+        return null;
+      }
+    },
+    visitNode(nodeJson,nodeMap){
+      var self=this;
+      if (!nodeJson){
+        return;
+      }
+      var node;
+      if (!nodeMap.has(nodeJson.id)){
+        node=this.nodeFactory.createNode({id:nodeJson.id, type:nodeJson.type,name:nodeJson.name,actionType:nodeJson.actionType,killMessage:nodeJson.killMessage});
+        node.set("domain",nodeJson.domain);
+        node.set("errorMsgs",nodeJson.errorMsgs);
+        node.set("errors",nodeJson.errors);
+        nodeMap.set(node.id,node);
+        if (nodeJson.transitions){
+          nodeJson.transitions.forEach(function(nodeTran){
+            var transitions=nodeTran;
+            if (!Ember.isArray(nodeTran)){
+              transitions=[nodeTran];
+            }
+            transitions.forEach(function(tran){
+              var targetNodeJson=tran.targetNode;
+              var targetNode=self.visitNode(targetNodeJson,nodeMap);
+              node.addTransitionTo(targetNode,tran.condition);
+            });
+          });
+        }
+      }else{
+        node=nodeMap.get(nodeJson.id);
+      }
+      return node;
+    },
+    restoreKillNodes(killnodesJson,workflow){
+      if (!killnodesJson){
+        return;
+      }
+      workflow.resetKillNodes();
+      killnodesJson.forEach(function(killNodeJson){
+        workflow.createKillNode(killNodeJson.name,killNodeJson.killMessage);
+      });
+      console.log("killnodes json=",killnodesJson);
+    }
+});
+export {WorkflowJsonImporter};

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-path-util.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-path-util.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-path-util.js
new file mode 100644
index 0000000..c921455
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-path-util.js
@@ -0,0 +1,73 @@
+/*
+*    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.Object.create({
+  findPath(source, target){
+    var visitedNodes = [];
+    var currentPath = [];
+    var allPaths = [];
+    this._findPath(source, target, visitedNodes, currentPath, 0, allPaths);
+    return allPaths;
+  },
+  _findPath(source, target, visitedNodes, currentPath, pathIndex, allPaths){
+    visitedNodes.pushObject(source);
+    currentPath[pathIndex++] = source;
+    if(source.id === target.id){
+      if(!allPaths[allPaths.length]){
+        var index = currentPath.indexOf(target);
+        allPaths[allPaths.length] = currentPath.slice(0, index+1);
+      }
+    }
+    if(source.hasTransition()){
+      source.transitions.forEach((transition)=>{
+        var node = transition.targetNode;
+        if(node.hasTransition() && !visitedNodes.findBy('id', node.id)){
+          this._findPath(node, target, visitedNodes, currentPath, pathIndex, allPaths);
+        }
+      }, this);
+    }
+    pathIndex--;
+    visitedNodes.removeObject(source);
+  },
+  _getAllNodes(workflow){
+    var workflowNodes = [];
+    workflow.nodeVisitor.process(workflow.startNode, (node) =>{
+      workflowNodes.pushObject(node);
+    });
+    return workflowNodes;
+  },
+  findValidTransitionsTo(workflow, node){
+    var validTransitionsTo = [];
+    if(!node.hasTransition()){
+      return validTransitionsTo;
+    }
+    var paths = this.findPath(workflow.get('startNode'), node);
+    var workflowNodes = this._getAllNodes(workflow);
+    validTransitionsTo = workflowNodes.slice();
+    workflowNodes.forEach((node)=>{
+      paths.forEach((path)=>{
+        if(path.contains(node)){
+          validTransitionsTo.removeObject(node);
+        }
+      }, this);
+    }, this);
+    validTransitionsTo = validTransitionsTo.reject((node)=>{
+      return node.get('type') === 'placeholder';
+    }, this);
+    return validTransitionsTo;
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-xml-generator.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-xml-generator.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-xml-generator.js
index 9fc791c..7049fde 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-xml-generator.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-xml-generator.js
@@ -18,7 +18,6 @@
 import Ember from 'ember';
 import {WorkflowXmlMapper} from '../domain/workflow_xml_mapper';
 import {NodeVisitor} from '../domain/node-visitor';
-import Constants from '../utils/constants';
 var WorkflowGenerator= Ember.Object.extend({
   workflowMapper:null,
   x2js : new X2JS({useDoubleQuotes:true}),

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow.js
index 5908de5..f4fc20d 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow.js
@@ -21,8 +21,7 @@ import {FindNodeMixin} from '../domain/findnode-mixin';
 import {NodeFactory} from '../domain/node-factory';
 import SchemaVersions from '../domain/schema-versions';
 import {NodeVisitor} from '../domain/node-visitor';
-import {idGen} from '../domain/id-gen';
-import {SlaInfo} from '../domain/sla-info'
+import {SlaInfo} from '../domain/sla-info';
 var Workflow= Ember.Object.extend(FindNodeMixin,{
   name:"",
   startNode:null,
@@ -60,52 +59,13 @@ var Workflow= Ember.Object.extend(FindNodeMixin,{
     //TODO idGen.reset();
     this.initialize();
   },
-  findCommonTargetNodeId(node){
-    var nodeIds = {}, targ, decPath = node.getTargets(), tempId = 0;
-    for(var i =0; i< decPath.length; i++){
-      var currNode = decPath[i];
-      do {
-        if(nodeIds.hasOwnProperty(currNode.get("id"))){
-          nodeIds[currNode.get("id")] = nodeIds[currNode.get("id")] + 1;
-        } else {
-          nodeIds[currNode.get("id")] = 1;
-        }
-        if(currNode.get("id") === "node-end"){
-          break;
-        }
-        currNode = currNode.getTargets()[0];
-      } while(currNode && currNode.get("id"));
-    }
-    for(var j in nodeIds){
-      if(tempId < nodeIds[j]){
-        targ = j;
-        tempId = nodeIds[j];
-      }
-    }
-    return targ;
-  },
+
   findJoinNode(node){
-    var commonTargetId=null;
-    var commonTarget=null;
-    if (node.isDecisionNode()){
-      if (Constants.globalSetting.useJoinNodeForDecision){
-        var target=this.findNodeById(node,"decision_end_"+node.get("id"));
-        if (!target){
-          commonTargetId=this.findCommonTargetNodeId(node);
-          commonTarget=this.findNodeById(this.startNode,commonTargetId);
-          return commonTarget;
-        }else{
-          return target;
-        }
-      }else{
-        commonTargetId=this.findCommonTargetNodeId(node);
-        commonTarget=this.findNodeById(this.startNode,commonTargetId);
-        return commonTarget;
-      }
+    if (node.isDecisionNode() || node.isForkNode()){
+      return this.findCommonTargetNode(this.startNode,node);
     }else if (node.isForkNode()) {
-      commonTargetId=this.findCommonTargetNodeId(node);
-      commonTarget=this.findNodeById(this.startNode,commonTargetId);
-      return commonTarget;
+      //TODO find join node by id if it is efficient later..
+      return this.findCommonTargetNode(this.startNode,node);
     }else{
       return null;
     }
@@ -136,7 +96,7 @@ var Workflow= Ember.Object.extend(FindNodeMixin,{
     }else{
     }
   },
-  generatedNode(target,type){
+  generatedNode(target,type,settings){
     var generatedNode=null;
     if ("decision" === type){
       generatedNode=this.nodeFactory.generateDecisionNode(target);
@@ -144,32 +104,38 @@ var Workflow= Ember.Object.extend(FindNodeMixin,{
       generatedNode=this.nodeFactory.generateForkNode(target);
     }else  if ("kill" === type){
       generatedNode = this.nodeFactory.createKillNode(settings.name);
-      source.deleteCurrentKillNode();
+      //source.deleteCurrentKillNode();//TODO how to get source...
     }else{
       generatedNode = this.nodeFactory.createActionNode(type);
       generatedNode.addTransitionTo(target);
     }
     return generatedNode;
   },
-  addKillNode(node,settings){
-    var generatedNode=this.generatedNode(null,"kill");
+
+  addKillNode(source,settings){
+    var generatedNode=this.generatedNode(null,"kill",settings);
     return source.addTransitionTo(generatedNode,"error");
   },
   addNode(transition,type,settings) {
-    var source=transition.sourceNode;
     var target=transition.targetNode;
     var computedTarget=target;
     if (target && target.isPlaceholder()){
       computedTarget=target.getTargets()[0];
     }
-    var generatedNode=this.generatedNode(computedTarget,type);
-    transition.targetNode=generatedNode;
+    var generatedNode=this.generatedNode(computedTarget,type,settings);
+    var sourceNode=this.findNodeById(this.startNode,transition.sourceNodeId);
+    if (sourceNode.isPlaceholder()){
+      var orignalTransition=this.findTransitionTo(this.startNode,sourceNode.id);
+      orignalTransition.targetNode=generatedNode;
+    }else{
+      transition.targetNode=generatedNode;
+    }
     return generatedNode;
   },
   deleteKillNode(node){
     let killNodes = this.get("killNodes");
     var killNodeReferenced=false;
-    this.nodeVisitor.process(this.startNode,function(n,ctx){
+    this.nodeVisitor.process(this.startNode,function(n){
       if (n.errorNode && n.errorNode.name===node.name){
         killNodeReferenced=true;
       }
@@ -195,35 +161,37 @@ var Workflow= Ember.Object.extend(FindNodeMixin,{
     var target=node.getDefaultTransitionTarget();
     if (node.isForkNode()|| node.isDecisionNode()){
       target=this.findJoinNode(node);
+      if (!target){//A bug will give target as null if the decision has single path.
+        target=node.getDefaultTransitionTarget();
+      }
       if (target.isJoinNode()){
         target=target.getDefaultTransitionTarget();
       }
     }
     var transitionslist=this.findTransistionsToNode(node);
     transitionslist.forEach(function(tran){
-      if (tran.getSourceNode().isDecisionNode()){
-        var joinNode=self.findJoinNode(tran.getSourceNode());
+      var sourceNode=self.findNodeById(self.startNode,tran.sourceNodeId);
+      var joinNode;
+      if (sourceNode.isDecisionNode()){
+        joinNode=self.findJoinNode(sourceNode);
         if (joinNode===target){
           if (tran.isDefaultCasePath()){
-            var placeholderNode=self.nodeFactory.createPlaceholderNode(target);
-            tran.targetNode=placeholderNode;
-          }else   if (tran.getSourceNode().getOkTransitionCount()>2){
-            tran.getSourceNode().removeTransition(tran);
+            tran.targetNode=self.nodeFactory.createPlaceholderNode(target);
+          }else   if (sourceNode.getOkTransitionCount()>2){
+            sourceNode.removeTransition(tran);
           }else{
-            var placeholderNode=self.nodeFactory.createPlaceholderNode(target);
-            tran.targetNode=placeholderNode;
+            tran.targetNode=self.nodeFactory.createPlaceholderNode(target);
           }
         }else{
           tran.targetNode=target;
         }
-      }else if (tran.getSourceNode().isForkNode()){
-        var joinNode=self.findJoinNode(tran.getSourceNode());
+      }else if (sourceNode.isForkNode()){
+        joinNode=self.findJoinNode(sourceNode);
         if (joinNode===target){
-          if (tran.getSourceNode().getOkTransitionCount()>2){
-            tran.getSourceNode().removeTransition(tran);
+          if (sourceNode.getOkTransitionCount()>2){
+            sourceNode.removeTransition(tran);
           }else{
-            var placeholderNode=self.nodeFactory.createPlaceholderNode(target);
-            tran.targetNode=placeholderNode;
+            tran.targetNode=self.nodeFactory.createPlaceholderNode(target);
           }
         }else{
           tran.targetNode=target;
@@ -234,13 +202,15 @@ var Workflow= Ember.Object.extend(FindNodeMixin,{
     });
   },
   deleteTransition(transition){
-    var src=transition.getSourceNode();
+    var src=this.findNodeById(this.startNode,transition.sourceNodeId);
     src.removeTransition(transition);
   },
   deleteEmptyTransitions(transitionslist){
+    var self=this;
     transitionslist.forEach(function(tran){
-      if (tran.getSourceNode().isForkNode()&& tran.getTargetNode().isJoinNode()){
-        tran.getSourceNode().removeTransition(tran);
+      var sourceNode=this.findNodeById(self.startNode,tran.sourceNodeId);
+      if (sourceNode.isForkNode()&& tran.getTargetNode().isJoinNode()){
+        sourceNode.removeTransition(tran);
       }
     });
   },
@@ -261,6 +231,4 @@ var Workflow= Ember.Object.extend(FindNodeMixin,{
     }
   }
 });
-
-
 export {Workflow};

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow_xml_mapper.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow_xml_mapper.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow_xml_mapper.js
index d5dc4da..70581bf 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow_xml_mapper.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow_xml_mapper.js
@@ -18,6 +18,7 @@
 import Ember from 'ember';
 import * as nodeHandler from '../domain/node-handler';
 import {SLAMapper} from "../domain/mapping-utils";
+import {ActionTypeResolver} from "../domain/action-type-resolver";
 
 import {MappingMixin,ConfigurationMapper} from "../domain/mapping-utils";
 var WorkflowXmlMapper= Ember.Object.extend({
@@ -27,7 +28,7 @@ var WorkflowXmlMapper= Ember.Object.extend({
   slaMapper: SLAMapper.create({}),
   schemaVersions:null,
   init: function() {
-    this.actionTypeResolver=nodeHandler.ActionTypeResolver.create({schemaVersions:this.schemaVersions});
+    this.actionTypeResolver=ActionTypeResolver.create({schemaVersions:this.schemaVersions});
     this.set("globalConfigHandler",GlobalConfigHandler.create({}));
     this.set("slaMapper",SLAMapper.create({}));
     this.nodeHandlerMap=new Map();
@@ -106,7 +107,7 @@ var WorkflowXmlMapper= Ember.Object.extend({
     if (!parameters|| !parameters.property){
       return;
     }
-    workflow.parameters={"configuration":{property:[]}}
+    workflow.parameters={"configuration":{property:[]}};
     parameters.property.forEach(function(prop){
       workflow.parameters.configuration.property.push({"name":prop.name,"value":prop.value});
     });

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/helpers/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/helpers/.gitkeep b/contrib/views/wfmanager/src/main/resources/ui/app/helpers/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/index.html
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/index.html b/contrib/views/wfmanager/src/main/resources/ui/app/index.html
index a317a48..df243ad 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/index.html
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/index.html
@@ -33,6 +33,15 @@
 </head>
 
 <body>
+
+<div style="display:none;">
+<!-- preloading images for designer-->
+  <img src="assets/play.png"/>
+  <img src="assets/stop.png"/>
+  <img src="assets/join.png"/>
+  <img src="assets/sitemap.png"/>
+</div>
+
     {{content-for "body"}}
     <script src="assets/vendor.js"></script>
     <script src="assets/oozie-designer.js"></script>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/routes/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/routes/.gitkeep b/contrib/views/wfmanager/src/main/resources/ui/app/routes/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/routes/dashboard.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/routes/dashboard.js b/contrib/views/wfmanager/src/main/resources/ui/app/routes/dashboard.js
index d0ef5e0..949d39a 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/routes/dashboard.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/routes/dashboard.js
@@ -62,11 +62,19 @@ export default Ember.Route.extend({
     });
     return deferred.promise;
   },
+  setPageResultLen(){
+    /* 
+      setting the no of jobs to be displayed to multiple of 5
+    */
+    var relHeight = parseInt(Ember.$(window).width()/100); 
+    return relHeight - relHeight%5;
+  },
   search(params){
     params = params || {};
     var type = params.type || "wf",
     start = Number(params.start || 1),
-    len = Number(params.len || Ember.ENV.PAGE_SIZE),
+    //len = Number(params.len || Ember.ENV.PAGE_SIZE),
+    len = this.setPageResultLen(),
     index = 0,
     filter = params.filter || "",
     API_URL = Ember.ENV.API_URL,

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/routes/design.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/routes/design.js b/contrib/views/wfmanager/src/main/resources/ui/app/routes/design.js
index cec0e9e..5ed2619 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/routes/design.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/routes/design.js
@@ -1,25 +1,27 @@
 /*
- *    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.
- */
+*    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.Route.extend({
-xmlAppPath : null,
-beforeModel: function(transition){
-      this.set("xmlAppPath", transition.queryParams.appPath);
+
+  beforeModel: function(transition){
+    this.set("xmlAppPath", transition.queryParams.appPath);
+    this.controllerFor('design').set("xmlAppPath", transition.queryParams.appPath);
   }
+
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/services/workflow-clipboard.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/services/workflow-clipboard.js b/contrib/views/wfmanager/src/main/resources/ui/app/services/workflow-clipboard.js
new file mode 100644
index 0000000..8784cda
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/services/workflow-clipboard.js
@@ -0,0 +1,34 @@
+/*
+*    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.Service.extend({
+  clipboard : null,
+  setContent(node, operation){
+    var clipboardContent = {
+      name : node.name,
+      domain : Ember.copy(node.domain),
+      type : node.type,
+      actionType : node.actionType,
+      operation : operation
+    };
+    this.set('clipboard', clipboardContent);
+  },
+  getContent (){
+    return this.get('clipboard');
+  }
+});


[05/10] ambari git commit: AMBARI-18691. Improve and Update Workflow designer to support coordinators and bundles. (Belliraj HB via dipayanb)

Posted by db...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/services/workspace-manager.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/services/workspace-manager.js b/contrib/views/wfmanager/src/main/resources/ui/app/services/workspace-manager.js
new file mode 100644
index 0000000..f5eb6e7
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/services/workspace-manager.js
@@ -0,0 +1,62 @@
+/*
+*    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.Service.extend({
+  tabsInfo : {},
+  workInProgress : {},
+  setLastActiveTab(tabId){
+    console.log("setting last active tabId "+tabId);
+    localStorage.setItem('lastActiveTab', tabId);
+  },
+  getLastActiveTab(){
+    console.log("get last active "+localStorage.getItem('lastActiveTab'));
+    return localStorage.getItem('lastActiveTab');
+  },
+  restoreTabs(){
+    var tabs = localStorage.getItem('tabsInfo');
+    console.log("Restoring tabs "+tabs);
+    return JSON.parse(tabs);
+  },
+  saveTabs(tabs){
+    if(!tabs){
+      return;
+    }
+    var tabArray = [];
+    tabs.forEach((tab)=>{
+      tabArray.push({
+        type : tab.type,
+        id : tab.id,
+        name : tab.name
+      });
+    });
+    console.log("Saving tabs "+JSON.stringify(tabArray));
+    localStorage.setItem('tabsInfo', JSON.stringify(tabArray));
+  },
+  restoreWorkInProgress(id){
+    console.log("Restoring workInProgress "+id);
+    return localStorage.getItem(id);
+  },
+  saveWorkInProgress(id, workInProgress){
+    console.log("Restoring workInProgress "+id);
+    localStorage.setItem(id, workInProgress);
+  },
+  deleteWorkInProgress(id){
+    localStorage.removeItem(id);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/styles/app.less
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/styles/app.less b/contrib/views/wfmanager/src/main/resources/ui/app/styles/app.less
new file mode 100644
index 0000000..5d1b3a3
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/styles/app.less
@@ -0,0 +1,1497 @@
+/*
+ *    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.
+ */
+
+@bgColor: #eee;
+@bgGreenActive: #5bb75b;
+@moduleHeaderBgColor: #fafafa;
+@nodeDefaultHeight: 40px;
+@nodeDefaultWidth: 40px;
+@defaultRed: red;
+@defaultBorderRadius: 5px;
+@nodeActionBgColor: #E5E5E5;
+@defaultPropertiesEditorHeight: 350px;
+
+body {
+    background: @bgColor;
+    padding: 0;
+    margin: 0;
+}
+a {
+  color: #000;
+}
+.padding0 {
+  padding: 0px;
+}
+.paddingtop7{
+  padding-top:7px;
+}
+.paddingtop8{
+  padding-top:7px;
+}
+.paddingbottom8{
+  padding-bottom:7px;
+}
+.paddingtop10{
+  padding-top:10px;
+}
+.padding10{
+    margin-top: 10px;
+}
+.padding20{
+    margin-top: 20px;
+}
+.marginleft20{
+  margin-left: 20px !important;
+}
+.paddingright10{
+  padding-right: 10px;
+}
+.marginright5{
+  margin-right: 5px !important;
+}
+#arrow{
+    top: 24%;
+    left: -22px;
+    margin-top: -11px;
+    border-right-color: #999 !important;
+    border-right-color: rgba(0, 0, 0, .25);
+    border-left-width: 0;
+    position: absolute;
+    display: block;
+    width: 0;
+    height: 0;
+    border-color: transparent;
+    border-style: solid;
+    border-width: 11px;
+}
+
+.container-custom {
+  background-color: @moduleHeaderBgColor;
+}
+
+.disabled {
+    cursor:none;
+}
+#header {
+    white-space: nowrap;
+    background: @bgGreenActive;
+    background-position: 10px;
+    color: yellow;
+    height: 50px;
+    padding: 10px;
+    font-size: 20px;
+}
+.branch{
+    padding: 0px !important;
+    border: 0px !important;
+    background: inherit !important;
+}
+
+.branch input {
+  border: 0px;
+  text-align: center;
+}
+
+#designer {
+  position: relative;
+}
+
+#wf_title {
+  border-bottom: 1px dotted #000;
+}
+
+.editable {
+  padding: 5px 10px;
+  border: 1px solid transparent;
+  background: transparent;
+  white-space: nowrap;
+  text-align: left;
+  margin: 0 2px;
+}
+
+.editable:focus,
+.editable:hover {
+    border: 1px solid #999;
+    background: #fff;
+    cursor: text;
+}
+
+.action {
+    float: left;
+    padding: 5px;
+    margin: 2px;
+    height: 60px;
+    line-height: 50px;
+    width: 62px;
+    font-size: small;
+    overflow: hidden;
+    text-align: center;
+}
+
+.node,
+.actions_list_left li:hover {
+    /* Permalink - use to edit and share this gradient: http://colorzilla.com/gradient-editor/#ffffff+0,e5e5e5+100;White+3D */
+    background: #ffffff;
+}
+
+.node {
+    text-align: center;
+    position: absolute;
+    left: 50%;
+    border: 1px solid #bbb;
+    overflow: visible;
+    background: transparent;
+    border: none;
+}
+
+.node-item{
+  background:#e5e5e5;
+  border:  1px solid #ABABAB;
+  z-index:4;
+
+}
+
+.action_node {
+    min-width: 195px;
+}
+
+.fork,
+.join {
+    border-radius: 70px;
+    width: @nodeDefaultWidth;
+    height: @nodeDefaultHeight;
+    white-space: wrap;
+    padding-top: 10px;
+}
+
+.start,
+.end {
+    border-radius: 60px;
+    width: @nodeDefaultWidth;
+    height: @nodeDefaultHeight;
+    background: #fff;
+    line-height: 25px;
+    cursor: not-allowed;
+}
+
+.start {
+  top: 20px;
+  padding-left: 7px;
+  padding-top: 6px;
+}
+.kill{
+  border-radius: @defaultBorderRadius;
+  min-width: 178px;
+  height: @nodeDefaultHeight;
+}
+.kill .fa-ban {
+  color: @defaultRed;
+}
+.hrClass{
+    margin-bottom: 10px;
+    margin-top: 10px;
+}
+
+.kill-name{
+  padding-left: 40px;
+  margin-top: -35px;
+}
+
+.node .editable {
+    padding: 2px 5px;
+    width: 8em;
+    text-align: center;
+}
+
+.node .error{
+     border: 1px solid #a94442;
+}
+
+.connector_overlay {
+    transition: all .3s ease-in;
+    white-space: nowrap;
+    opacity: .8;
+    border: 1px solid #ddd;
+    background: #1a8cff;
+    border-radius: 30px;
+    width: 30px;
+    height: 30px;
+    line-height: 28px;
+    text-align: center;
+    cursor: pointer;
+    transform: scale(0.8);
+
+}
+
+.jsplumb-hover .connector_overlay,
+.connector_overlay:hover {
+    opacity: 1;
+}
+
+.node_actions {
+    transition: opacity 1s ease-in;
+    opacity: 0;
+    position: absolute;
+    white-space: nowrap;
+    border: 1px solid #999;
+    background: @nodeActionBgColor;
+    border-radius: 3px;
+    min-width: 20px;
+    height: 28px;
+    cursor: pointer;
+}
+.node_actions i{
+  padding: 5px;
+}
+.node_properties {
+    border-radius: 30px;
+    cursor: pointer;
+}
+.node_properties:hover {
+    cursor: pointer;
+}
+.decision_node .node_properties {
+  margin-top: -16px;
+}
+.decisionNodeError{
+    position: relative;
+    left: 50px;
+ }
+.action-node {
+    border-radius: @defaultBorderRadius;
+    height: 38px;
+}
+.node_left .fa-trash-o{
+    color: @defaultRed;
+}
+.node_left {
+  right: -45px;
+  top: -61%;
+}
+.decision_node .node_left{
+    transform: rotate(315deg) scale(1.4);
+    right: -50px;
+    top: -126%;
+}
+.nodeEnd{
+    top:15%;
+    position: relative;
+}
+.nodeStart{
+    right:5%;
+    position: relative;
+}
+.node_bottom {
+    bottom: 50%;
+    left: 50%;
+    z-index: 5;
+    transform: translate(-50%, -20%) scale(0.8);
+    opacity: 1;
+    border-radius: 3px;
+    width: 40px;
+    height: 24px;
+}
+.fork .node_bottom {
+    top: 80%;
+}
+.node_bottom_actions{
+  position: absolute;
+  background: @nodeActionBgColor;
+  white-space: nowrap;
+}
+.node:hover .node_actions {
+    opacity: 1;
+}
+
+.action_node {
+    border-radius: 4px;
+}
+
+input:invalid {
+    border: 1px solid @defaultRed;
+}
+
+.fa-exclamation-triangle {
+    color: @defaultRed;
+}
+
+.actions_list_left {
+    list-style: none;
+    padding: 0;
+    margin: 0;
+}
+
+.actions_list_left li.disabled {
+    cursor: not-allowed;
+    background: #eee;
+    color: #ccc;
+}
+
+.actions_list_left li {
+    background: #fff;
+    width: 60px;
+    padding: 10px;
+    border: 1px solid silver;
+    border-radius: @defaultBorderRadius;
+    margin: 2px 0;
+    cursor: move;
+    z-index: 1000;
+    display: inline-block;
+    position: relative;
+    text-align: center;
+}
+
+.control_flow_node,
+.control_flow li:hover {
+    /* Permalink - use to edit and share this gradient: http://colorzilla.com/gradient-editor/#fdfeea+0,e8f135+100 */
+    /*background: #fdfeea;*/
+    /* Old browsers */
+    /*background: -moz-linear-gradient(top, #fdfeea 0%, #e8f135 100%);*/
+    /* FF3.6-15 */
+    /*background: -webkit-linear-gradient(top, #fdfeea 0%, #e8f135 100%);*/
+    /* Chrome10-25,Safari5.1-6 */
+    /*background: linear-gradient(to bottom, #fdfeea 0%, #e8f135 100%);*/
+    /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
+    /*filter: progid: DXImageTransform.Microsoft.gradient( startColorstr='#fdfeea', endColorstr='#e8f135', GradientType=0);*/
+    /* IE6-9 */
+}
+.decision-condition {
+  white-space: nowrap;
+  width: 10em;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  border: 1px solid #D0D0D0;
+  border-radius: 3px;
+  background-color: #F5F5F5;
+  padding: 3px;
+  font-size: 11px;
+  opacity: 0.8;
+}
+.decision_node {
+  transform: rotate(45deg) scale(.7);
+  width: 60px;
+  height: 60px;
+  padding: 5px;
+  float: right;
+  margin: 0 2px;
+}
+.decision-data-wrapper{
+  transform: rotate(-45deg) scale(1.3); ;
+}
+.decision_node_data .editable{
+  margin-right: 10px;
+}
+.decision_node_data {
+  padding-right: 31px;
+  float: right;
+  margin: 0 2px;
+}
+.fork_node_data {
+  float: right;
+  margin-top: -15px;
+}
+.fork_node_data .editable {
+  margin-right: 5px;
+}
+.decision_node .content {
+    text-align: center;
+    position: absolute;
+    padding: 0 5px;
+    width: 120px;
+    height: 70px;
+    transform: rotate(-45deg) scale(1.2) translate(-13%, 30%);
+    white-space: nowrap;
+}
+
+.breadcrumb {
+    margin: 0;
+}
+
+.collapse.width {
+    height: auto;
+    -webkit-transition: width 0.35s ease;
+    -moz-transition: width 0.35s ease;
+    -o-transition: width 0.35s ease;
+    transition: width 0.35s ease;
+}
+
+.highlighter-always {
+    opacity: 1;
+    animation-name: highlighter;
+    animation-duration: 1s;
+    animation-iteration-count: infinite;
+    animation-timing-function: ease-out;
+}
+
+@keyframes highlighter {
+    0% {
+        transform: scale(1)
+    }
+    50% {
+        transform: scale(1.5)
+    }
+    100% {
+        transform: scale(1)
+    }
+}
+
+.control_flow li._fork {
+    margin: 4px 8px;
+}
+
+.control_flow li.switch {
+    border-radius: 0px;
+    transform: rotate(45deg) translate(0%, -0%) scale(.9);
+}
+
+.action_node_data {
+    padding: 5px;
+    float: left;
+    margin: 0 2px;
+}
+
+#content {
+    padding: 0;
+    margin: 0;
+    float: left;
+    position: relative;
+    transition: left .6s cubic-bezier(0.175, 0.885, 0.320, 1.275);
+}
+
+.expanded {
+    left: 0px;
+}
+
+.expanded:after {
+    content: "\f100" !important;
+}
+
+.collapsed {
+    left: -215px;
+}
+
+.title-btn,
+.title-btn:hover {
+    border: 0;
+    background: transparent;
+}
+
+.back_button {
+    height: 30px;
+    background-color: #fff;
+    position: relative;
+    margin-left: 13px;
+    border-radius: @defaultBorderRadius;
+    border: 1px solid #ccc;
+}
+
+.back_button:before {
+    content: "";
+    position: absolute;
+    top: -1px;
+    left: -13px;
+    border-style: solid;
+    border-width: 15px 15px 15px 0;
+    border-color: transparent #ccc transparent transparent;
+}
+
+.back_button:after {
+    content: "";
+    position: absolute;
+    top: 0px;
+    left: -12px;
+    border-style: solid;
+    border-width: 14px 14px 14px 0;
+    border-color: transparent #fff transparent transparent;
+}
+
+.back_button > a {
+    display: block;
+    text-decoration: none;
+    text-align: center;
+    color: #000;
+    padding: 0 10px 0 5px;
+    line-height: 27px;
+    font-size: smaller;
+}
+
+.ambari-view #header {
+    display: none;
+}
+
+.ambari-view #content {
+    padding: 0;
+}
+
+.ambari-view body {
+    background: #fff;
+}
+
+.messageDiv {
+    position: absolute;
+    left: 40%;
+    top: 100px;
+    z-index: 1;
+}
+
+.workflow-error {
+    top:50px;
+    left: 75%;
+    z-index: 1;
+}
+
+#action_properties_dialog .modal-body {
+    max-height: @defaultPropertiesEditorHeight;
+    overflow-y: scroll;
+    overflow-x: hidden;
+}
+
+#action_properties_dialog .container,
+#global_properties_dialog .container {
+    max-width: 180%;
+}
+
+#action_properties_dialog .blank-form {
+    right: 15px;
+    position: relative;
+}
+
+#action_properties_dialog .modal-dialog,
+#workflow_sla_dialog .modal-dialog,
+#global_properties_dialog .modal-dialog,
+#workflow_parameters_dialog .modal-dialog,
+#workflow_credentials_dialog .modal-dialog,
+#version-settings-dialog .modal-dialog,
+#control-dialog .modal-dialog,
+#ConfirmDialog .modal-dialog,
+#killnode-manager-dialog .modal-dialog {
+    width: 800px;
+}
+#configureJob .modal-dialog{
+  width: 650px;
+}
+#collapseOne{
+    margin: 10px;
+}
+.panel-heading {
+    padding: 4px 15px;
+}
+
+#action_properties_dialog .panel-default > .panel-heading,
+#global_properties_dialog .panel-default > .panel-heading,
+#workflow_sla_dialog .panel-default > .panel-heading,
+#workflow_credentials_dialog .panel-default > .panel-heading,
+#configureWorkfowModal .panel-default > .panel-heading,
+#workflow_parameters_dialog .panel-default > .panel-heading,
+#killnode-manager-dialog .panel-default > .panel-heading,
+ .whiteLabel, .whiteLabel:hover, .whiteLabel:focus, .whiteLabel:visited, .whiteLabel:active {
+    background-color: @bgGreenActive;
+    color: #fff;
+}
+.btn-primary{
+    background-color: @bgGreenActive !important;
+    border-color: #289028 !important;
+    color: #fff;
+}
+.btn-primary:visited,.btn-primary:focus,.btn-primary:active,.btn-primary.active{
+    background-color: @bgGreenActive !important;
+    border-color: #289028 !important;
+    color: #fff;
+}
+.btn-primary:hover{
+  background-color: #289028 !important;
+  border-color: #289028 !important;
+  color: #fff;
+}
+._actions_popup {
+    padding: 4px;
+}
+
+._actions_popup .control_flow {
+    padding-left: 20%;
+}
+
+._actions_popup ul {
+    padding: 0;
+    margin: 0;
+}
+
+._actions_popup h4 {
+    font-size: 10px;
+    font-weight: bold;
+    border-bottom: 1px solid #e5e5e5;
+    padding-bottom: 5px;
+}
+
+._actions_popup li {
+    list-style: none;
+    float: left;
+    width: 53px;
+    height: 50px;
+    border: 1px solid silver;
+    margin: 3px;
+    padding: 10px;
+    text-align: center;
+    font-size: 11px;
+    border-radius: 6px;
+    cursor: pointer;
+}
+.labels {
+    width:70px;
+}
+.error{
+    border: 2px solid @defaultRed;
+}
+.validated{
+    border: 2px solid #4cae4c;
+}
+.notification {
+    width:40%;
+    left:50%;
+    position: relative;
+}
+.redColor{
+    color: @defaultRed;
+}
+.killNode{
+    width: 150px;
+}
+.zoom-buttons {
+  position: absolute;
+  top: 9px;
+  right: 2%;
+}
+.legend {
+    right: 1%;
+
+}
+.globlaPropetiesInfo{
+        width: 80%;
+    left: 10%;
+    position: relative;
+}
+.zoom-buttons .btn {
+    font-size: 8px;
+}
+
+.requiredField {
+    color: @defaultRed;
+}
+#search-bar .twitter-typeahead {
+    position: inherit !important;
+}
+#search-bar .tt-hint {
+  display: none !important;
+}
+#search-bar .bootstrap-tagsinput {
+    width: 260px;
+    border-radius: 0px;
+    line-height: 20px;
+    vertical-align: top;
+    height: 30px;
+    overflow-y: auto;
+}
+#search-bar .bootstrap-tagsinput .label-info{
+    background-color : @bgGreenActive;
+}
+#search-bar .tt-menu {
+    position: absolute;
+    top: 100%;
+    left: inherit !important;
+    z-index: 100;
+    border: 1px solid rgba(0,0,0,0.2);
+    margin-top: 7px;
+    background-color: white;
+    width: 60% !important;
+    padding: 0 5px;
+}
+#job-detail-app-path{
+  overflow-x: scroll;
+}
+
+#search-bar .search-icon {
+  display: inline-block;
+  border: 1px solid #ccc;
+  padding: 4px 10px;
+  border-left: 0px;
+  border-bottom-right-radius: 3px;
+  border-top-right-radius: 3px;
+}
+
+#startDate, #endDate {
+  height: 30px;
+  width: 162px;
+}
+
+.jobTitle {
+  height: 24px;
+  margin-left: 10px;
+  line-height: 30px;
+}
+
+.info {
+    float: left;
+    margin-right: 20px;
+    color: #777;
+    padding-top: 4px;
+}
+
+.pages {
+    margin-right: 40px;
+}
+
+.listing-footer {
+  border-top: 1px solid #d2d2d2;
+  border-bottom: 1px solid #d2d2d2;
+  padding: 3px 0px;
+  margin: 0 0 5px 0;
+}
+
+.page-selector {
+  padding: 4px 12px;
+  border-radius: 0px;
+}
+
+.listing thead {
+    background: #f5f5f5;
+}
+
+.listing th {
+  border-left : 1px solid #ddd;
+  border-bottom: 1px solid #ddd !important;
+}
+
+.listing tr th:first-child {
+  border-left: 0;
+}
+
+.listing > tbody > tr > td {
+  vertical-align: middle;
+  padding: 5px;
+  border-left: 0;
+  border-right: 0;
+}
+
+.job-listing > tbody > tr > td {
+  border-bottom: 1px solid #ddd;
+}
+
+
+.pointer {
+  cursor: pointer;
+}
+
+#job-details .nav-tabs {
+  background: #eee;
+  margin-bottom: 10px;
+}
+
+.preview pre.prettyprint {
+  border: none;
+  background: #fff;
+}
+
+.preview pre {
+  border: none;
+  background: #fff;
+}
+
+.date-picker {
+  position: relative;
+}
+
+.actions-col .loading-container{
+  position: relative;
+}
+
+#bulk-action-loader .loading-container{
+  position: relative;
+}
+
+.decisionNodeHandler {
+    left: 10%;
+    bottom: 30%;
+    position: relative;
+}
+
+.decisionBox {
+    right: 10px;
+    top: 13%;
+    width:75px;
+    position: relative;
+}
+
+.pages .open .dropdown-menu {
+  max-height: 120px;
+  overflow-y: scroll;
+  min-width : 75px;
+  width : 75px;
+}
+
+#action-details .panel-heading {
+  padding: 10px 15px;
+}
+
+#bulk-action-button .dropdown-menu li .fa {
+  margin-right: 10px;
+}
+
+#dashboard, #dashboard .panel, .panel-heading, .panel-body {
+  border-radius: 0px;
+}
+
+#job-details, #job-details .panel, .panel-heading, .panel-body {
+  border-radius: 0px;
+}
+
+#dashboard .listing-error{
+  text-align: center;
+}
+
+#dashboard .panel {
+  border: 0;
+  border-bottom: 1px solid #ddd;
+}
+
+#loading {
+    position: absolute;
+    top: 90px;
+    left: 0;
+    display: none;
+    width: 100vw;
+    height: 80vh;
+    overflow: hidden;
+    z-index: 1;
+}
+
+.loader img {
+  height: 40px;
+  width: 50px;
+}
+
+#search-table {
+    margin-bottom: 0px;
+}
+
+#search-table .bulk-actions-buttons {
+    margin-left: -124px;
+    margin-top: 3px;
+    position: fixed;
+    transition: all .5s ease;
+}
+
+#search-table .bulk-actions-buttons:before {
+    display: block;
+    content: "";
+    width: 0;
+    height: 0;
+    left: -10px;
+    top: 10px;
+    border: 5px solid transparent;
+    border-right: 10px solid #666;
+    position: absolute;
+}
+
+#search-table .bulk-actions-buttons.shown {
+    margin-left: 30px;
+}
+
+#search-table .actions-col {
+      white-space: nowrap;
+      text-align: center;
+      min-width: 150px;
+  }
+
+  .btn-kill:hover,
+  .btn-kill:focus {
+      background: #d9534f;
+      color: #fff;
+      border-color: @defaultRed;
+  }
+
+  .actions-col .btn {
+      color: gray;
+      cursor: not-allowed;
+      opacity: .5;
+      font-size: 10px;
+  }
+
+  .actions-col .btn.isOn {
+      color: #000;
+      cursor: pointer;
+      opacity: 1;
+  }
+  .pages .btn {
+      /*color: @bgGreenActive;*/
+  }
+
+  .pages .btn.disabled {
+      color: gray;
+  }
+
+  .pages .btn-primary {
+      color: #fff;
+  }
+  .cbox {
+      width: 20px;
+  }
+
+  .main-panel {
+      padding: 0px;
+  }
+
+  #dashboard .main-panel {
+    padding: 5px;
+  }
+
+  .first-col {
+      text-align: center;
+  }
+
+
+
+.DONEWITHERROR,
+.FAILED,
+.KILLED {
+    color: #d9534f;
+}
+
+.RUNNING {
+    color: green;
+}
+
+.PAUSED,
+.PAUSEDWITHERROR,
+.PREPPAUSED,
+.RUNNINGWITHERROR,
+.SUSPENDED,
+.SUSPENDEDWITHERROR {
+    color: #f0ad4e;
+}
+
+.SUCCEEDED {
+    color: #5cb85c;
+}
+
+.mb0 {
+  margin-bottom: 0;
+}
+
+.pb5 {
+    padding-bottom: 5px;
+}
+
+.navbar-header {
+  width: 100%;
+}
+
+#create-new-button {
+  float: right;
+  padding-top: 8px;
+}
+
+.width100Per{
+  width: 100%;
+}
+.hdfs-browse{
+  max-height: 500px;
+  overflow: scroll;
+}
+#wf_title{
+    margin-left: 2px;
+    width: 150px;
+    font-size: 12px;
+}
+.backto-dashboard{
+  text-decoration: blink !important;
+}
+.file-upload-control input[type="file"]{
+  width: 200px;
+  display: inline;
+  border: 1px solid #ccc;
+}
+.file-upload-control  input[type="button"], input[type="submit"], input[type="reset"], input[type="file"]::-webkit-file-upload-button, button {
+    padding: 6px 12px;
+    border-radius: 4px;
+    background-color: #fff;
+    line-height: 1.42857143;
+    border: none;
+}
+.close-icon{
+  font-size: 18px;
+  font-weight: bold;
+  line-height: 1;
+  text-shadow: 0 1px 0 #fff;
+  color: #AFAFAF;
+  background: transparent;
+  padding: 3px;
+}
+#flow-designer{
+  position: relative;
+  top:10%;
+}
+.designer-main-panel{
+   position: relative;
+   width: 100%;
+   border: none;
+   height: 0px;
+}
+.connector_overlay_new {
+    white-space: nowrap;
+    border: 1px solid #ddd;
+    background: #E5E5E5;
+    border-radius: 30px;
+    width: 24px;
+    height: 24px;
+    line-height: 24px;
+    text-align: center;
+    cursor: pointer;
+    transform: scale(0.8);
+    font-size: 12px;
+}
+.connector_overlay_new:hover .node_actions{
+    opacity: 1;
+}
+.placeholder-node{
+  width:1px;
+  height: 1px;
+  background: transparent;
+  padding-left: 0px;
+  padding-right: 0px;
+  margin-left: 4px;
+  /*  transform: translate(0%, -6%);*/
+}
+.decision_end{
+  width: 10px;
+  height: 10px;
+  border-radius: 16px;
+}
+#decision-properties-table {
+  width: 70%;
+  margin-left: 50px;
+}
+.preview-xml{
+  border: none;
+  padding: 8px;
+}
+.workflow-actions-pop{
+  width: 250px;
+}
+#killnodes-container{
+  width: 300px;
+  height: 100px;
+  padding: 5px;
+  border-radius: 3px;
+}
+.decision-add-branch-popover{
+  position: absolute;
+  left: 44px;
+  top: -7px;
+  z-index: 5;
+}
+
+.jsplumb-connector { z-index:1; }
+.jsplumb-endpoint { z-index:2; }
+.jsplumb-overlay { z-index:3; }
+#selector-content .panel-body{
+    width:400px;
+}
+
+.decisionSplit {
+    border-radius: 24px;
+    width: 24px;
+    height: 24px;
+    left: 70% !important;
+    top: 67% !important;
+    transform:rotate(315deg) !important;
+}
+
+.forkSplit {
+    border-radius: 24px;
+    width: 24px;
+    height: 18px;
+    left: 50% !important;
+    top: 75% !important;
+}
+
+.control_flow_node {
+    cursor: not-allowed;
+}
+.join {
+  background: #fff;
+}
+.default-condition{
+  background-color: blue;
+}
+.query-text-area {
+  width: 540px;
+}
+.decisionText{
+    position: absolute;
+    transform: rotate(315deg);
+    top: 30%;
+    left: 0px;
+    right: 0px;
+}
+.decisionIcon{
+    position: relative;
+    right: 5px;
+}
+.actionNodes li{
+    padding: 10px 0px !important;
+    height: auto;
+}
+.dr_action_fork{
+    width: 45px !important;
+    height: auto !important;
+    padding: 10px 0px !important;
+    border-radius: 0px !important;
+}
+.dr_action_switch{
+    width: 45px !important;
+    height: 45px !important;
+    padding: 10px 0px !important;
+}
+.paddingClass{
+    padding-top: 0.5%;
+}
+.margin0{
+    margin-bottom: 0px;
+}
+.editor-icon-title span{
+  padding-left: 5px;
+}
+.icon_map_red{
+  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAMUklEQVR4Xu2df2xb1RXHz7nPTpxQykZL+VEajbYbjMFgoCE2xoYG2g9NG6OlCNbEiX/QCFALWtXaTifwYE2ctCui/GxInhM7CEaL2JjEH9uQ+KHBNsQPsQ5UBkVN+bEVutKmaZ3E757puT9kPzvxi/P8bPed/Nfne88593s/77zXe++7F4H/HK0AOrr13HhgABwOAQPAADhcAYc3nzMAA+BwBRzefM4ADIDDFXB48zMZoLlHvURoeDEACSfoQYIIJb2eiATfcEJ7p2ojtsT6b0PABxwnhJREiLcmI4FHHNf2rAajN9b3GYCY40gRNPgssc5/miPbfrTR6I2p5GQBEmG/o1+E8wCQRG8JxMMnJBRSawShXJjdNgbAkAFIkxcm1wW3n4gAtPXEL5aScl78GAAGgB8B2Xc7Z4ATMfdN3qa8dwAGgAHgdwAHMcAZgP8bmDsOwI8AB93+AMAZgDMAZwBn3fO5reUMwBmAMwBngCwF+CVwchxWbNniHt9bt0jxaHv6fxn831TgRKNR8V792QvrBB5SQ4GPi0Hm+426ABVwq2HfB4Bo2wQdPwJMPgK8sf4fg4QBEDgPpNRQKPefk9q1OhqNSmPnLu9Uz1cItoECX838RvCMS1CzGgqMGMvetHHLXHfa9QQAXn2kKLwGirYsuebmD4pBY8XvDIAJAJrXbzkTFPd7AqAxW3QEuHUw7H84+9qyJ59UGt4/8A6g+HLOEDtCbzLkbzd2Wkssvg2BluaUlfiPZKTtcjsyAQNgAgBvt9oKBAP5dxw9lwgHrsm+3hzrv0gAvplfVu5NhINzs69fFY26mjxN+tS7y1heQ23BY6GbP7TiLp/KBgNgAoCWWPxGBHo8T0iUzyZCwZ9kX2/rjJ8nBb2TV1bCx4kO//zs6/p7ws66+
 QdBKA3G8qS4Tk+u8e5hACxUoNT1AMujQ7OxLrVDCHFGTjhESxKRwNOGa9jco74kCK8wPC7uHgz77zI2pzUWf4CAbsu1Ac8kIv5rLWz6pKY4A5jIALp6Lev7LkAQD0sFvi0kfEwC706GfY8WUrZlQ2IeaNpDCNpPAcQoETyye2z4zuej0bSx/MrNm+s/H53VQwQ+ENItCLd6ML2yN9y+nwGwWIFSM4AxbRd68y8YKtGRxSZm/ls3nbIW6sIZwGQGsFDzqjLFADAAPBRcVbekzcFwBuAMwBnA5psux92y6JN1jQ0HO6UGPgJwCwFbXUh3FBo2LkecnAEqnAFautT7EGFVdudKgKeHwv4l5ehwo00GoIIAZGYMPU0jxjkGvZMUCfPiHf5Pyw0BA1BBADJzAXVnp0AIxdjRShqa4r/y72YALFTAioEgC8PJmGqN9T9NgD/PtqtPCSdDvm+aGkCaYUCcASqYATJDzBsS80jTtgqg7+r/1j/OBaClQ5HgezPsW1PVGYAKA5DpJSL0x+LnjAtyD631v2vHnX+MDgagGgAwda+WpxADwADwQFB57q3asMoZgDOAcY8g6gTET2qD32lGqeF8EBTOrlXxHUKI0NsdXw5APiRyEypbF6Z2PWh6zcE0JSg6EjhDe9OrTvACSFBAge9Mr6J1pSsNQEt3/x1IeG9ui2hTIhxYbV0rJ7ekPwImCq1KLbtzKUcPL559yhf37ROH9rpHhID6svvMcyDHE+FgBfweDUS/+zvje0CBnNXCAJDWUnVzHos2Hyi3JlhoXXq5nR63TxgGBAWA1tvmM9sRyt8lQsEbK+IbAPQvjVL73OOF/LsIFqkR/85yx4bLog/OavA03EUAlyKBM7aKRZAC4FWpuO5OrvGOllvkqex7u9WXgeBbOWUkDB9ePGvh1htu0ModW/l3yCLCtl8PlJRmB+5qG7NzVKzcYheyn1ltrCh/AqAzj/6+nwRcm1zrf8GOeMoOgLdLfQ
 UQLi+lMRLwxaGw73ul1K2lOnoW9jQ0/gAlud318s/FPjy1sm1lB6C5U02V/IIn5WiiIzjLygazrVwFGACHE8EAMADlVYAfAeXVd6bWy5oB2nriZ6TTNCwEuEsJVIJMaRp96fF1N/+3lPpcp7gCZQFAf6tt9DSsISlXgxAnFQ9jyhIHAanHczj9295o+6EZ2uLqBgUsBSCzO8bOg0EpZTTvU+qZSq9/kavQnYsO747bNVEy05Brob5lADT3xK8UE7Tl+L445Wo9wnbQaEWiI/BKuVw4ya5lALTG4veS1FbaIp6ibEqEfGut9KVnr0/fftsyPayMzWpbp51/Ph0bZnZEg6cSsDU28DUC+RgAXGS10FVu7w0h8ReOB8AbU18HgG9UeWeVK7y/MwAOPjVNSphgABwMQGbDy3Llllqxazw3USJeh2nNlq9y7NZICDyXELcd98sAABgBcNReyQwAA8CPACefm8gZgDOArRlAnx2URD8kwjGZcj9rx7LnYi9a/A5QTCGLfm/riv8ojfTUse1QpJT/UYTrmsFw278sclGSGQagJNmmV0lf/z62z72bAE7ProkkXxqMBDMbI1TqjwGwQfnJtlCXAHJxathdyeldBsAGAAKb+k6dSMGevM2QJHyY6PAvsCGESV0wADapn5kuBroj2x0Brphsy3WbwuKBILuE1vfE+8DT1E76+ThIYyCxL++wBbuCyfLDGaAColeTSwagmnqjArEwABUQvZpcMgDV1BsViIUBsFF0feFl/c6RC1xSjA1E2nZUw6ffDIBNAGSOU0X5+2Mnakqkv6JwL7HjbLypmsgA2ABA5oBEd9N24zcDBPhUMuy73oYQeCAIAPI2y7ZrOri5q2+xQPHv/F6Q44lQwFPJRwFnABtuP393/1lpwo8KuNqXCPnmMAA2dEIlM4DePG+X+gdA+FnOUDBBVzLi77Cn+YW9cAawSX1/d//JE4AbkeRSkGIMBfTtSg3fU+g4VZtCyrh
 hAOxUuwp9MQBV2Cl2hsQA2Kl2FfpiAKqwU+wMiQGwU20A0I9KuwpAmlkGpg8gPQ8gTL0oEuGK3l5Xb3u7vvm16T8GwLRUMyt408Ytc13pukcQ6FqQ2gQKlzq7cWT1/atWjRkt68epeuoPbiCEoJCyHgX+USru9oLDxkTY0qPejmlcl9l1m+BvAnHFQNj3TzMRMwBmVLKgjDfW/xcAvNowDrA5GfHfbjTf2q1uJIKc/fIz28aG2q4yDhp5Y2ozACRzbeAnLpTnmjl/lwGwoHOLmfD9Rl2guWDYWE5KGBmK+E4xdmpLp7oXBZxqLF9oC3VvrP85APy+sSwSXT8YCTxVLDYGoJhCFvzu71IXphHezwMAZGooFGg0AtDcqR4QAk7OK4903lAosCP7emtX34uE4kpjWQK8KRn2PVEsfAagmEJW/K4/p7vjryLApTnmiJKJSMBrdOGNqf0A4M++rp+oORT2X5z/CIivBKDNBhv7QSqLEh2te4uFzwAUU8ii31s2PHoOTLieQEGXZUwSPOPBCW9vuH2/0YU+bDxOOCgArjtSFF4jkjcWOk41M9XsWbABAPUj2F0gYVggtg5EfM+bCZ0BMKOSVWWIcHlP33wh6sfNLATxdaqngQRPfJ3vw2IzhsujQ7Pr68fnjiyatWs6J20YARCEl42OHXrHqiZXk52GOs+FIPDl4zHZtR6gmkQo8LihisUn5RHfQtj6lTYDkNXjxgxgFwz6Dl0ClAs00FwKyLfyPpuzJ5B0Zcizp3GmvHhj/TsA8CumCltaSI4rabE4Xa+5UFPercjRfQjbHQ+AvsexImmr8dN1S/t6EmNSwpgQEgFEnR3+cn3gJyDlUscDoIuiz080eRaeJUhzxLF5EhV5eKHnI/1lmQEo863XGlNvkYRXlOJGAL04GPH3llLXbB0GwKxSJZbzdj56CITSUFp1eSARDp5SWl1ztRgAczqVXKraz0xiAEruWnMVGQBzOp2wpRiAE7Zr
 zTWMATCn0wlX6ujncN0AsGQmjZMA2xQhwoNr2/Km02di91hdfgewQsUsG97OwTmE2p1EcEup5yXmhyTHEZSHXHXaPVYfLM0AWATAys2b6/ePnrRKInUIEF+wyGyOGQnycwXE+tmNB+8vtJayFJ8MQCmqFajT0qXehwj6mgQb/mhTIhzIWTNZqlMGoFTlDPWae9RLUKOvW2RuSjOKIt4cWOt70wpfDIAVKtawDQaghjvPitAZACtUrGEbDEANd54VoTMAVqhYwzYYgBruPCtCZwCsULGGbTAANdx5VoTOAFihYg3b+D/35R/ptIYQMwAAAABJRU5ErkJggg==)
+}
+.node_actions i{
+  border-right: 1px solid #ababab;
+  border-radius: 0px;
+  min-width: 26px;
+}
+.node_actions i:last-child {
+  border-right:none;
+}
+.wf-path {
+    font-size: 12px;
+    float: left;
+    color: gray;
+    margin-top: 17px;
+    max-width: 150px;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    overflow: hidden;
+}
+.cred-type{
+  font-size: 12px;
+  color: gray;
+  margin-left: 5px;
+}
+.labelCheckbox{
+    padding-left:35px !important;
+}
+.file-op-setting{
+   padding-left: 105px;
+}
+.rightAlign{
+    text-align: left !important;
+}
+.bottom-margin-zero{
+    margin-bottom: 5px !important;
+}
+#credentials_config .fa-trash-o{
+    color: @defaultRed;
+    cursor: pointer;
+}
+.credential-list {
+  margin-top: 37px;
+}
+.credential-list .fa-trash-o{
+  color: @defaultRed;
+  cursor: pointer;
+}
+.credential-list .fa-pencil{
+  color : @bgGreenActive;
+  cursor: pointer;
+}
+.check-class{
+    padding-left: 3%;
+}
+.popover-title{
+  background-color:#fff
+}
+.centralize-panel{
+  margin-left: 17%;
+}
+.dataset-list {
+  margin-top: 37px;
+}
+
+.dataset-list .fa-trash-o{
+  color: @defaultRed;
+  cursor: pointer;
+}
+
+.dataset-list .fa-pencil{
+  color : @bgGreenActive;
+  cursor: pointer;
+}
+
+.node {
+  stroke: #fff;
+  stroke-width: 2px;
+}
+
+.link {
+  fill: none;
+  stroke: #000;
+}
+
+.cy-panel {
+  height: 500px;
+  position: relative;
+  border: 1px solid #ccc;
+  border-radius: 3px;
+}
+
+.cy-panzoom {
+  left: 90%;
+  z-index: 999;
+}
+
+.overlay_node_editor {
+  position: absolute;
+  z-index: 100;
+  overflow: hidden;
+  margin-top: 3px;
+  margin-left: 5px;
+  display: none;
+}
+
+.overlay-node-label {
+  position: absolute;
+  z-index: 100;
+  display: none;
+  background-color: #fbfbfb;
+  min-width: 110px;
+  border: 1px solid #999;
+  padding: 0 5px;
+  height: 18px;
+  font-size: 12px;
+}
+
+#cyRenderer .editable {
+  padding: 7px 10px;
+  border: 1px solid #999;
+  background: #fff;
+  cursor: text;
+  white-space: nowrap;
+  text-align: left;
+  width: 140px;
+}
+
+#cyRenderer .error {
+  padding: 5px 10px;
+  border: 1px solid @defaultRed;
+  background: #fff;
+  cursor: text;
+  white-space: nowrap;
+  text-align: left;
+  width: 140px;
+}
+
+#cyRenderer input:invalid {
+  border: 1px solid @defaultRed;
+}
+
+.decision-condition-label {
+  border-bottom: 1px solid #D0D0D0;
+  padding: 3px;
+  min-width: 120px;
+}
+
+.decision-condition-header {
+  font-weight: bold;
+}
+
+.overlay-transition-content,
+.overlay-node-actions {
+  position: absolute;
+  z-index: 100;
+  overflow: hidden;
+  display: none;
+  border: 1px solid #999;
+  background: #fff;
+  border-radius: 3px;
+  min-width: 25px;
+}
+
+.overlay-node-actions {
+  height: 32px;
+  cursor: pointer;
+  padding: 2px;
+}
+
+.overlay-transition-actions {
+  float: right;
+  height: 30px;
+  cursor: pointer;
+  padding: 2px;
+}
+
+.overlay-node-actions span {
+  display: none;
+}
+
+.overlay-transition-actions span i,
+.overlay-node-actions span i {
+  min-width: 20px;
+  padding: 5px;
+  border: 1px solid transparent;
+  border-radius: 2px;
+}
+
+.overlay-transition-actions span i:hover,
+.overlay-node-actions span i:hover{
+  border: 1px solid #ababab;
+}
+
+.overlay-trash-transition-icon .fa-trash-o,
+.overlay-trash-icon .fa-trash-o {
+    color: @defaultRed;
+}
+
+.overlay-plus-icon .fa-plus-square {
+  color: @bgGreenActive;
+}
+.cyScrollMsg {
+  text-align: center;
+}
+
+.cyScrollMsgContent {
+  width: 30px;
+  background-color: #ccc;
+}
+
+.text-bold {
+  font-weight: bold;
+}
+
+.green-border {
+  border-color: green;
+}
+
+.configuration-property-table .propertyName {
+  word-break: break-all;
+  width: 20%;
+}
+
+.configuration-property-table .propertyValue {
+  width: 80%;
+  word-break: break-all;
+}
+
+.undo {
+  cursor: pointer;
+}
+
+.paste-action {
+  font-size: 10px;
+}
+
+.paste-action-btn {
+  border: 1px solid silver;
+  border-radius: 6px;
+  margin-left: 5px;
+  margin-bottom: 4px
+}
+#notificationWidget{
+  width: 20%;
+  float: left;
+  position: fixed;
+  top: 15%;
+  left: 66%;
+  word-break: break-all;
+  height: 50%;
+  max-height: 600px;
+  overflow-y: scroll;
+  z-index: 1040;
+}
+
+.closeTab {
+  margin-left: 10px;
+  cursor: pointer;
+  color: @defaultRed;
+}
+
+.tab-panel-heading {
+  margin-top: 2px;
+}
+
+.borderTopNone {
+  border-top: none;
+}
+
+.borderRadiusNone {
+  border-radius: 0px;
+}
+
+.borderRightRadiusNone {
+  border-top-right-radius: 0px;
+  border-bottom-right-radius: 0px;
+}
+
+.kill-message {
+  font-style: italic;
+  color: gray;
+}
+
+.ok-to-warning {
+  font-style: italic;
+  color: #8a6d3b;
+  background-color: #fcf8e3;
+}
+
+.kill-nodes-list {
+  height: 200px;
+  overflow-y: auto;
+}
+
+.kill-nodes-list .fa-trash-o{
+  color: @defaultRed;
+  cursor: pointer;
+}
+
+.kill-nodes-list .fa-pencil{
+  color : @bgGreenActive;
+  cursor: pointer;
+}
+
+#killnode-manager-dialog .panel-footer {
+  background-color: #fff;
+}
+
+.plr0px {
+  padding-left: 0px;
+  padding-right: 0px;
+}
+#stackTrace{
+  white-space: pre-wrap;
+  max-width: 100%;
+  max-height: 400px;
+  overflow: scroll;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/.gitkeep b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/bundle-config.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/bundle-config.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/bundle-config.hbs
new file mode 100644
index 0000000..27168a4
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/bundle-config.hbs
@@ -0,0 +1,129 @@
+{{!
+* 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.
+}}
+<div class="main">
+  <nav class="navbar navbar-default mb0 borderTopNone">
+    <div class="container-fluid container-custom">
+      <div class="navbar-header">
+        <div class="form-inline col-xs-6 paddingtop8">
+          <div class="form-group {{if (v-get this 'bundle.name' 'isInvalid') 'has-error'}}" >
+            <label for="wf_title">Name<span class="requiredField">&nbsp;*</span></label>
+            {{input class="form-control" type="text" name="bundle_title" value=bundle.name title="Bundle Name" placeholder="Bundle Name"}}
+            {{#if (v-get this 'bundle.name' 'isInvalid')}}
+              <span class="text-danger" title="Name is required"><i class="fa fa-close"></i>Name is required</span>
+            {{/if}}
+          </div>
+        </div>
+        <div class="navbar-brand pull-right paddingtop8 col-xs-18">
+          <div class="btn-group" role="group" aria-label="...">
+            <button type="button" class="btn btn-default"  data-toggle="modal" data-target="#ConfirmDialog" title="New Workflow" {{action "confirmReset"}}>
+              <i class="fa fa-refresh"> Reset</i>
+            </button>
+            <button  type="button" class="btn btn-default" title="Import workflow" {{action "openFileBrowser" "bundleFilePath"}}>
+              <i class="fa fa-download"> Import</i>
+            </button>
+            <button  id="import-bundle-test" type="button" class="btn btn-default hide" title="Import Bundle Test" {{action "importBundleTest"}}>
+              <i class="fa fa-download"></i>
+            </button>
+            <div class="btn-group">
+              <div class="dropdown">
+                <button class="btn btn-default dropdown-toggle borderRadiusNone" type="button" data-toggle="dropdown"><i class="marginright5"></i>More
+                <span class="caret"></span></button>
+                <ul class="dropdown-menu">
+                  <li>
+                    <a href="javascript:void(0)" data-toggle="modal" data-target="#previewModal"  title="Preview Xml" {{action "preview"}}>
+                      <i class="fa fa-eye marginright5"></i>Preview xml
+                    </a>
+                  </li>
+                  <!-- <li>
+                    <a href="javascript:void(0)" data-toggle="modal" title="Download workflow" {{action "downloadWorkflowXml"}}>
+                      <i class="fa fa-download marginright5"></i>Download xml
+                    </a>
+                  </li> -->
+                </ul>
+              </div>
+            </div>
+            <button type="button" class="btn btn-primary" title="Submit Bundle" {{action "submitBundle"}}>
+              <i class="fa fa-upload"> Submit</i>
+            </button>
+          </div>
+        </div>
+      </div>
+    </div>
+  </nav>
+  <div class="container-fluid">
+    <form class="form-horizontal">
+      <div class="col-sm-12 paddingtop10">
+        <div class="col-sm-8 centralize-panel">
+
+          <div class="panel panel-default">
+            <div class="panel-heading clearfix">
+              <h4 class="panel-title pull-left paddingtop7">Coordinators</h4>
+              <button id="coordinator-create-btn" {{action 'createCoordinator'}} type="button" class="btn btn-default pull-right">
+                      <i class="fa fa-plus-circle"></i> Add Coordinator
+              </button>
+            </div>
+            <div class="panel-body">
+                <ul class="list-group">
+                  {{#each bundle.coordinators as |coordinator index|}}
+                  <li class="list-group-item">
+                    {{coordinator.name}}
+                    <span class="pull-right">
+                      <i class="fa fa-trash-o" title="Delete" {{action "deleteCoordinator" index bubbles=false}}></i>
+                    </span>
+                    <span class="pull-right paddingright10">
+                      <i class="fa fa-pencil" title="Edit" {{action "editCoordinator" index bubbles=false}}></i>
+                    </span>
+                  </li>
+                  {{else}}
+                  <li class="list-group-item">No Coordinators Configured.</li>
+                  {{/each}}
+                </ul>
+                {{#field-error model=this field='bundle.coordinators' showErrorMessage=true}}{{/field-error}}
+
+              {{#if coordinatorCreateMode}}
+              {{#bundle-coord-config coordinator=currentCoordinator openTab="openTab" openFileBrowser="openFileBrowser" add="addCoordinator" cancel="cancelCoordinatorOperation" createMode=coordinatorCreateMode}}{{/bundle-coord-config}}
+              {{/if}}
+              {{#if coordinatorEditMode}}
+              {{#bundle-coord-config coordinator=currentCoordinator openTab="openTab" openFileBrowser="openFileBrowser" update="updateCoordinator" cancel="cancelCoordinatorOperation" editMode=coordinatorEditMode}}{{/bundle-coord-config}}
+              {{/if}}
+            </div>
+          </div>
+          <div class="panel panel-default">
+            <div class="panel-body">
+              {{#date-with-expr inputName="kickOffTime" label="Kick off Time" inputPlaceholder="Kick Off Time" dateField=bundle.kickOffTime}}{{/date-with-expr}}
+            </div>
+          </div>
+        </div>
+      </div>
+    </form>
+  </div>
+</div>
+{{#if showingFileBrowser}}
+  {{hdfs-browser closeFileBrowser="closeFileBrowser" selectFileCallback=selectFileCallback filePath=filePath}}
+{{/if}}
+{{#if showingJobConfig}}
+  {{job-config type='bundle' closeJobConfigs="closeBundleSubmitConfig" jobFilePath=bundleFilePath openFileBrowser="openFileBrowser" closeFileBrowser="closeFileBrowser" jobConfigs=bundleConfigs}}
+{{/if}}
+{{#if showingResetConfirmation}}
+  {{#confirmation-dialog title="Confirm Bundle Reset"
+  confirmationMessage="Any unsaved changes may be lost. Do you want to proceed resetting the bundle ?"
+  okBtnText="Continue" cancelBtnText="Cancel" onOk="resetBundle"}}{{/confirmation-dialog}}
+{{/if}}
+{{#if showingPreview}}
+  {{#preview-dialog title="Bundle XML Preview" previewXml=previewXml}}{{/preview-dialog}}
+{{/if}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/bundle-coord-config.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/bundle-coord-config.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/bundle-coord-config.hbs
new file mode 100644
index 0000000..86a49b9
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/bundle-coord-config.hbs
@@ -0,0 +1,58 @@
+{{!
+* 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.
+}}
+<div class="well">
+  <div class="form-group">
+    <label class="control-label col-xs-2">Coordinator Name<span class="requiredField">&nbsp;*</span></label>
+    <div class="col-xs-7">
+      {{input type="text" class="form-control" name="name" value=coordinator.name placeholder="Coordinator Name"}}
+      {{#field-error model=this field='coordinator.name' showErrorMessage=showErrorMessage}}{{/field-error}}
+    </div>
+  </div>
+  <div class="form-group">
+    <label class="control-label col-xs-2">Coordinator Path<span class="requiredField">&nbsp;*</span></label>
+    <div class="col-xs-7">
+      <div class="input-group">
+        {{input type="text" class="form-control" name="appPath" focus-out="showCoordinatorName" value=coordinator.appPath placeholder="Path of the coordinator file"}}
+        <span class="input-group-btn">
+          <button class="btn btn-primary" type="button" {{action "openFileBrowser" "coordinator.appPath"}}>Browse</button>
+          <button class="btn btn-default" type="button" {{action "openTab" 'coord' coordinator.appPath}} name="button"><i class="fa fa-external-link"></i></button>
+        </span>
+      </div>
+      {{#if coordinatorName}}
+        <span title="Name of the coordinator">({{coordinatorName}})</span>
+      {{/if}}
+      {{#field-error model=this field='coordinator.appPath' showErrorMessage=showErrorMessage}}{{/field-error}}
+    </div>
+  </div>
+  <div class="panel panel-default">
+    <div class="panel-heading">Configuration</div>
+    <div class="panel-body handlerPanel">
+      {{#name-value-config configuration=coordinator.configuration}}{{/name-value-config}}
+    </div>
+  </div>
+  <div class="form-group">
+    <div class="col-xs-7 pull-right">
+      <button id="coordinator-cancel-btn" {{action 'cancelCoordinatorOperation'}} type="button" class="btn btn-default">Cancel</button>
+      {{#if createMode}}
+      <button id="coordinator-add-btn" {{action 'addCoordinator'}} type="button" class="btn btn-primary">Add</button>
+      {{else}}
+      <button id="coordinator-update-btn" {{action 'updateCoordinator'}} type="button" class="btn btn-primary"> Update </button>
+      {{/if}}
+    </div>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/bundle-job-details.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/bundle-job-details.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/bundle-job-details.hbs
index b1f1d7e..f6b491b 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/bundle-job-details.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/bundle-job-details.hbs
@@ -95,7 +95,22 @@
   <div role="tabpanel" class="tab-pane" id="jobConfig">
     <div class="panel panel-default">
       <div class="panel-body preview">
-        <pre class="prettyprint">{{model.conf}}</pre>
+        <table class="table table-striped configuration-property-table">
+          <thead>
+            <tr>
+              <th class="propertyName">Name</th>
+              <th class="propertyValue">Value</th>
+            </tr>
+          </thead>
+          <tbody>
+            {{#each model.configurationProperties as |configurationProperty|}}
+              <tr>
+                <td class="propertyName">{{configurationProperty.name}}</td>
+                <td class="propertyValue">{{configurationProperty.value}}</td>
+              </tr>
+            {{/each}}
+          </tbody>
+        </table>
       </div>
     </div>
   </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/conditional-data-input.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/conditional-data-input.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/conditional-data-input.hbs
new file mode 100644
index 0000000..03eb0d8
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/conditional-data-input.hbs
@@ -0,0 +1,64 @@
+{{!
+* 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.
+}}
+<div class="form-inline">
+  <select onchange={{action (mut condition.operator) value="target.value"}} name="select-input" class="form-control" data-show-icon="true">
+    {{#each conditionsList as |condition index|}}
+    <option value={{condition.value}} selected={{eq condition.operator condition.value}}>{{condition.displayName}}</option>
+    {{/each}}
+  </select>
+  {{#if (not (eq condition.operator "combine"))}}
+    <button id="data-add-btn" {{action 'addCondition'}} type="button" class="btn btn-default form-control">
+    <i class="fa fa-plus-circle"></i>&nbsp;Condition</button>
+  {{/if}}
+  <button id="data-add-btn" {{action 'addDataInput'}} type="button" class="btn btn-default form-control">
+    <i class="fa fa-plus-circle"></i>&nbsp;Data Input</button>
+  {{#if showAdvanced}}
+  {{input type="text" class="form-control" name="conditionName" title="Condition Name" value=condition.name placeholder="Condition Name"}}
+  {{input type=text class="form-control" value=condition.min placeholder="Mininum Inputs"}}
+  {{input type=text class="form-control" value=condition.wait placeholder="Wait Time"}}
+  <button id="data-add-btn" {{action 'hideAdvanced'}} type="button" title="Configure Advanced Options" class="form-control btn btn-default">
+    <i class="fa fa-chevron-left"></i>&nbsp;Advanced
+  </button>
+  {{else}}
+  <button id="data-add-btn" {{action 'showAdvanced'}} type="button" title="Configure Advanced Options" class="form-control btn btn-default">
+    <i class="fa fa-chevron-right"></i>&nbsp;Advanced
+  </button>
+  {{/if}}
+  {{yield}}
+  {{field-error model=this field='condition.operator' showErrorMessage=showErrorMessage}}
+  {{field-error model=this field='condition.operands' showErrorMessage=showErrorMessage}}
+</div>
+<ul class="list-group">
+  {{#each condition.operands as |operand index|}}
+  <li class="list-group-item">
+    {{#if (eq operand.type 'condition') }}
+    {{#conditional-data-input condition=operand datasets=datasets}}
+    <span class="pull-right">
+      <i class="fa fa-trash-o" title="Delete" {{action "deleteOperand" index bubbles=false}}></i>
+    </span>
+    {{/conditional-data-input}}
+    {{else}}
+      {{#data-input datasets=datasets dataInput=operand register="registerChild" deregister="deregisterChild"}}
+      <span class="pull-right">
+        <i class="fa fa-trash-o" title="Delete" {{action "deleteOperand" index bubbles=false}}></i>
+      </span>
+      {{/data-input}}
+    {{/if}}
+  </li>
+  {{/each}}
+</ul>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/confirmation-dialog.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/confirmation-dialog.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/confirmation-dialog.hbs
new file mode 100644
index 0000000..fc86286
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/confirmation-dialog.hbs
@@ -0,0 +1,34 @@
+{{!
+* 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.
+}}
+<div id="ConfirmDialog" class="modal fade" role="dialog">
+  <div class="modal-dialog">
+    <div class="modal-content">
+      <div class="modal-header">
+        <button type="button" class="close" data-dismiss="modal">&times;</button>
+        <h4 class="modal-title">{{title}}</h4>
+      </div>
+      <div class="modal-body">
+      {{confirmationMessage}}
+      </div>
+      <div class="modal-footer">
+        <button type="button" class="btn btn-default" data-dismiss="modal">{{cancelBtnText}}</button>
+        <button type="button" class="btn btn-primary" {{action "onOk"}} data-dismiss="modal">{{okBtnText}}</button>
+      </div>
+    </div>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/coord-config.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/coord-config.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/coord-config.hbs
new file mode 100644
index 0000000..a6edcec
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/coord-config.hbs
@@ -0,0 +1,352 @@
+{{!
+* 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.
+}}
+<div class="main">
+  <nav class="navbar navbar-default mb0 borderTopNone">
+    <div class="container-fluid container-custom">
+      <div class="navbar-header">
+        <div class="form-inline col-xs-6 paddingtop8">
+          <div class="form-group {{if (v-get this 'coordinator.name' 'isInvalid') 'has-error'}}">
+            <label for="wf_title">Name </label>
+            {{input class="form-control" type="text" name="coord_title" value=coordinator.name title="Coordinator Name" placeholder="Coordinator Name"}}
+            {{#if (v-get this 'coordinator.name' 'isInvalid')}}
+              <span class="text-danger" title="Name is required"><i class="fa fa-close"></i>Name is required</span>
+            {{/if}}
+          </div>
+        </div>
+        <div class="navbar-brand pull-right paddingtop8 col-xs-18">
+          <div class="btn-group" role="group" aria-label="...">
+            <button type="button" class="btn btn-default"  data-toggle="modal" data-target="#ConfirmDialog" title="New Workflow" {{action "confirmReset"}}>
+              <i class="fa fa-refresh"> Reset</i>
+            </button>
+            <button  type="button" class="btn btn-default" title="Import workflow" {{action "openFileBrowser" "coordinatorFilePath"}}>
+              <i class="fa fa-download"> Import</i>
+            </button>
+
+            <button  id="import-test" type="button" class="btn btn-default hide" title="Import coordinator Test" {{action "importCoordinatorTest"}}>
+              <i class="fa fa-download"></i>
+            </button>
+            <button type="button" class="btn btn-default" title="Parameters Configuration" {{action "showParameterSettings" true}}>
+              <i class="fa fa-cog marginright5"></i>Parameters
+            </button>
+            <button type="button" class="btn btn-default"  data-toggle="modal" data-target="#control-dialog" title="Coordinator Controls" {{action "showControlConfig"}}>
+                 <i class="fa fa-wrench marginright5"></i>Controls
+            </button>
+            <div class="btn-group">
+              <div class="dropdown">
+                <button class="btn btn-default dropdown-toggle borderRadiusNone" type="button" data-toggle="dropdown"><i class="marginright5"></i>More
+                <span class="caret"></span></button>
+                <ul class="dropdown-menu">
+                  <li>
+                    <a href="javascript:void(0)" data-toggle="modal" data-target="#previewModal"  title="Preview Xml" {{action "preview"}}>
+                      <i class="fa fa-eye marginright5"></i>Preview xml
+                    </a>
+                  </li>
+                  <!-- <li>
+                    <a href="javascript:void(0)" data-toggle="modal" title="Download workflow" {{action "downloadWorkflowXml"}}>
+                      <i class="fa fa-download marginright5"></i>Download xml
+                    </a>
+                  </li> -->
+                </ul>
+              </div>
+            </div>
+            <button type="button" class="btn btn-primary" title="Submit Coordinator" {{action "submitCoordinator"}}>
+              <i class="fa fa-upload marginright5"></i>Submit
+            </button>
+          </div>
+        </div>
+      </div>
+    </div>
+  </nav>
+  <div class="container-fluid">
+    <form class="form-horizontal">
+      <div class="col-sm-12 paddingtop10">
+        <div class="col-sm-8 centralize-panel">
+          <div class="panel panel-default">
+            <div class="panel-body">
+              <div class="form-group">
+                <label class="control-label col-xs-2">Workflow Path<span class="requiredField">&nbsp;*</span></label>
+                <div class="col-xs-7">
+                  <div class="input-group">
+                    {{input type="text" class="form-control" name="appPath" focus-out="showWorkflowName" value=coordinator.workflow.appPath placeholder="Path of the workflow file"}}
+                    <span class="input-group-btn">
+                      <button class="btn btn-primary" type="button" {{action "openFileBrowser" "coordinator.workflow.appPath"}}>Browse</button>
+                      <button class="btn btn-default" type="button" {{action "openTab" 'wf' coordinator.workflow.appPath}} name="button"><i class="fa fa-external-link"></i></button>
+                    </span>
+                  </div>
+                  {{#if workflowName}}
+                    <span title="Name of the workflow">({{workflowName}})</span>
+                  {{/if}}
+                  {{#field-error model=this field='coordinator.workflow.appPath' showErrorMessage=showErrorMessage}}{{/field-error}}
+                </div>
+              </div>
+              <div class="form-group">
+                <label class="control-label col-xs-2">Frequency<span class="requiredField">&nbsp;*</span></label>
+                <div class="col-xs-2">
+                  <select class="form-control" name="frequency-type" title="Frequency type" onchange={{action (mut coordinator.frequency.type) value="target.value"}}>
+                    {{#each timeUnitOptions as |timeUnit|}}
+                    <option value={{timeUnit.value}} selected={{eq timeUnit.value coordinator.frequency.type}}>{{timeUnit.displayName}}</option>
+                    {{/each}}
+                  </select>
+                  {{#field-error model=this field='coordinator.frequency.type' showErrorMessage=showErrorMessage}}{{/field-error}}
+                </div>
+                <div class="col-xs-3">
+                  {{input class="form-control" type="text" value=coordinator.frequency.value placeholder="frequency" title="Periodic intervals at which datasets that are produced, and coordinator applications are scheduled to run"}}
+                  {{field-error model=this field='coordinator.frequency.value' showErrorMessage=showErrorMessage}}
+                </div>
+              </div>
+              {{#date-with-expr required=true inputName="start" label="Start" inputPlaceholder="Start Time" dateField=coordinator.start timezone=coordinator.timezone register="registerChild" deregister="deregisterChild"}}{{/date-with-expr}}
+              {{#date-with-expr required=true inputName="end" label="End" inputPlaceholder="End Time" dateField=coordinator.end timezone=coordinator.timezone register="registerChild" deregister="deregisterChild"}}{{/date-with-expr}}
+              <div class="form-group">
+                <label for="" class="control-label col-xs-2">Time Zone<span class="requiredField">&nbsp;*</span></label>
+                <div class="col-xs-7">
+                  <select onchange={{action (mut coordinator.timezone) value="target.value"}} name="select-input" class="form-control" data-show-icon="true">
+                    {{#each timezoneList as |timezone index|}}
+                    <option value={{timezone.value}} selected={{eq timezone.value coordinator.timezone}}>{{timezone.displayName}}</option>
+                    {{/each}}
+                  </select>
+                  {{field-error  model=this field='coordinator.timezone' showErrorMessage=showErrorMessage}}
+                </div>
+              </div>
+              <div class="panel panel-default">
+                <div class="panel-heading clearfix">
+                  <h4 class="panel-title pull-left paddingtop7">Configuration</h4>
+                </div>
+                <div class="panel-body handlerPanel">
+                  {{#name-value-config configuration=coordinator.workflow.configuration}}{{/name-value-config}}
+                </div>
+              </div>
+              {{#sla-info slaInfo=coordinator.slaInfo register="registerChild" slaEnabled=coordinator.slaEnabled}}{{/sla-info}}
+            </div>
+          </div>
+          <div class="panel panel-default">
+            <div class="panel-heading clearfix">
+              <h4 class="panel-title pull-left paddingtop7">Data</h4>
+            </div>
+            <div class="panel-body handlerPanel">
+              <div class="panel panel-default">
+                <div class="panel-heading clearfix">
+                  <h4 class="panel-title pull-left paddingtop7">Datasets</h4>
+                  <button id="dataset-create-btn" {{action 'createDataset'}} type="button" class="btn btn-default pull-right">
+                    <i class="fa fa-plus-circle"></i> Add Dataset
+                  </button>
+                </div>
+                <div class="panel-body">
+                  <ul class="list-group">
+                    {{#each coordinator.datasets as |dataset index|}}
+                    <li class="list-group-item">
+                      {{dataset.name}}
+                      <span class="pull-right">
+                        <i class="fa fa-trash-o" title="Delete" {{action "deleteDataset" index bubbles=false}}></i>
+                      </span>
+                      <span class="pull-right paddingright10">
+                        <i class="fa fa-pencil" title="Edit" {{action "editDataset" index bubbles=false}}></i>
+                      </span>
+                    </li>
+                    {{else}}
+                    <li class="list-group-item">No Datasets Configured.</li>
+                    {{/each}}
+                  </ul>
+                  {{#if datasetCreateMode}}
+                    {{#dataset-config dataset=currentDataset add="addDataset" cancel="cancelDatasetOperation" createMode=datasetCreateMode}}{{/dataset-config}}
+                  {{/if}}
+                  {{#if datasetEditMode}}
+                    {{#dataset-config dataset=currentDataset update="updateDataset" cancel="cancelDatasetOperation" editMode=datasetEditMode}}{{/dataset-config}}
+                  {{/if}}
+                </div>
+              </div>
+              <div class="panel panel-default">
+                <div class="panel-heading clearfix">
+                  <h4 class="panel-title pull-left paddingtop7">Inputs</h4>
+                </div>
+                <div class="panel-body handlerPanel">
+                  {{#if coordinator.supportsConditionalDataInput}}
+                  <div class="">
+                    <label for="" class="control-label col-xs-2">Data Input Type</label>
+                    <div class="btn-group">
+                      <button {{action 'toggleDataTnput' 'simple'}} type="button" class="btn btn-default {{if (eq coordinator.dataInputType 'simple') 'btn-primary' ''}} scope-btn">
+                        Simple
+                      </button>
+                      <button {{action 'toggleDataTnput' 'logical'}} type="button" class="btn btn-default {{if (eq coordinator.dataInputType 'logical') 'btn-primary' ''}} scope-btn">
+                        Conditional
+                      </button>
+                    </div>
+                  </div>
+                  {{/if}}
+                  <div class="panel panel-default">
+                    <div class="panel-heading clearfix">
+                      <h4 class="panel-title pull-left paddingtop7">Datasets</h4>
+                      {{#if (eq coordinator.dataInputType 'simple')}}
+                        <button id="dataset-create-btn" {{action 'createDataInput'}} type="button" class="btn btn-default pull-right">
+                          <i class="fa fa-plus-circle"></i> Add Data Input
+                        </button>
+                      {{else}}
+                        {{#if (not conditionalDataInExists)}}
+                        <button id="condition-create-btn" {{action 'createCondition'}} type="button" class="btn btn-default pull-right">
+                          <i class="fa fa-plus-circle"></i> Add Condition
+                        </button>
+                        {{/if}}
+                      {{/if}}
+                    </div>
+                    <div class="panel-body">
+                      {{#if (eq coordinator.dataInputType 'simple')}}
+                        <ul class="list-group">
+                          {{#each coordinator.dataInputs as |data index|}}
+                          <li class="list-group-item">
+                            {{data.name}}
+                            <span class="pull-right">
+                              <i class="fa fa-trash-o" title="Delete" {{action "deleteDataInput" index bubbles=false}}></i>
+                            </span>
+                            <span class="pull-right paddingright10">
+                              <i class="fa fa-pencil" title="Edit" {{action "editDataInput" index bubbles=false}}></i>
+                            </span>
+                          </li>
+                          {{else}}
+                          <li class="list-group-item">No Data inputs Configured</li>
+                          {{/each}}
+                        </ul>
+                        {{#if dataInputCreateMode}}
+                          {{#data-input-output-config datasets=datasetsForInputs data=currentDataInput type="input" add="addDataInput" cancel="cancelDataInputOperation" createMode=dataInputCreateMode}}{{/data-input-output-config}}
+                        {{/if}}
+                        {{#if dataInputEditMode}}
+                          {{#data-input-output-config datasets=datasetsForInputs data=currentDataInput type="input" update="updateDataInput" cancel="cancelDataInputOperation" editMode=dataInputEditMode}}{{/data-input-output-config}}
+                        {{/if}}
+                      {{/if}}
+                      {{#if (eq coordinator.dataInputType 'logical')}}
+                      <ul class="list-groups">
+                        {{#if conditionalDataInExists}}
+                        <li class="list-group-item">
+                          {{#conditional-data-input condition=coordinator.conditionalDataInput datasets=datasetsForInputs isToplevel=true register="registerChild" deregister="deregisterChild"}}
+                          <span class="pull-right">
+                            <i class="fa fa-trash-o" title="Delete" {{action "deleteCondition" index bubbles=false}}></i>
+                          </span>
+                          {{/conditional-data-input}}
+                        </li>
+                        {{else}}
+                        <li class="list-group-item">No Conditional Data Inputs Configured</li>
+                        {{/if}}
+                      </ul>
+                      {{/if}}
+                    </div>
+                  </div>
+                  <div class="panel panel-default">
+                    <div class="panel-heading clearfix">
+                      <h4 class="panel-title pull-left paddingtop7">Conditional Inputs</h4>
+                      {{#if (not inputLogicExists)}}
+                      <button id="condition-create-btn" {{action 'createInputLogic'}} type="button" class="btn btn-default pull-right">
+                        <i class="fa fa-plus-circle"></i> Add Condition
+                      </button>
+                      {{/if}}
+                    </div>
+                    <div class="panel-body handlerPanel">
+                      <ul class="list-group">
+                        {{#if inputLogicExists}}
+                        <li class="list-group-item">
+                          {{#conditional-data-input condition=coordinator.inputLogic datasets=datasetsForInputs isToplevel=true register="registerChild" deregister="deregisterChild"}}
+                          <span class="pull-right">
+                            <i class="fa fa-trash-o" title="Delete" {{action "deleteInputLogic" index bubbles=false}}></i>
+                          </span>
+                          {{/conditional-data-input}}
+                        </li>
+                        {{else}}
+                        <li class="list-group-item">No Conditional Data Inputs Configured</li>
+                        {{/if}}
+                      </ul>
+                    </div>
+                  </div>
+                </div>
+              </div>
+              <div class="panel panel-default">
+                <div class="panel-heading clearfix">
+                  <h4 class="panel-title pull-left paddingtop7">Outputs</h4>
+                  <button id="dataset-create-btn" {{action 'createDataOutput'}} type="button" class="btn btn-default pull-right">
+                    <i class="fa fa-plus-circle"></i> Add Data Output
+                  </button>
+                </div>
+                <div class="panel-body">
+                  <ul class="list-group">
+                    {{#each coordinator.dataOutputs as |data index|}}
+                    <li class="list-group-item">
+                      {{data.name}}
+                      <span class="pull-right">
+                        <i class="fa fa-trash-o" title="Delete" {{action "deleteDataOutput" index bubbles=false}}></i>
+                      </span>
+                      <span class="pull-right paddingright10">
+                        <i class="fa fa-pencil" title="Edit" {{action "editDataOutput" index bubbles=false}}></i>
+                      </span>
+                    </li>
+                    {{else}}
+                    <li class="list-group-item">No Data Ouputs Configured</li>
+                    {{/each}}
+                  </ul>
+                  {{#if dataOutputCreateMode}}
+                    {{#data-input-output-config datasets=datasetsForOutputs data=currentDataOutput type="output" add="addDataOutput" cancel="cancelDataOutputOperation" createMode=dataOutputCreateMode}}{{/data-input-output-config}}
+                  {{/if}}
+                  {{#if dataOutputEditMode}}
+                    {{#data-input-output-config datasets=datasetsForOutputs data=currentDataOutput type="output" update="updateDataOutput" cancel="cancelDataOutputOperation" editMode=dataOutputEditMode}}{{/data-input-output-config}}
+                  {{/if}}
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </form>
+  </div>
+</div>
+{{#if showingFileBrowser}}
+  {{hdfs-browser closeFileBrowser="closeFileBrowser" selectFileCallback=selectFileCallback filePath=filePath}}
+{{/if}}
+{{#if showingJobConfig}}
+  {{job-config type='coord' closeJobConfigs="closeCoordSubmitConfig" jobFilePath=coordinatorFilePath openFileBrowser="openFileBrowser" closeFileBrowser="closeFileBrowser" jobConfigs=coordinatorConfigs}}
+{{/if}}
+{{#if showingResetConfirmation}}
+  {{#confirmation-dialog title="Confirm Coordinator Reset"
+    confirmationMessage="Any unsaved changes may be lost. Do you want to proceed resetting the coordinator ?"
+    okBtnText="Continue" cancelBtnText="Cancel" onOk="resetCoordinator"}}{{/confirmation-dialog}}
+{{/if}}
+{{#if showingPreview}}
+  {{#preview-dialog title="Coordinator XML Preview" previewXml=previewXml}}{{/preview-dialog}}
+{{/if}}
+{{#if showParameterSettings}}
+  {{#workflow-parameters type='coord' closeWorkFlowParam="closeWorkFlowParam" saveWorkFlowParam="saveWorkFlowParam" parameters=parameters}}{{/workflow-parameters}}
+{{/if}}
+{{#if showControlConfig}}
+  <div id="control-dialog" class="modal fade" role="dialog">
+    <div class="modal-dialog">
+      <div class="modal-content">
+        <div class="modal-header">
+          <button type="button" class="close" data-dismiss="modal">&times;</button>
+          <h4 class="modal-title">Controls</h4>
+        </div>
+        <div class="modal-body">
+          <div class="panel panel-default">
+            <div class="panel-body handlerPanel form-horizontal">
+              {{#each coordinatorControls as |property|}}
+                {{#named-properties property=property labelWidthClass="col-xs-4" inputWidthClass="col-xs-8"}}{{/named-properties}}
+              {{/each}}
+            </div>
+          </div>
+        </div>
+        <div class="modal-footer">
+          <button type="button" class="btn btn-primary" data-dismiss="modal" {{action "saveCoordControls"}}>Save</button>
+          <button type="button" class="btn btn-default" data-dismiss="modal" onclick={{action (mut showControlConfig) false}}>Cancel</button>
+        </div>
+      </div>
+    </div>
+  </div>
+{{/if}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/coord-job-details.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/coord-job-details.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/coord-job-details.hbs
index 65aed2d..350f873 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/coord-job-details.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/coord-job-details.hbs
@@ -119,7 +119,22 @@
   <div role="tabpanel" class="tab-pane" id="jobConfig">
     <div class="panel panel-default">
       <div class="panel-body preview">
-        <pre class="prettyprint">{{model.conf}}</pre>
+        <table class="table table-striped configuration-property-table">
+          <thead>
+            <tr>
+              <th class="propertyName">Name</th>
+              <th class="propertyValue">Value</th>
+            </tr>
+          </thead>
+          <tbody>
+            {{#each model.configurationProperties as |configurationProperty|}}
+              <tr>
+                <td class="propertyName">{{configurationProperty.name}}</td>
+                <td class="propertyValue">{{configurationProperty.value}}</td>
+              </tr>
+            {{/each}}
+          </tbody>
+        </table>
       </div>
     </div>
   </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/credentials-config.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/credentials-config.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/credentials-config.hbs
index 129b7df..366920d 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/credentials-config.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/credentials-config.hbs
@@ -18,26 +18,18 @@
 <form class="form-horizontal" id="credentials_config">
   <div class="panel panel-default">
     {{#if (eq mode 'edit')}}
-      <div class="panel-heading" id="credential-head" {{action 'togglePanel'}}>
-        <span>{{credential.name}}</span><span class="cred-type">({{credential.type}})</span>
-        {{#if isOpen}}
-          <i class="indicator glyphicon glyphicon-chevron-up pull-right"></i>
-        {{else}}
-          <i class="indicator glyphicon glyphicon-chevron-down pull-right"></i>
-        {{/if}}
-        <span class="col-xs-1 pull-right">
-          <i class="fa fa-trash-o" title="Delete" {{action "delete" credential.name bubbles=false}}></i>
-        </span>
+      <div class="panel-heading" id="credential-head">
+        <span>Edit - {{credential.name}}</span><span class="cred-type">({{credential.type}})</span>
       </div>
     {{else if (eq mode 'create')}}
-      <div class="panel-heading" id="credential-head" {{action 'togglePanel'}}>Create New</div>
+      <div class="panel-heading" id="credential-head">Create New</div>
     {{/if}}
-    <div class="panel-body handlerPanel collapse panel-collapse">
+    <div class="panel-body">
       <div class="form-group">
         <label class="control-label col-xs-2">Name<span class="requiredField">&nbsp;*</span></label>
         <div class=" col-xs-4">
           {{input class="form-control" type="text" value=credential.name}}
-          {{field-error error=errors.credential.name}}
+          {{field-error model=this field='credential.name' showErrorMessage=showErrorMessage}}
         </div>
       </div>
       <div class="form-group">
@@ -48,7 +40,7 @@
               <option value={{type.value}} selected={{eq type.value credential.type}}>{{type.displayName}}</option>
             {{/each}}
           </select>
-          {{field-error error=errors.credential.type}}
+          {{field-error model=this field='credential.type' showErrorMessage=showErrorMessage}}
         </div>
       </div>
       {{#if credential.type}}
@@ -56,7 +48,7 @@
           <div class="panel-heading">Properties</div>
           <div class="panel-body handlerPanel">
             {{#each staticProps as |property|}}
-              {{#named-properties property=property required=true register="register" labelWidthClass="col-xs-4" inputWidthClass="col-xs-4"}}{{/named-properties}}
+              {{#named-properties property=property unregisterRequired=true required=true unregister="unregister" register="register" labelWidthClass="col-xs-4" inputWidthClass="col-xs-8"}}{{/named-properties}}
             {{/each}}
           </div>
         </div>
@@ -73,11 +65,14 @@
           {{#name-value-config configuration=credential register="register"}}{{/name-value-config}}
         </div>
       </div>
-      {{#if (eq mode 'create')}}
-      <div class="col-xs-2 pull-right">
-        <input class="form-control btn btn-success" type="button" {{action "add"}} value="Add">
+      <div class="col-xs-24 pull-right">
+        <input class="btn btn-default marginright5" type="button" {{action "cancel"}} value="Cancel">
+        {{#if (eq mode 'create')}}
+          <input class="btn btn-primary" type="button" {{action "add"}} value="Add">
+        {{else}}
+          <input class="btn btn-primary" type="button" {{action "add"}} value="Update">
+        {{/if}}
       </div>
-      {{/if}}
     </div>
   </div>
 </form>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/data-input-output-config.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/data-input-output-config.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/data-input-output-config.hbs
new file mode 100644
index 0000000..2185d0d
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/data-input-output-config.hbs
@@ -0,0 +1,68 @@
+{{!
+* 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.
+}}
+<div class="well">
+  <div class="form-group">
+    <label for="" class="control-label col-xs-2">Name<span class="requiredField">&nbsp;*</span></label>
+    <div class="col-xs-7">
+      {{input type="text" class="form-control" name="coord-name" value=data.name placeholder="Name"}}
+      {{field-error model=this field='data.name' showErrorMessage=showErrorMessage}}
+    </div>
+  </div>
+  <div class="form-group">
+    <label class="control-label col-xs-2">Dataset<span class="requiredField">&nbsp;*</span></label>
+    <div class="col-xs-7">
+      <select onchange={{action (mut data.dataset) value="target.value"}} name="select-input" class="form-control" data-show-icon="true">
+        <option value="">Select Dataset</option>
+        {{#each datasets as |dataset index|}}
+        <option value={{dataset.name}} selected={{eq dataset.name data.dataset}}>{{dataset.name}}</option>
+        {{/each}}
+      </select>
+      {{field-error model=this field='data.dataset' showErrorMessage=showErrorMessage}}
+    </div>
+  </div>
+  {{#if (eq type 'input')}}
+  <div class="form-group">
+    <label class="control-label col-xs-2">Instance Type<span class="requiredField">&nbsp;*</span></label>
+    <div class="col-xs-3">
+      <input type="radio" class="marginright5" name="instanceType" checked={{if (eq data.isList true) 'checked'}} onChange={{action "onInstanceTypeChange" true}}>List of Instances
+    </div>
+    <div class="col-xs-3">
+      <input type="radio" class="marginright5" name="instanceType" checked={{if (eq data.isList false) 'checked'}} onChange={{action "onInstanceTypeChange" false}}>With Start and End
+    </div>
+  </div>
+  {{#if data.isList}}
+    {{#instance-list-config instances=data.instances title="Instance"}}{{/instance-list-config}}
+  {{else}}
+    {{#date-with-expr required=true inputName="start" label="Start" inputPlaceholder="Start Time" dateField=data.start register="registerChild" deregister="deregisterChild"}}{{/date-with-expr}}
+    {{#date-with-expr required=true inputName="end" label="End" inputPlaceholder="End Time" dateField=data.end register="registerChild" deregister="deregisterChild"}}{{/date-with-expr}}
+  {{/if}}
+  {{/if}}
+  {{#if (eq type 'output')}}
+  {{#date-with-expr required=true inputName="instance" label="Instance" inputPlaceholder="Instance" dateField=data.instance register="registerChild" deregister="deregisterChild"}}{{/date-with-expr}}
+  {{/if}}
+  <div class="form-group">
+    <div class="col-xs-7 pull-right">
+      <button id="data-add-btn" {{action 'cancel'}} type="button" class="btn btn-default">Cancel</button>
+      {{#if createMode}}
+      <button id="data-add-btn" {{action 'add'}} type="button" class="btn btn-primary">Save</button>
+      {{else}}
+      <button id="data-update-btn" {{action 'update'}} type="button" class="btn btn-primary"> Update </button>
+      {{/if}}
+    </div>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/data-input.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/data-input.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/data-input.hbs
new file mode 100644
index 0000000..b09d763
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/data-input.hbs
@@ -0,0 +1,40 @@
+{{!
+* 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.
+}}
+<div class="form-inline">
+  <label class="control-label">Data Input</label>
+  <select onchange={{action (mut dataInput.dataset) value="target.value"}} name="select-input" class="form-control" data-show-icon="true">
+    <option value="">Select Dataset</option>
+    {{#each datasets as |dataset index|}}
+    <option value={{dataset.name}} selected={{eq dataset.name dataInput.dataset}}>{{dataset.name}}</option>
+    {{/each}}
+  </select>
+  {{#if showAdvanced}}
+    {{input type=text class="form-control" value=dataInput.name placeholder="Data Input Name"}}
+    {{input type=text class="form-control" value=dataInput.min placeholder="Mininum Inputs"}}
+    {{input type=text class="form-control" value=dataInput.wait placeholder="Wait Time"}}
+    <button id="data-add-btn" {{action 'hideAdvanced'}} type="button" title="Configure Advanced Options" class="form-control btn btn-default">
+      <i class="fa fa-chevron-left"></i>&nbsp;Advanced
+    </button>
+  {{else}}
+    <button id="data-add-btn" {{action 'showAdvanced'}} type="button" title="Configure Advanced Options" class="form-control btn btn-default">
+      <i class="fa fa-chevron-right"></i>&nbsp;Advanced
+    </button>
+  {{/if}}
+  {{yield}}
+</div>
+{{field-error model=this field='dataInput.dataset' showErrorMessage=showErrorMessage}}


[03/10] ambari git commit: AMBARI-18691. Improve and Update Workflow designer to support coordinators and bundles. (Belliraj HB via dipayanb)

Posted by db...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/named-properties.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/named-properties.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/named-properties.hbs
index 2fa78bc..5750422 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/named-properties.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/named-properties.hbs
@@ -21,6 +21,6 @@
   </label>
   <div class="{{inputWidthClass}}">
     {{input type="text" class="form-control" value=property.value placeholder="value"}}
-    {{field-error error=errors.property.value}}
+    {{field-error model=this field='property.value' showErrorMessage=showErrorMessage}}
   </div>
 </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/pig-action-info.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/pig-action-info.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/pig-action-info.hbs
new file mode 100644
index 0000000..abc8cba
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/pig-action-info.hbs
@@ -0,0 +1,47 @@
+{{!
+* 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.
+}}
+<div id="notificationWidget" class="">
+    <!--a href="#" class="close " data-dismiss="alert" aria-label="close">&times;</a-->
+	<ul class="list-group">
+	  <li class="list-group-item">{{info-header  hoveredAction=hoveredAction hideNotification="hideNotification"}}</li>
+	  {{#if hoveredAction.nameNode}}<li class="list-group-item"><b>Name Node : </b><br/>{{hoveredAction.nameNode}}</li>{{/if}}
+	  {{#if hoveredAction.nameNode}}<li class="list-group-item"><b>Resource Manager : </b><br/>{{hoveredAction.jobTracker}} </li>{{/if}}
+	  {{#if hoveredAction.nameNode}}<li class="list-group-item"><b>Script :  </b><br/>{{hoveredAction.script}}</li>{{/if}}
+	  {{#if hoveredAction.nameNode}}<li class="list-group-item"><b>Job xml : </b>
+	    {{#property-value-config action=hoveredAction.jobXml}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.nameNode}}<li class="list-group-item"><b>Archives : </b>
+	    {{#property-value-config action=hoveredAction.archives}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.nameNode}}<li class="list-group-item"><b>Files : </b>
+	    {{#property-value-config action=hoveredAction.files}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.nameNode}}<li class="list-group-item"><b>Params : </b>
+	    {{#property-value-config action=hoveredAction.params}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.nameNode}}<li class="list-group-item"><b>Args : </b>
+	    {{#property-value-config action=hoveredAction.args}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.nameNode}}<li class="list-group-item"><b>Prepare : </b>
+	    {{#prepare-config-info action=hoveredAction}}{{/prepare-config-info}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.nameNode}}<li class="list-group-item"><b>Configuration : </b>
+	    {{#name-value-info action=hoveredAction}}{{/name-value-info}}
+	  </li>{{/if}}
+	</ul>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/pig-action.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/pig-action.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/pig-action.hbs
index eb38432..d0fe490 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/pig-action.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/pig-action.hbs
@@ -26,7 +26,7 @@
           <button class="btn btn-primary" type="button" {{action "openFileBrowser" "actionModel.script"}}>Browse</button>
         </span>
       </div>
-      {{#field-error error=errors.actionModel.script}}{{/field-error}}
+        {{field-error model=this field='actionModel.script' showErrorMessage=showErrorMessage}}
       </div>
     </div>
     {{#jobxml-config jobXml=actionModel.jobXml openFileBrowser="openFileBrowser" register="register"}}{{/jobxml-config}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/prepare-config-fs.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/prepare-config-fs.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/prepare-config-fs.hbs
index 9d712bf..c549a26 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/prepare-config-fs.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/prepare-config-fs.hbs
@@ -36,51 +36,7 @@
           <input class="form-control btn btn-danger" type="button" {{action "deletePrepare" index}} value="-">
         </div>
       </div>
-      {{#if (eq prep.type "mkdir")}}
-      <div class="form-group bottom-margin-zero">
-        <label class="control-label col-xs-2">Path</label>
-        <div class="col-xs-7">
-          <div class="input-group">
-            {{input type="text" class="form-control" value=prep.settings.path placeholder="path of the directory"}}
-            <span class="input-group-btn">
-              <button class="btn btn-primary" type="button" {{action "openFileBrowserForListItem" index "path"}}>Browse</button>
-            </span>
-          </div>
-        </div>
-      </div>
-      {{#unless prep.settings.path}}
-      <div class="form-group bottom-margin-zero">
-        <label class="text-danger control-label col-xs-2">
-        </label>
-        <label class="text-danger control-label col-xs-4 rightAlign">
-          Path is mandatory
-        </label>
-      </div>
-      {{/unless}}
-      {{/if}}
-      {{#if (eq prep.type "delete")}}
-      <div class="form-group bottom-margin-zero">
-        <label class="control-label col-xs-2">Path</label>
-        <div class="col-xs-7">
-          <div class="input-group">
-            {{input type="text" class="form-control" value=prep.settings.path placeholder="path of the directory"}}
-            <span class="input-group-btn">
-              <button class="btn btn-primary" type="button" {{action "openFileBrowserForListItem" index "path"}}>Browse</button>
-            </span>
-          </div>
-        </div>
-      </div>
-      {{#unless prep.settings.path}}
-      <div class="form-group bottom-margin-zero">
-        <label class="text-danger control-label col-xs-2">
-        </label>
-        <label class="text-danger control-label col-xs-4 rightAlign">
-          Path is mandatory
-        </label>
-      </div>
-      {{/unless}}
-      {{/if}}
-      {{#if (eq prep.type "touchz")}}
+      {{#if (or (eq prep.type "delete") (eq prep.type "mkdir") (eq prep.type "touchz"))}}
       <div class="form-group bottom-margin-zero">
         <label class="control-label col-xs-2">Path</label>
         <div class="col-xs-7">

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/prepare-config-info.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/prepare-config-info.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/prepare-config-info.hbs
new file mode 100644
index 0000000..866e6b9
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/prepare-config-info.hbs
@@ -0,0 +1,22 @@
+{{!
+* 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.
+}}
+{{#each action.prepare as |obj|}}
+	<ul class="list-unstyled">
+	  <li>Type : {{obj.type}}, Path : {{obj.path}}</li>
+	</ul>	
+{{/each}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/preview-dialog.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/preview-dialog.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/preview-dialog.hbs
new file mode 100644
index 0000000..943c917
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/preview-dialog.hbs
@@ -0,0 +1,33 @@
+{{!
+* 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.
+}}
+<div id="previewModal" class="modal fade" role="dialog">
+  <div class="modal-dialog">
+    <div class="modal-content">
+      <div class="modal-header">
+        <button type="button" class="close" data-dismiss="modal">&times;</button>
+        <h4 class="modal-title">{{title}}</h4>
+      </div>
+      <div class="modal-body">
+        <pre class="preview-xml">{{previewXml}}</pre>
+      </div>
+      <div class="modal-footer">
+        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+      </div>
+    </div>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/property-value-config.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/property-value-config.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/property-value-config.hbs
new file mode 100644
index 0000000..1cd5b69
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/property-value-config.hbs
@@ -0,0 +1,22 @@
+{{!
+* 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.
+}}
+{{#each action as |obj|}}
+	<ul class="list-unstyled">
+	  <li>{{obj.value}}</li>
+	</ul>	
+{{/each}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/save-wf.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/save-wf.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/save-wf.hbs
new file mode 100644
index 0000000..65bac42
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/save-wf.hbs
@@ -0,0 +1,79 @@
+{{!
+* 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.
+}}
+<div class="modal fade" id="configureJob" role="dialog">
+  <div class="modal-dialog">
+    <div class="modal-content">
+      <div class="modal-header">
+        <button type="button" class="close" data-dismiss="modal">&times;</button>
+        <h4 class="modal-title">Save Workflow</h4>
+      </div>
+      <div class="modal-body">
+        <div class="panel panel-default">
+          <div class="panel-body">
+            {{#if alertType}}
+            <div id="error" class="alert alert-{{alertType}}">
+              <div>{{alertMessage}}</div>
+              <div>{{alertDetails}}</div>
+              {{#if isStackTraceAvailable}}
+                {{#if isStackTraceVisible}}
+                  <a href="#" {{action "hideStackTrace"}}>Hide Log</a>
+                  <div id="stackTrace">{{{stackTrace}}}</div>
+                {{/if}}
+                {{#unless isStackTraceVisible}}  
+                  <a href="#" {{action "showStackTrace"}}>Show Log</a>
+                {{/unless}}
+              {{/if}}
+            </div>
+            {{/if}}
+            <div class="row form-group">
+              <div class="col-xs-3"> 
+                <label class="control-label" for="{{type}}-path">{{displayName}} path</label><span class="requiredField">&nbsp;*</span>
+              </div>
+              <div class="col-xs-8">
+                <div class="input-group">
+                  {{input class="form-control" type="text" name="{{type}}-path"  value=filePath}}
+                  <span class="input-group-btn">
+                    <button type="button" class="btn btn-primary" {{action "selectFile"}}>Browse</button>
+                  </span>
+                </div>
+                {{field-error model=this field='filePath' showErrorMessage=showErrorMessage}}
+                {{input type="checkbox" checked=overwritePath}}Overwrite
+                {{#if overwritePath}}
+                  <div class="alert alert-info">
+                     Sending overwrite option will replace the existing file in hdfs file system.
+                  </div>
+                {{/if}}
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="modal-footer">
+        {{#if savingInProgress}}
+        {{spin-spinner lines=10 length=10 width=5 radius=10 }}
+        <span class="pull-left">Saving {{displayName}}</span>
+        {{/if}}
+        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+        <button type="button" class="btn btn-primary" {{action "saveWorkflow"}}>Submit</button>
+      </div>
+    </div>
+  </div>
+</div>
+{{#if showingFileBrowser}}
+{{hdfs-browser closeFileBrowser="closeFileBrowser" selectFileCallback=selectFileCallback filePath=filePath}}
+{{/if}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/shell-action-info.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/shell-action-info.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/shell-action-info.hbs
new file mode 100644
index 0000000..332852c
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/shell-action-info.hbs
@@ -0,0 +1,48 @@
+{{!
+* 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.
+}}
+<div id="notificationWidget" class="">
+    <!--a href="#" class="close " data-dismiss="alert" aria-label="close">&times;</a-->
+	<ul class="list-group">
+	  <li class="list-group-item">{{info-header  hoveredAction=hoveredAction hideNotification="hideNotification"}}</li>
+	  {{#if hoveredAction.nameNode}}<li class="list-group-item"><b>Name Node : </b><br/>{{hoveredAction.nameNode}}</li>{{/if}}
+	  {{#if hoveredAction.jobTracker}}<li class="list-group-item"><b>Resource Manager :</b> <br/>{{hoveredAction.jobTracker}} </li>{{/if}}
+	  {{#if hoveredAction.exec}}<li class="list-group-item"><b>Exec :  </b><br/>{{hoveredAction.exec}}</li>{{/if}}
+	  {{#if hoveredAction.envVar}}<li class="list-group-item"><b>Env Var : </b>
+	    {{#property-value-config action=hoveredAction.envVar}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.captureOutput}}<li class="list-group-item"><b>Capture Output :  </b><br/>{{hoveredAction.captureOutput}}</li>{{/if}}
+	  {{#if hoveredAction.jobXml}}<li class="list-group-item"><b>Job xml : </b>
+	    {{#property-value-config action=hoveredAction.jobXml}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.archives}}<li class="list-group-item"><b>Archives : </b>
+	    {{#property-value-config action=hoveredAction.archives}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.files}}<li class="list-group-item"><b>Files : </b>
+	    {{#property-value-config action=hoveredAction.files}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.args}}<li class="list-group-item"><b>Args : </b>
+	    {{#property-value-config action=hoveredAction.args}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.prepare}}<li class="list-group-item"><b>Prepare : </b>
+	    {{#prepare-config-info action=hoveredAction}}{{/prepare-config-info}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.configuration.property}}<li class="list-group-item"><b>Configuration : </b>
+	    {{#name-value-info action=hoveredAction}}{{/name-value-info}}
+	  </li>{{/if}}
+	</ul>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/shell-action.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/shell-action.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/shell-action.hbs
index 81d2c52..4673c732 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/shell-action.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/shell-action.hbs
@@ -27,7 +27,7 @@
           <button class="btn btn-primary" type="button" {{action "openFileBrowser" "actionModel.exec"}}>Browse</button>
         </span>
       </div>
-      {{#field-error error=errors.actionModel.exec}}{{/field-error}}
+      {{field-error model=this field='actionModel.exec' showErrorMessage=showErrorMessage}}
     </div>
   </div>
 
@@ -63,7 +63,7 @@
             <div class="col-xs-7">
               {{input type="text" class="form-control" name="job-tracker" value=actionModel.jobTracker placeholder="Resource Manager"}}
             </div>
-            {{field-error error=errors.actionModel.jobTracker}}
+            {{field-error model=this field='actionModel.jobTracker' showErrorMessage=showErrorMessage}}
           </div>
           <div class="form-group">
             <label for="inputPassword" class="control-label col-xs-2">Name node</label>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/sla-info.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/sla-info.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/sla-info.hbs
index e304f80..28bdf15 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/sla-info.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/sla-info.hbs
@@ -16,11 +16,11 @@
 * limitations under the License.
 }}
 <div class="panel panel-default">
-  <div class="panel-heading" id="sla-accordion" data-toggle="collapse" data-parent="#sla-accordion" data-target="#slaCollapse">
+  <div class="panel-heading" id="sla-accordion" data-toggle="collapse" data-parent="#sla-accordion" data-target="#{{collapseId}}">
       SLA <span class="grayed">({{if slaEnabled "Enabled" "Disabled"}})</span>
       <i class="indicator glyphicon glyphicon-chevron-down pull-right"></i>
     </div>
-    <div id="slaCollapse" class="panel-collapse collapse panel-body">
+    <div id="{{collapseId}}" class="panel-collapse collapse panel-body">
       <div class="form-group">
       <label class="control-label col-xs-2">Enabled</label>
       <span class="col-xs-2 paddingtop7">{{input type="checkbox" checked=slaEnabled}}</span>
@@ -28,14 +28,15 @@
       <div class="form-group">
         <label class="control-label col-xs-2 padding10">Nominal Time<span class="requiredField">&nbsp;*</span></label>
         <div class="col-xs-3 padding10">
-          {{input type="text" id="nominalTime" title="Date in UTC Format" class="form-control" value=nominalTime placeholder="Nominal Time"}}
+          {{input type="text" name="nominalTime" title="Date in UTC Format" class="form-control" value=nominalTime placeholder="Nominal Time"}}
+          {{field-error model=this field='nominalTime' showErrorMessage=showErrorMessage}}
         </div>
-        {{field-error error=errors.nominalTime}}
       </div>
       <div class="form-group">
         <label class="control-label col-xs-2">Should Start</label>
         <div class="col-xs-3">
           {{input class="form-control" type="text" value=slaInfo.shouldStart.time placeholder="Should Start"}}
+          {{field-error model=this field='slaInfo.shouldStart.time' showErrorMessage=showErrorMessage}}
         </div>
         <div class="col-xs-2">
           <select class="form-control" name="time-unit" title="Time Unit" onchange={{action (mut slaInfo.shouldStart.unit) value="target.value"}}>
@@ -43,14 +44,14 @@
               <option value={{timeUnit.value}} selected={{eq timeUnit.value slaInfo.shouldStart.unit}}>{{timeUnit.displayName}}</option>
             {{/each}}
           </select>
-          {{field-error error=errors.shouldStart.unit}}
+          {{field-error model=this field='slaInfo.shouldStart.unit' showErrorMessage=showErrorMessage}}
         </div>
       </div>
       <div class="form-group">
         <label class="control-label col-xs-2">Should End<span class="requiredField">&nbsp;*</span></label>
         <div class="col-xs-3">
           {{input class="form-control" type="text" value=slaInfo.shouldEnd.time placeholder="Should End"}}
-          {{field-error error=errors.shouldEnd.time}}
+          {{field-error model=this field='slaInfo.shouldEnd.time' showErrorMessage=showErrorMessage}}
         </div>
         <div class="col-xs-2">
           <select class="form-control" name="time-unit" title="Time Unit" onchange={{action (mut slaInfo.shouldEnd.unit) value="target.value"}}>
@@ -58,7 +59,7 @@
               <option value={{timeUnit.value}} selected={{eq timeUnit.value slaInfo.shouldEnd.unit}}>{{timeUnit.displayName}}</option>
             {{/each}}
           </select>
-          {{field-error error=errors.shouldEnd.unit}}
+          {{field-error model=this field='slaInfo.shouldEnd.unit' showErrorMessage=showErrorMessage}}
         </div>
       </div>
       <div class="form-group">
@@ -72,7 +73,7 @@
               <option value={{timeUnit.value}} selected={{eq timeUnit.value slaInfo.maxDuration.unit}}>{{timeUnit.displayName}}</option>
             {{/each}}
           </select>
-          {{field-error error=errors.maxDuration.unit}}
+          {{field-error model=this field='slaInfo.maxDuration.unit' showErrorMessage=showErrorMessage}}
         </div>
       </div>
       <div class="form-group">

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/spark-action-info.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/spark-action-info.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/spark-action-info.hbs
new file mode 100644
index 0000000..1b4274f
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/spark-action-info.hbs
@@ -0,0 +1,46 @@
+{{!
+* 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.
+}}
+<div id="notificationWidget" class="">
+    <!--a href="#" class="close " data-dismiss="alert" aria-label="close">&times;</a-->
+	<ul class="list-group">
+	  <li class="list-group-item">{{info-header  hoveredAction=hoveredAction hideNotification="hideNotification"}}</li>
+	  {{#if hoveredAction.nameNode}}<li class="list-group-item"><b>Name Node : </b><br/>{{hoveredAction.nameNode}}</li>{{/if}}
+	  {{#if hoveredAction.jobTracker}}<li class="list-group-item"><b>Resource Manager : </b><br/>{{hoveredAction.jobTracker}} </li>{{/if}}
+	  {{#if hoveredAction.class}}<li class="list-group-item"><b>Class : </b><br/>{{hoveredAction.class}} </li>{{/if}}
+	  {{#if hoveredAction.jar}}<li class="list-group-item"><b>Jar : </b><br/>{{hoveredAction.jar}} </li>{{/if}}
+	  {{#if hoveredAction.master}}<li class="list-group-item"><b>Master : </b><br/>{{hoveredAction.master}} </li>{{/if}}
+	  {{#if hoveredAction.args}}<li class="list-group-item"><b>Args : </b>
+	    {{#property-value-config action=hoveredAction.args}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.jobXml}}<li class="list-group-item"><b>Job xml : </b>
+	    {{#property-value-config action=hoveredAction.jobXml}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.archives}}<li class="list-group-item"><b>Archives : </b>
+	    {{#property-value-config action=hoveredAction.archives}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.files}}<li class="list-group-item"><b>Files : </b>
+	    {{#property-value-config action=hoveredAction.files}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.prepare}}<li class="list-group-item"><b>Prepare : </b>
+	    {{#prepare-config-info action=hoveredAction}}{{/prepare-config-info}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.configuration.property}}<li class="list-group-item"><b>Configuration : </b>
+	    {{#name-value-info action=hoveredAction}}{{/name-value-info}}
+	  </li>{{/if}}
+	</ul>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/spark-action.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/spark-action.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/spark-action.hbs
index 7472995..52bdad5 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/spark-action.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/spark-action.hbs
@@ -22,7 +22,7 @@
       <label for="inputPassword" class="control-label col-xs-2">Name<span class="requiredField">&nbsp;*</span></label>
       <div class="col-xs-7">
         {{input type="text" class="form-control" name="spark-name" value=actionModel.sparkName placeholder="Spark Name"}}
-        {{#field-error error=errors.actionModel.sparkName}}{{/field-error}}
+        {{field-error model=this field='actionModel.sparkName' showErrorMessage=showErrorMessage}}
       </div>
     </div>
     <div class="form-group">
@@ -35,7 +35,7 @@
             <button class="btn btn-primary" type="button" {{action "openFileBrowser" "actionModel.jar"}}>Browse</button>
           </span>
         </div>
-        {{#field-error error=errors.actionModel.jar}}{{/field-error}}
+        {{field-error model=this field='actionModel.jar' showErrorMessage=showErrorMessage}}
       </div>
     </div>
     {{#if isJar}}
@@ -63,7 +63,7 @@
           <input type=text placeholder="Custom" disabled={{disableCustomMaster}} value={{customMaster}} onchange={{action (mut actionModel.master) value="target.value"}}>
         </div>
       </div>
-      {{#field-error error=errors.actionModel.master}}{{/field-error}}
+      {{field-error model=this field='actionModel.master' showErrorMessage=showErrorMessage}}
     </div>
     <div class="form-group">
       <label for="inputEmail" class="control-label col-xs-2">Spark Options</label>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/sqoop-action-info.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/sqoop-action-info.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/sqoop-action-info.hbs
new file mode 100644
index 0000000..eb4c31c
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/sqoop-action-info.hbs
@@ -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.
+}}
+<div id="notificationWidget" class="">
+    <!--a href="#" class="close " data-dismiss="alert" aria-label="close">&times;</a-->
+	<ul class="list-group">
+	  <li class="list-group-item">{{info-header  hoveredAction=hoveredAction hideNotification="hideNotification"}}</li>
+	  {{#if hoveredAction.nameNode}}<li class="list-group-item"><b>Name Node : </b><br/>{{hoveredAction.nameNode}}</li>{{/if}}
+	  {{#if hoveredAction.jobTracker}}<li class="list-group-item"><b>Resource Manager :</b> <br/>{{hoveredAction.jobTracker}} </li>{{/if}}
+	  {{#if hoveredAction.command}}<li class="list-group-item"><b>Command :  </b><br/>{{hoveredAction.command}}</li>{{/if}}
+	  {{#if hoveredAction.jobXml}}<li class="list-group-item"><b>Job xml : </b>
+	    {{#property-value-config action=hoveredAction.jobXml}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.archives}}<li class="list-group-item"><b>Archives : </b>
+	    {{#property-value-config action=hoveredAction.archives}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.files}}<li class="list-group-item"><b>Files : </b>
+	    {{#property-value-config action=hoveredAction.files}}{{/property-value-config}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.prepare}}<li class="list-group-item"><b>Prepare : </b>
+	    {{#prepare-config-info action=hoveredAction}}{{/prepare-config-info}}
+	  </li>{{/if}}
+	  {{#if hoveredAction.configuration.property}}<li class="list-group-item"><b>Configuration : </b>
+	    {{#name-value-info action=hoveredAction}}{{/name-value-info}}
+	  </li>{{/if}}
+	</ul>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/ssh-action-info.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/ssh-action-info.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/ssh-action-info.hbs
new file mode 100644
index 0000000..3e5c363
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/ssh-action-info.hbs
@@ -0,0 +1,32 @@
+{{!
+* 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.
+}}
+<div id="notificationWidget" class="">
+    <!--a href="#" class="close " data-dismiss="alert" aria-label="close">&times;</a-->
+	<ul class="list-group">
+	  <li class="list-group-item">{{info-header  hoveredAction=hoveredAction hideNotification="hideNotification"}}</li>
+	  {{#if hoveredAction.host}}<li class="list-group-item"><b>Host : </b> <br/>{{hoveredAction.host}} </li>{{/if}}
+	  {{#if hoveredAction.host}}<li class="list-group-item"><b>Command :  </b><br/>{{hoveredAction.command}} </li>{{/if}}
+	  {{#if hoveredAction.host}}<li class="list-group-item"><b>Capture Output : </b> <br/>{{hoveredAction.captureOutput}} </li>{{/if}}
+	  {{#if hoveredAction.host}}<li class="list-group-item"><b>Arg : </b> <br/>{{hoveredAction.arg}} </li>{{/if}}
+	  {{#if hoveredAction.host}}<li class="list-group-item"><b>Args :  </b>
+	    {{#property-value-config action=hoveredAction.args}}{{/property-value-config}}
+	  </li>{{/if}}
+	</ul>
+</div>
+
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/ssh-action.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/ssh-action.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/ssh-action.hbs
index 065e270..ab2ebb2 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/ssh-action.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/ssh-action.hbs
@@ -22,14 +22,14 @@
       <label for="inputEmail" class="control-label col-xs-2">Host<span class="requiredField">&nbsp;*</span></label>
       <div class="col-xs-7">
         {{input type="text" class="form-control" name="host" value=actionModel.host placeholder="localhost"}}
-        {{field-error error=errors.actionModel.host}}
+        {{field-error model=this field='actionModel.host' showErrorMessage=showErrorMessage}}
       </div>
     </div>
     <div class="form-group">
       <label for="inputEmail" class="control-label col-xs-2">Command<span class="requiredField">&nbsp;*</span></label>
       <div class="col-xs-7">
         {{input type="text" class="form-control" name="command" value=actionModel.command placeholder="command"}}
-        {{field-error error=errors.actionModel.command}}
+        {{field-error model=this field='actionModel.command' showErrorMessage=showErrorMessage}}
       </div>
     </div>
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/sub-workflow-action-info.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/sub-workflow-action-info.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/sub-workflow-action-info.hbs
new file mode 100644
index 0000000..8b63c23
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/sub-workflow-action-info.hbs
@@ -0,0 +1,29 @@
+{{!
+* 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.
+}}
+<div id="notificationWidget" class="">
+    <!--a href="#" class="close " data-dismiss="alert" aria-label="close">&times;</a-->
+	<ul class="list-group">
+	  <li class="list-group-item"><b>The details are</b>
+	  <a href="#" class="pull-right" {{action "hideNotification"}}>X</a></li>
+	  {{#if hoveredAction.appPath}}<li class="list-group-item"><b>App Path :  </b><br/>{{hoveredAction.appPath}}</li>{{/if}}
+      {{#if hoveredAction.propagate-configuration}}<li class="list-group-item"><b>Propagate Configuration :  </b><br/>{{hoveredAction.propagate-configuration}}</li>{{/if}}
+	  {{#if hoveredAction.configuration.property}}<li class="list-group-item"><b>Configuration : </b>
+	    {{#name-value-info action=hoveredAction}}{{/name-value-info}}
+	  </li>{{/if}}
+	</ul>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/sub-workflow.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/sub-workflow.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/sub-workflow.hbs
index a1ffaba..2841188 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/sub-workflow.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/sub-workflow.hbs
@@ -27,7 +27,7 @@
             <button class="btn btn-primary" type="button" {{action "openFileBrowser" "actionModel.appPath"}}>Browse</button>
           </span>
         </div>
-        {{#field-error error=errors.actionModel.appPath}}{{/field-error}}
+        {{field-error model=this field='actionModel.appPath' showErrorMessage=showErrorMessage}}
       </div>
     </div>
     <div class="form-group">

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/transition-config.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/transition-config.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/transition-config.hbs
index 65902b3..fe46446 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/transition-config.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/transition-config.hbs
@@ -18,7 +18,7 @@
 <div class="form-group">
   <label class="control-label col-xs-2">Error To<span class="requiredField">&nbsp;*</span></label>
   <div class=" col-xs-7">
-    <select onchange={{action "onSelectChange" value="target.value"}} name="select-node" class="form-control" data-show-icon="true">
+    <select onchange={{action "errorToHandler" value="target.value"}} name="select-node" class="form-control" data-show-icon="true">
       <optgroup label="Kill Nodes"></optgroup>
       {{#each killNodes as |node index|}}
       <option value={{node.name}} selected={{eq node.name transition.errorNode.name}}>{{node.name}}</option>
@@ -28,13 +28,24 @@
       <option value={{node.name}} selected={{eq node.name transition.errorNode.name}}>{{node.name}}</option>
       {{/each}}
     </select>
-    {{field-error error=errors.errorNode.name}}
+    {{#if (eq transition.errorNode.type 'kill')}}
+      <span class="kill-message">{{transition.errorNode.killMessage}}</span>
+    {{/if}}
   </div>
 </div>
-<div class="form-group margin0">
-  <label class="control-label col-xs-2">Ok To</label>
-  <div class=" col-xs-7 paddingClass">
-    {{okToNode.name}}
+<div class="form-group">
+  <label class="control-label col-xs-2">Ok To<span class="requiredField">&nbsp;*</span></label>
+  <div class=" col-xs-7">
+    <select onchange={{action "okToHandler" value="target.value"}} name="select-node" class="form-control" data-show-icon="true">
+      {{#each currentNode.validOkToNodes as |node index|}}
+        <option value={{node.name}} selected={{eq node.name transition.okToNode.name}}>{{node.name}}</option>
+      {{/each}}
+    </select>
+    {{#if showWarning}}
+      <span class="ok-to-warning">
+        Changing Ok To transition may result in deletion of intermediate nodes. <span class="undo" {{action 'undoChangeOkTo'}}><u>Undo</u></span>
+      </span>
+    {{/if}}
   </div>
 </div>
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/version-settings.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/version-settings.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/version-settings.hbs
index 337ad7d..145f81b 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/version-settings.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/version-settings.hbs
@@ -25,7 +25,7 @@
       <div class="modal-body">
         <div class="row">
           <div class="form-group">
-            <label class="control-label col-xs-3"> Workflow Verion</label>
+            <label class="control-label col-xs-3"> Workflow Version</label>
             <div class="col-xs-7">
               <select onchange={{action (mut currentWorkflowVersion) value="target.value"}} name="select-version" class="form-control">
                 {{#each workflowSchemaVersions as |version index|}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-actions.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-actions.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-actions.hbs
index 8670161..7c883af 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-actions.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-actions.hbs
@@ -19,6 +19,7 @@
   <span data-toggle="popover" title="Click on an Action to Insert"></span>
   <div id="actions">
     <div class="_actions_popup">
+      <div class="clearfix"></div>
       <h4>Control Flow Nodes</h4>
       <ul class="actions_list_left control_flow">
           <li {{action 'addAction' 'fork'}} data-name="fork" data-type="fork" class="dr_action_fork _fork enabled"> <i class="fa fa-sitemap"></i> Fork </li>
@@ -26,6 +27,10 @@
       </ul>
       <div class="clearfix"></div>
       <h4>Action Nodes</h4>
+      {{#if clipboardHasContents}}
+        <div><span class="paste-action">Paste from clipboard</span><span class="btn paste-action-btn" {{action 'pasteNode'}}><i class="fa fa-paste"></i></span></div>
+      {{/if}}
+      <div class="clearfix"></div>
       <ul class="actions_list_left actionNodes">
           <li {{action 'addAction' 'hive'}} class="dr_action enabled" data-name="Hive" data-type="hive"> <i class="fa fa-server"></i> Hive </li>
           <li {{action 'addAction' 'hive2'}} class="dr_action enabled" data-name="Hive" data-type="hive2"> <i class="fa fa-server"></i> Hive2</li>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-config.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-config.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-config.hbs
index 1593165..d425bd0 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-config.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-config.hbs
@@ -35,7 +35,7 @@
             {{/if}}
             <div class="row form-group">
               <div class="col-xs-3">
-                <label class="control-label" for="Workflow Path">Workflow Path</label><span class="requiredField">&nbsp;*</span>
+                <label class="control-label" for="Workflow Path">Workflow Pathdafxg</label><span class="requiredField">&nbsp;*</span>
               </div>
               <div class="col-xs-8">
                 <div class="input-group">

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-credentials.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-credentials.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-credentials.hbs
index d0a2b43..464221f 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-credentials.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-credentials.hbs
@@ -26,14 +26,36 @@
         <div class=" panel panel-default">
           <div class="panel-heading">Credentials</div>
           <div class="panel-body handlerPanel">
-            {{#each credentialsList as |credential|}}
-              {{#credentials-config showCredentials="showCredentials" delete="deleteCredentials" register="register" credential=credential mode="edit"}}{{/credentials-config}}
-            {{else}}
-              No Credentials
-            {{/each}}
+            <div id="credential-action-bar" class="form-group pull-right">
+              <button id="dataset-create-btn" {{action 'createCredentials'}} type="button" class="btn btn-default">
+                <i class="fa fa-plus-circle"></i> Add
+              </button>
+            </div>
+            <div class="paddingtop10">
+              <ul class="list-group credential-list">
+                {{#each credentialsList as |credential index|}}
+                <li class="list-group-item">
+                  {{credential.name}}<span class="cred-type">({{credential.type}})</span>
+                  <span class="pull-right">
+                    <i class="fa fa-trash-o" title="Delete" {{action "deleteCredentials" index bubbles=false}}></i>
+                  </span>
+                  <span class="pull-right paddingright10">
+                    <i class="fa fa-pencil" title="Edit" {{action "editCredentials" index bubbles=false}}></i>
+                  </span>
+                </li>
+                {{else}}
+                  <span>No Credentials Configured.</span>
+                {{/each}}
+              </ul>
+            </div>
           </div>
         </div>
-        {{#credentials-config showCredentials="showCredentials" add="addCredentials" mode="create"}}{{/credentials-config}}
+        {{#if createMode}}
+          {{#credentials-config credential=currentCredentials showCredentials="showCredentials" add="addCredentials" mode="create" cancel="cancelCreateMode"}}{{/credentials-config}}
+        {{/if}}
+        {{#if editMode}}
+          {{#credentials-config credential=currentCredentials showCredentials="showCredentials" update="updateCredentials" mode="edit" cancel="cancelEditMode"}}{{/credentials-config}}
+        {{/if}}
       </div>
       <div class="modal-footer">
         <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-job-action-info.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-job-action-info.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-job-action-info.hbs
new file mode 100644
index 0000000..8d1e09c
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-job-action-info.hbs
@@ -0,0 +1,80 @@
+{{!
+* 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.
+}}
+
+<div id="actionInfo">
+  <div class="panel panel-default">
+    <div class="panel-body">
+      <div class="col-md-12">
+        <div class="col-md-2">Name</div>
+        <div class="col-md-10">{{actionInfo.name}}</div>
+      </div>
+      <div class="col-md-12">
+        <div class="col-md-2">Type</div>
+        <div class="col-md-10">{{actionInfo.type}}</div>
+      </div>
+      <div class="col-md-12">
+        <div class="col-md-2">Transition</div>
+        <div class="col-md-10">{{actionInfo.transition}}</div>
+      </div>
+      <div class="col-md-12">
+        <div class="col-md-2">Start Time</div>
+        <div class="col-md-10">{{actionInfo.startTime}}</div>
+      </div>
+      <div class="col-md-12">
+        <div class="col-md-2">End Time</div>
+        <div class="col-md-10">{{actionInfo.endTime}}</div>
+      </div>
+      <div class="col-md-12">
+        <div class="col-md-2">Status</div>
+        <div class="col-md-10">{{actionInfo.status}}</div>
+      </div>
+      <div class="col-md-12">
+        <div class="col-md-2">Error Code</div>
+        <div class="col-md-10">{{actionInfo.errorCode}}</div>
+      </div>
+      <div class="col-md-12">
+        <div class="col-md-2">Error Message</div>
+        <div class="col-md-10">{{actionInfo.errorMessage}}</div>
+      </div>
+      <div class="col-md-12">
+        <div class="col-md-2">External ID</div>
+        <div class="col-md-10">{{actionInfo.externalId}}</div>
+      </div>
+      <div class="col-md-12">
+        <div class="col-md-2">External Status</div>
+        <div class="col-md-10">{{actionInfo.externalStatus}}</div>
+      </div>
+      <div class="col-md-12">
+        <div class="col-md-2">Console URL</div>
+        {{#unless (eq "-" actionInfo.consoleUrl)}}
+        <div class="col-md-10"><a target="_blank" href="{{actionInfo.consoleUrl}}">{{actionInfo.consoleUrl}}</a></div>
+        {{else}}
+        <div class="col-md-10">{{actionInfo.consoleUrl}}</div>
+        {{/unless}}
+      </div>
+      <div class="col-md-12">
+        <div class="col-md-2">Tracker URI</div>
+        {{#unless (eq "-" actionInfo.trackerUri)}}
+        <div class="col-md-10"><a target="_blank" href="{{actionInfo.trackerUri}}">{{actionInfo.trackerUri}}</a></div>
+        {{else}}
+        <div class="col-md-10">{{actionInfo.trackerUri}}</div>
+        {{/unless}}
+      </div>
+    </div>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-job-details.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-job-details.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-job-details.hbs
index 6465ca8..5b33c41 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-job-details.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-job-details.hbs
@@ -106,67 +106,11 @@
             <li role="presentation"><a href="#actionConf" aria-controls="action-conf" role="tab" data-toggle="tab">Configuration</a></li>
           </ul>
           <div class="tab-content">
-            <div role="tabpanel" class="tab-pane active" id="actionInfo">
-              <div class="panel panel-default">
-                <div class="panel-body">
-                  <div class="col-md-12">
-                    <div class="col-md-2">Name</div>
-                    <div class="col-md-10">{{model.actionDetails.name}}</div>
-                  </div>
-                  <div class="col-md-12">
-                    <div class="col-md-2">Type</div>
-                    <div class="col-md-10">{{model.actionDetails.type}}</div>
-                  </div>
-                  <div class="col-md-12">
-                    <div class="col-md-2">Transition</div>
-                    <div class="col-md-10">{{model.actionDetails.transition}}</div>
-                  </div>
-                  <div class="col-md-12">
-                    <div class="col-md-2">Start Time</div>
-                    <div class="col-md-10">{{model.actionDetails.startTime}}</div>
-                  </div>
-                  <div class="col-md-12">
-                    <div class="col-md-2">End Time</div>
-                    <div class="col-md-10">{{model.actionDetails.endTime}}</div>
-                  </div>
-                  <div class="col-md-12">
-                    <div class="col-md-2">Status</div>
-                    <div class="col-md-10">{{model.actionDetails.status}}</div>
-                  </div>
-                  <div class="col-md-12">
-                    <div class="col-md-2">Error Code</div>
-                    <div class="col-md-10">{{model.actionDetails.errorCode}}</div>
-                  </div>
-                  <div class="col-md-12">
-                    <div class="col-md-2">Error Message</div>
-                    <div class="col-md-10">{{model.actionDetails.errorMessage}}</div>
-                  </div>
-                  <div class="col-md-12">
-                    <div class="col-md-2">External ID</div>
-                    <div class="col-md-10">{{model.actionDetails.externalId}}</div>
-                  </div>
-                  <div class="col-md-12">
-                    <div class="col-md-2">External Status</div>
-                    <div class="col-md-10">{{model.actionDetails.externalStatus}}</div>
-                  </div>
-                  <div class="col-md-12">
-                    <div class="col-md-2">Console URL</div>
-                    {{#unless (eq "-" model.actionDetails.consoleUrl)}}
-                    <div class="col-md-10"><a target="_blank" href="{{model.actionDetails.consoleUrl}}">{{model.actionDetails.consoleUrl}}</a></div>
-                    {{else}}
-                    <div class="col-md-10">{{model.actionDetails.consoleUrl}}</div>
-                    {{/unless}}
-                  </div>
-                  <div class="col-md-12">
-                    <div class="col-md-2">Tracker URI</div>
-                    {{#unless (eq "-" model.actionDetails.trackerUri)}}
-                    <div class="col-md-10"><a target="_blank" href="{{model.actionDetails.trackerUri}}">{{model.actionDetails.trackerUri}}</a></div>
-                    {{else}}
-                    <div class="col-md-10">{{model.actionDetails.trackerUri}}</div>
-                    {{/unless}}
-                  </div>
-                </div>
-              </div>
+            <div role="tabpanel" class="tab-pane active">
+              {{#if model.actionDetails}}
+              {{#workflow-job-action-info actionInfo=model.actionDetails}}
+              {{/workflow-job-action-info}}
+              {{/if}}
             </div>
             <div role="tabpanel" class="tab-pane" id="actionConf">
               <div class="panel panel-default">
@@ -191,7 +135,22 @@
   <div role="tabpanel" class="tab-pane" id="jobConfig">
     <div class="panel panel-default">
       <div class="panel-body preview">
-        <pre class="prettyprint">{{model.conf}}</pre>
+        <table class="table table-striped configuration-property-table">
+          <thead>
+            <tr>
+              <th class="propertyName">Name</th>
+              <th class="propertyValue">Value</th>
+            </tr>
+          </thead>
+          <tbody>
+            {{#each model.configurationProperties as |configurationProperty|}}
+              <tr>
+                <td class="propertyName">{{configurationProperty.name}}</td>
+                <td class="propertyValue">{{configurationProperty.value}}</td>
+              </tr>
+            {{/each}}
+          </tbody>
+        </table>
       </div>
     </div>
   </div>
@@ -203,11 +162,11 @@
     <div class="panel panel-default">
       <div class="panel-body preview">
         {{#if model.errorLog}}
-          <pre>{{model.errorLog}}</pre>
+        <pre>{{model.errorLog}}</pre>
         {{else if model.error}}
-          <pre>{{model.errorLog}}</pre>
+        <pre>{{model.errorLog}}</pre>
         {{else}}
-          {{spin-spinner lines=8 length=5 width=3 radius=5 top=220}}
+        {{spin-spinner lines=8 length=5 width=3 radius=5 top=220}}
         {{/if}}
       </div>
     </div>
@@ -216,11 +175,11 @@
     <div class="panel panel-default">
       <div class="panel-body preview">
         {{#if model.auditLog}}
-          <pre>{{model.auditLog}}</pre>
+        <pre>{{model.auditLog}}</pre>
         {{else if model.error}}
-          <pre>{{model.auditLog}}</pre>
+        <pre>{{model.auditLog}}</pre>
         {{else}}
-          {{spin-spinner lines=8 length=5 width=3 radius=5 top=220}}
+        {{spin-spinner lines=8 length=5 width=3 radius=5 top=220}}
         {{/if}}
       </div>
     </div>
@@ -228,7 +187,68 @@
   <div role="tabpanel" class="tab-pane" id="jobDag">
     <div class="panel panel-default">
       <div class="panel-body">
-        <img src={{dagUrl}} />
+        <!-- <img src={{dagUrl}} /> -->
+        <div class="row">
+          <div class="col-xs-8">
+            <div id="cy" class="cy-panel"></div>
+          </div>
+          <div class="col-xs-4">
+            {{#if model.nodeName}}
+            <div class="panel panel-default">
+              <div class="panel-body">
+                <div class="row">
+                  <div class="col-md-4 text-bold">Name</div>
+                  <div class="col-md-8">{{model.nodeName}}</div>
+                </div>
+                <div class="row">
+                  <div class="col-md-4 text-bold">Type</div>
+                  <div class="col-md-8">{{model.nodeType}}</div>
+                </div>
+                {{#if model.actionInfo}}
+                <div class="row">
+                  <div class="col-md-4 text-bold">Status</div>
+                  <div class="col-md-8">{{model.actionInfo.status}}</div>
+                </div>
+                <div class="row">
+                  <div class="col-md-4 text-bold">Start Time</div>
+                  <div class="col-md-8">{{model.actionInfo.startTime}}</div>
+                </div>
+                <div class="row">
+                  <div class="col-md-4 text-bold">End Time</div>
+                  <div class="col-md-8">{{model.actionInfo.endTime}}</div>
+                </div>
+                <div class="row pull-right" {{action 'getActionDetails' model.actionInfo}}>
+                  <div class="col-md-12">
+                    <a data-toggle="modal" href="#" data-target="#actionDetailsModal">More</a>
+                  </div>
+                </div>
+                {{else}}
+                <div class="row">
+                  <div class="col-md-4 text-bold">Status</div>
+                  <div class="col-md-8">Not Started</div>
+                </div>
+                {{/if}}
+              </div>
+            </div>
+            {{#if model.actionDetails}}
+            <div class="modal fade" role="dialog" id="actionDetailsModal">
+              <div class="modal-dialog">
+                <div class="modal-content">
+                  <div class="modal-header">
+                    <button type="button" class="close" data-dismiss="modal">&times;</button>
+                    <h4 class="modal-title">Job Action Details</h4>
+                  </div>
+                  <div class="modal-body">
+                    {{#workflow-job-action-info actionInfo=model.actionDetails}}
+                    {{/workflow-job-action-info}}
+                  </div>
+                </div>
+              </div>
+            </div>
+            {{/if}}
+            {{/if}}
+          </div>
+        </div>
       </div>
     </div>
   </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-node.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-node.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-node.hbs
index e80462c..6187b27 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-node.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-node.hbs
@@ -53,9 +53,10 @@
     <div class="node_actions node_left">
       <i class="fa fa-cog node_properties" title="Edit" {{action "openEditor"}}></i>
       <i class="fa fa-trash-o" title="Delete" {{action "deleteNode"}}></i>
+      <i class="fa fa-copy" title="Copy" {{action "copyNode"}}></i>
     </div>
     <div class="action_node_data">
-      <i class="fa fa-{{icon}}"></i>
+      <i class="fa fa-{{icon}}" {{action "showNotification" node  on="mouseEnter"}}></i>
       {{input required pattern="([a-zA-Z_]([\-_a-zA-Z0-9])*){1,39}" name="actionName" data-toggle="tooltip" title=node.name classBinding="node.errors:error:editable" class="editable" value=node.name placeholder="Action Name"}}
     </div>
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-parameters.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-parameters.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-parameters.hbs
index 769db30..b097af2 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-parameters.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-parameters.hbs
@@ -20,24 +20,23 @@
     <div class="modal-content">
       <div class="modal-header">
         <button type="button" class="close" data-dismiss="modal">&times;</button>
-        <h4 class="modal-title">Workflow Parameters</h4>
+        <h4 class="modal-title">{{displayName}} Parameters</h4>
       </div>
       <div class="modal-body">
-
-      <div class=" panel panel-default">
-        <div class="panel-heading">Configuration</div>
-        <div class="panel-body handlerPanel">
-  {{#field-error error=errors.parameters}}{{/field-error}} 
-		  <form class="form-horizontal" id="action_properties">
-          	{{#name-value-config configuration=parameters.configuration register="register"}}{{/name-value-config}}
-          </form>	
+        <div class=" panel panel-default">
+          <div class="panel-heading">Configuration</div>
+          <div class="panel-body handlerPanel">
+            {{field-error model=this field='parameters.configuration.property' showErrorMessage=showErrorMessage}}
+  		      <form class="form-horizontal" id="action_properties">
+            	{{#name-value-config configuration=parameters.configuration validations=validations register="register"}}{{/name-value-config}}
+            </form>
+          </div>
         </div>
       </div>
-      </div>
       <div class="modal-footer">
-        <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
+        <button type="button" class="btn btn-default" data-dismiss="modal" {{action 'close'}}>Cancel</button>
         <button type="button" class="btn btn-primary" {{action "saveParameters"}}>Save</button>
       </div>
     </div>
   </div>
-</div>
\ No newline at end of file
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/dashboard.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/dashboard.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/dashboard.hbs
index b580720..41a23b1 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/dashboard.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/dashboard.hbs
@@ -24,7 +24,7 @@
     <span class="navbar-brand">Workflow Dashboard</span>
     <div class="navbar-brand" id="create-new-button">
       <button type="button" {{action "launchDesign"}} class="btn btn-default whiteLabel">
-          <i class="fa fa-sitemap"></i> Create Workflow
+          <i class="fa fa-sitemap marginright5"></i>Workflow Designer
       </button>
       {{help-icon}}
     </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/templates/design.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/design.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/design.hbs
index b020c86..cb0462c 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/design.hbs
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/design.hbs
@@ -15,4 +15,4 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 }}
-{{flow-designer xmlAppPath=appPath}}
+{{designer-workspace xmlAppPath=xmlAppPath}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/utils/constants.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/utils/constants.js b/contrib/views/wfmanager/src/main/resources/ui/app/utils/constants.js
index d9ca912..2f7df82 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/app/utils/constants.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/utils/constants.js
@@ -17,6 +17,9 @@
 
 import Ember from 'ember';
 export default Ember.Object.create({
+  Workflow : 'wf',
+  Coordinator : 'coord',
+  Bundle : 'bundle',
   globalSetting:{
     useJoinNodeForDecision:false,
     useAdditionalPlaceholderFlowForDecision:true,
@@ -27,6 +30,9 @@ export default Ember.Object.create({
   showErrorTransitions:false,
   generatedByCdata: "Generated by Worflow Designer",
   rmDefaultValue: "${resourceManager}",
+  defaultNameNodeValue : "${nameNode}",
+  useCytoscape : true,
+  autoRestoreWorkflowEnabled : true,
   actions:{
     hiveAction:{name : "hive",supportsSchema : true, currentVersion:''},
     hive2Action:{name : "hive2",supportsSchema : true, currentVersion:''},
@@ -43,5 +49,40 @@ export default Ember.Object.create({
   },
   sparkMasterList :Ember.A([{value:'yarn-cluster',displayName:'Yarn Cluster'},
                             {value:'yarn-client',displayName:'Yarn Client'},
-                            {value:'local',displayName:'Local'}])
+                            {value:'local',displayName:'Local'}]),
+  timezoneList : Ember.A([
+    {displayName:'UTC',gmtOffset:0, value:'UTC'},
+    {displayName:'(GMT -12:00) Eniwetok, Kwajalein',gmtOffset:12, value:'GMT-12:00'},
+    {displayName:'(GMT -11:00) Midway Island, Samoa',gmtOffset:11, value:'GMT-11:00'},
+    {displayName:'(GMT -10:00) Hawaii',gmtOffset:10, value:'GMT-10:00'},
+    {displayName:'(GMT -9:00) Alaska',gmtOffset:9, value:'GMT-09:00'},
+    {displayName:'(GMT -8:00) Pacific Time (US &amp; Canada)',gmtOffset:8, value:'GMT-08:00'},
+    {displayName:'(GMT -7:00) Mountain Time (US &amp; Canada)',gmtOffset:7, value:'GMT-07:00'},
+    {displayName:'(GMT -6:00) Central Time (US &amp; Canada), Mexico City',gmtOffset:6, value:'GMT-06:00'},
+    {displayName:'(GMT -5:00) Eastern Time (US &amp; Canada), Bogota, Lima',gmtOffset:5, value:'GMT-05:00'},
+    {displayName:'(GMT -4:00) Atlantic Time (Canada), Caracas, La Paz',gmtOffset:4, value:'GMT-04:00'},
+    {displayName:'(GMT -3:30) Newfoundland',gmtOffset:3.5, value:'GMT-03:30'},
+    {displayName:'(GMT -3:00) Brazil, Buenos Aires, Georgetown',gmtOffset:3, value:'GMT-03:00'},
+    {displayName:'(GMT -2:00) Mid-Atlantic',gmtOffset:2, value:'GMT-02:00'},
+    {displayName:'(GMT -1:00 hour) Azores, Cape Verde Islands',gmtOffset:1, value:'GMT-01:00'},
+    {displayName:'(GMT) Western Europe Time, London, Lisbon, Casablanca',gmtOffset:0, value:'GMT+00:00'},
+    {displayName:'(GMT +1:00 hour) Brussels, Copenhagen, Madrid, Paris',gmtOffset:-1, value:'GMT+01:00'},
+    {displayName:'(GMT +2:00) Kaliningrad, South Africa',gmtOffset:-2, value:'GMT+02:00'},
+    {displayName:'(GMT +3:00) Baghdad, Riyadh, Moscow, St. Petersburg',gmtOffset:-3, value:'GMT+03:00'},
+    {displayName:'(GMT +3:30) Tehran',gmtOffset:-3.5, value:'GMT+03:30'},
+    {displayName:'(GMT +4:00) Abu Dhabi, Muscat, Baku, Tbilisi',gmtOffset:-4, value:'GMT+04:00'},
+    {displayName:'(GMT +4:30) Kabul',gmtOffset:-4.5, value:'GMT+04:30'},
+    {displayName:'(GMT +5:00) Ekaterinburg, Islamabad, Karachi, Tashkent',gmtOffset:-5, value:'GMT+05:00'},
+    {displayName:'(GMT +5:30) Bombay, Calcutta, Madras, New Delhi',gmtOffset:-5.5,value:'GMT+05:30'},
+    {displayName:'(GMT +5:45) Kathmandu',gmtOffset:-5.75, value:'GMT+05:45'},
+    {displayName:'(GMT +6:00) Almaty, Dhaka, Colombo',gmtOffset:-6, value:'GMT+06:00'},
+    {displayName:'(GMT +7:00) Bangkok, Hanoi, Jakarta',gmtOffset:-7, value:'GMT+07:00'},
+    {displayName:'(GMT +8:00) Beijing, Perth, Singapore, Hong Kong',gmtOffset:-8, value:'GMT+08:00'},
+    {displayName:'(GMT +9:00) Tokyo, Seoul, Osaka, Sapporo, Yakutsk',gmtOffset:-9, value:'GMT+09:00'},
+    {displayName:'(GMT +9:30) Adelaide, Darwin',gmtOffset:-9.5, value:'GMT+09:30'},
+    {displayName:'(GMT +10:00) Eastern Australia, Guam, Vladivostok',gmtOffset:-10, value:'GMT+10:00'},
+    {displayName:'(GMT +11:00) Magadan, Solomon Islands, New Caledonia',gmtOffset:-11, value:'GMT+11:00'},
+    {displayName:'(GMT +12:00) Auckland, Wellington, Fiji, Kamchatka',gmtOffset:-12, value:'GMT+12:00'}
+  ]),
+  persistWorkInProgressInterval : 30000,
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/validators/decission-node-validator.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/validators/decission-node-validator.js b/contrib/views/wfmanager/src/main/resources/ui/app/validators/decission-node-validator.js
new file mode 100644
index 0000000..4d2c53e
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/validators/decission-node-validator.js
@@ -0,0 +1,58 @@
+/*
+ *    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 BaseValidator from 'ember-cp-validations/validators/base';
+
+const DecissionNodeValidator = BaseValidator.extend({
+  validate(value, options, model, attribute) {
+      var hasDefaultCond = false;
+      value.forEach(function(item){
+        if(item.condition === "default"){
+          hasDefaultCond = true;
+          return;
+        }
+      });
+      if(!hasDefaultCond){
+        return "Decision Should have one default condition";
+      }
+      var hasEmptyCond = false;
+      value.forEach(function(item){
+        if(item.condition === '' || item.condition === undefined || Ember.$.trim(item.condition).length === 0){
+          hasEmptyCond = true;
+          return;
+        }
+      });
+      if(hasEmptyCond){
+        return "Condition cannot be blank";
+      }
+      return true;
+  }
+});
+
+DecissionNodeValidator.reopenClass({
+  /**
+   * Define attribute specific dependent keys for your validator
+   *
+   * @param {String}  attribute   The attribute being evaluated
+   * @param {Unknown} options     Options passed into your validator
+   * @return {Array}
+   */
+  getDependentsFor(/* attribute, options */) {
+    return [];
+  }
+});
+
+export default DecissionNodeValidator;

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/validators/duplicate-data-node-name.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/validators/duplicate-data-node-name.js b/contrib/views/wfmanager/src/main/resources/ui/app/validators/duplicate-data-node-name.js
new file mode 100644
index 0000000..5282544
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/validators/duplicate-data-node-name.js
@@ -0,0 +1,60 @@
+/*
+*    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 BaseValidator from 'ember-cp-validations/validators/base';
+
+const DuplicateDataNodeName = BaseValidator.extend({
+  validate(value, options, model, attribute) {
+    if (model.get('dataNodes')) {
+      var nodeNames = new Map();
+      model.get("validationErrors").clear();
+      model.get('dataNodes').forEach((item)=>{
+        if (item.data.node && item.data.node.name) {
+          Ember.set(item.data.node, "errors", false);
+          if(nodeNames.get(item.data.node.name)){
+            Ember.set(item.data.node, "errors", true);
+            model.get("validationErrors").pushObject({node:item.data,message:"Node name should be unique"});
+          }else{
+            nodeNames.set(item.data.node.name, item.data);
+            Ember.set(item.data.node, "errors", false);
+          }
+        }
+      });
+
+      if(model.get('dataNodes').length !== nodeNames.size){
+        return false;
+      }
+      return true;
+    }
+    return true;
+  }
+});
+
+DuplicateDataNodeName.reopenClass({
+  /**
+   * Define attribute specific dependent keys for your validator
+   *
+   * @param {String}  attribute   The attribute being evaluated
+   * @param {Unknown} options     Options passed into your validator
+   * @return {Array}
+   */
+  getDependentsFor(/* attribute, options */) {
+    return [];
+  }
+});
+
+export default DuplicateDataNodeName;

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/validators/duplicate-flattened-node-name.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/validators/duplicate-flattened-node-name.js b/contrib/views/wfmanager/src/main/resources/ui/app/validators/duplicate-flattened-node-name.js
new file mode 100644
index 0000000..046cb53
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/validators/duplicate-flattened-node-name.js
@@ -0,0 +1,66 @@
+/*
+*    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 BaseValidator from 'ember-cp-validations/validators/base';
+
+const DuplicateFlattenedNodeName = BaseValidator.extend({
+  validate(value, options, model, attribute) {
+    var nodeNames = new Map();
+    model.get("validationErrors").clear();
+    model.get('flattenedNodes').forEach((item)=>{
+      Ember.set(item, "errors", false);
+      if(nodeNames.get(item.name)){
+        Ember.set(item, "errors", true);
+        model.get("validationErrors").pushObject({node:item,message:"Node name should be unique"});
+      }else{
+        nodeNames.set(item.name, item);
+        Ember.set(item, "errors", false);
+      }
+      if(model.get("supportedActionTypes").indexOf(item.actionType) === -1 && item.type === "action"){
+        model.get('validationErrors').pushObject({node : item ,message : item.actionType+" is unsupported"});
+      }
+      var nodeErrors=item.validateCustom();
+      if (nodeErrors.length>0){
+        Ember.set(item, "errors", true);
+        nodeErrors.forEach(function(errMsg){
+          model.get("errors").pushObject({node:item,message:errMsg });
+        });
+      }
+    });
+
+    if(model.get('flattenedNodes').length !== nodeNames.size || (model.get("errors") && model.get("errors").length>0)){
+      return false;
+    }
+    return true;
+  }
+});
+
+DuplicateFlattenedNodeName.reopenClass({
+  /**
+   * Define attribute specific dependent keys for your validator
+   *
+   * @param {String}  attribute   The attribute being evaluated
+   * @param {Unknown} options     Options passed into your validator
+   * @return {Array}
+   */
+  getDependentsFor(/* attribute, options */) {
+    return [];
+  }
+});
+
+export default DuplicateFlattenedNodeName;

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/validators/duplicate-kill-node-name.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/validators/duplicate-kill-node-name.js b/contrib/views/wfmanager/src/main/resources/ui/app/validators/duplicate-kill-node-name.js
new file mode 100644
index 0000000..b8770c2
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/validators/duplicate-kill-node-name.js
@@ -0,0 +1,58 @@
+/*
+*    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 BaseValidator from 'ember-cp-validations/validators/base';
+
+const DuplicateKillNodeName = BaseValidator.extend({
+  validate(value, options, model, attribute) {
+    let killNodes = [], flag;
+    model.get("validationErrors").clear();
+    if(model.get("workflow") && model.get("workflow").killNodes){
+      killNodes = model.get("workflow").killNodes;
+      for(let i=0; i<killNodes.length; i++){
+        for(let j=0; j<killNodes.length; j++){
+          if(killNodes[i].name === killNodes[j].name && i !== j){
+            model.get('validationErrors').pushObject({node : killNodes[j] ,message : "Duplicate killnode"});
+            flag = true;
+            break;
+          }
+        }
+        if(flag){
+          break;
+        }
+      }
+    }
+    if (flag){
+      return false;
+    }
+    return true;
+  }
+});
+
+DuplicateKillNodeName.reopenClass({
+  /**
+   * Define attribute specific dependent keys for your validator
+   *
+   * @param {String}  attribute   The attribute being evaluated
+   * @param {Unknown} options     Options passed into your validator
+   * @return {Array}
+   */
+  getDependentsFor(/* attribute, options */) {
+    return [];
+  }
+});
+
+export default DuplicateKillNodeName;


[02/10] ambari git commit: AMBARI-18691. Improve and Update Workflow designer to support coordinators and bundles. (Belliraj HB via dipayanb)

Posted by db...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/validators/fs-action-validator.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/validators/fs-action-validator.js b/contrib/views/wfmanager/src/main/resources/ui/app/validators/fs-action-validator.js
new file mode 100644
index 0000000..4064379
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/validators/fs-action-validator.js
@@ -0,0 +1,76 @@
+/*
+ *    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 BaseValidator from 'ember-cp-validations/validators/base';
+
+const FsActionValidator = BaseValidator.extend({
+  validate(value, options, model, attribute/**/) {
+    var isValidated = true,
+    msg = "";
+    if (!value.length) {
+      return false;
+    }
+    value.forEach(function(item) {
+      switch (item.type) {
+        case "mkdir":
+        case "delete":
+        case "touchz":
+        if (!item.settings.path) {
+          isValidated = false;
+          msg = "path is mandatory";
+        }
+        break;
+        case "chmod":
+        if (!item.settings.path) {
+          isValidated = false;
+          msg = "path and permissions are mandatory";
+        }
+        break;
+        case "chgrp":
+        if (!item.settings.path || !item.settings.group) {
+          isValidated = false;
+          msg = "path and group are mandatory";
+        }
+        break;
+        case "move":
+        if (!item.settings.source || !item.settings.target) {
+          isValidated = false;
+          msg = "source and target are mandatory";
+        }
+        break;
+      }
+    });
+    if (msg.length) {
+      return false;
+    }
+    return true;
+  }
+});
+
+FsActionValidator.reopenClass({
+  /**
+   * Define attribute specific dependent keys for your validator
+   *
+   * @param {String}  attribute   The attribute being evaluated
+   * @param {Unknown} options     Options passed into your validator
+   * @return {Array}
+   */
+  getDependentsFor(/* attribute, options */) {
+    return [];
+  }
+});
+
+export default FsActionValidator;

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/validators/job-params-validator.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/validators/job-params-validator.js b/contrib/views/wfmanager/src/main/resources/ui/app/validators/job-params-validator.js
new file mode 100644
index 0000000..9940bd7
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/validators/job-params-validator.js
@@ -0,0 +1,54 @@
+/*
+ *    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 BaseValidator from 'ember-cp-validations/validators/base';
+
+const JobParamsValidator = BaseValidator.extend({
+  validate(value, options, model, attribute) {
+    if(!value || value.length === 0){
+      return true;
+    }
+    var missingConfig = false;
+    value.forEach(function(item) {
+      if (item.isRequired && (!item || !item.value || item.value==="")){
+        missingConfig = true;
+        return;
+      }else if(!item.isRequired && (!item || !item.value || item.value==="")){
+        return;
+      }
+    });
+    if(missingConfig){
+      return "You need to fill all the mandatory job properties";
+    }
+    return true;
+
+  }
+});
+
+JobParamsValidator.reopenClass({
+  /**
+   * Define attribute specific dependent keys for your validator
+   *
+   * @param {String}  attribute   The attribute being evaluated
+   * @param {Unknown} options     Options passed into your validator
+   * @return {Array}
+   */
+  getDependentsFor(/* attribute, options */) {
+    return [];
+  }
+});
+
+export default JobParamsValidator;

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/validators/operand-length.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/validators/operand-length.js b/contrib/views/wfmanager/src/main/resources/ui/app/validators/operand-length.js
new file mode 100644
index 0000000..b79596b
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/validators/operand-length.js
@@ -0,0 +1,46 @@
+/*
+*    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 BaseValidator from 'ember-cp-validations/validators/base';
+
+const OperandLength = BaseValidator.extend({
+  validate(value, options, model, attribute) {
+    if (options.min && value && value.length >= options.min) {
+        return true;
+    }else{
+      if(options.message){
+        return options.message;
+      }
+      return "Atleast two inputs are required";
+    }
+  }
+});
+
+OperandLength.reopenClass({
+  /**
+   * Define attribute specific dependent keys for your validator
+   *
+   * @param {String}  attribute   The attribute being evaluated
+   * @param {Unknown} options     Options passed into your validator
+   * @return {Array}
+   */
+  getDependentsFor(/* attribute, options */) {
+    return [];
+  }
+});
+
+export default OperandLength;

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/app/validators/unique-name.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/validators/unique-name.js b/contrib/views/wfmanager/src/main/resources/ui/app/validators/unique-name.js
new file mode 100644
index 0000000..c08dc09
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/app/validators/unique-name.js
@@ -0,0 +1,59 @@
+/*
+*    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 BaseValidator from 'ember-cp-validations/validators/base';
+
+const UniqueName = BaseValidator.extend({
+  validate(value, options, model, attribute) {
+    var nameMap = [], errorMsg = undefined, i = 0;
+    if(value){
+      value.forEach(function(item, index){
+        if(!item.name){
+          errorMsg = "Name cannot be blank";
+          i = index;
+        } else if(nameMap.indexOf(item.name) > -1){
+          i = index;
+          errorMsg = "Name cannot be duplicate";
+        } else{
+          nameMap.push(item.name);
+        }
+      });
+      if(errorMsg){
+        if(i){
+          value.splice(i, 1);
+        }
+        return errorMsg;
+      }
+      return true;
+    }
+  }
+});
+
+UniqueName.reopenClass({
+  /**
+   * Define attribute specific dependent keys for your validator
+   *
+   * @param {String}  attribute   The attribute being evaluated
+   * @param {Unknown} options     Options passed into your validator
+   * @return {Array}
+   */
+  getDependentsFor(/* attribute, options */) {
+    return [];
+  }
+});
+
+export default UniqueName;

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/bower.json
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/bower.json b/contrib/views/wfmanager/src/main/resources/ui/bower.json
index cbab954..0d897f1 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/bower.json
+++ b/contrib/views/wfmanager/src/main/resources/ui/bower.json
@@ -22,6 +22,9 @@
     "abdmob/x2js": "~1.2.0",
     "bootstrap-treeview": "~1.2.0",
     "datatables": "~1.10.11",
-    "vkBeautify": "https://github.com/vkiryukhin/vkBeautify.git"
+    "vkBeautify": "https://github.com/vkiryukhin/vkBeautify.git",
+    "cytoscape": "^2.7.7",
+    "cytoscape-dagre": "^1.3.0",
+    "cytoscape-panzoom": "^2.4.0"
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/ember-cli-build.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/ember-cli-build.js b/contrib/views/wfmanager/src/main/resources/ui/ember-cli-build.js
index 063c332..5f8b81c 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/ember-cli-build.js
+++ b/contrib/views/wfmanager/src/main/resources/ui/ember-cli-build.js
@@ -107,6 +107,16 @@ module.exports = function(defaults) {
 
     //vkBeautify
     app.import('bower_components/vkBeautify/vkbeautify.js')
+	
+	//cytoscape
+	app.import('bower_components/cytoscape/dist/cytoscape.js');
+	
+	//cytoscape-dagre
+	app.import('bower_components/cytoscape-dagre/cytoscape-dagre.js');
+
+	//cytoscape-panzoom
+	app.import('bower_components/cytoscape-panzoom/cytoscape-panzoom.js');
+	app.import('bower_components/cytoscape-panzoom/cytoscape.js-panzoom.css');	
 
     return app.toTree();
 };

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/addon/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/addon/.gitkeep b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/addon/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/app/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/app/.gitkeep b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/app/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/tests/dummy/app/components/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/tests/dummy/app/components/.gitkeep b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/tests/dummy/app/components/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/tests/dummy/app/controllers/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/tests/dummy/app/controllers/.gitkeep b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/tests/dummy/app/controllers/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/tests/dummy/app/helpers/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/tests/dummy/app/helpers/.gitkeep b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/tests/dummy/app/helpers/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/tests/dummy/app/models/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/tests/dummy/app/models/.gitkeep b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/tests/dummy/app/models/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/tests/dummy/app/routes/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/tests/dummy/app/routes/.gitkeep b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/tests/dummy/app/routes/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/tests/dummy/app/templates/components/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/tests/dummy/app/templates/components/.gitkeep b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/tests/dummy/app/templates/components/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/tests/integration/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/tests/integration/.gitkeep b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/tests/integration/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/tests/unit/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/tests/unit/.gitkeep b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/tests/unit/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/vendor/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/vendor/.gitkeep b/contrib/views/wfmanager/src/main/resources/ui/externaladdons/hdfs-directory-viewer/vendor/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/mock-service/mock-server.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/mock-service/mock-server.js b/contrib/views/wfmanager/src/main/resources/ui/mock-service/mock-server.js
new file mode 100644
index 0000000..f8a40ab
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/mock-service/mock-server.js
@@ -0,0 +1,52 @@
+/**
+ * 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.
+ */
+(function () {
+  "use strict";
+
+  var bodyParser = require('body-parser'),
+    express = require('express'),
+    mockData = require('./mockData.js'),
+    server = express(),
+    PORT = process.env.PORT || 11000;
+
+  server.use('/', express.static(__dirname + '/dist'));
+  server.use(bodyParser());
+  server.use(function (req, res, next) {
+    if (req.is('text/*')) {
+      req.text = '';
+      req.setEncoding('utf8');
+      req.on('data', function (chunk) { req.text += chunk; });
+      req.on('end', next);
+    } else {
+      next();
+    }
+  });
+
+  server.get('/oozie/v2/jobs', function(req, res) {
+    res.json(200, mockData.getJobs());
+  });
+  
+   server.get('/oozie/v2/job/:id', function(req, res) {
+    res.json(200, mockData.getJobById());
+  });
+
+  server.listen(PORT, function () {
+    console.log('Dev server listening on port ' + PORT);
+  });
+
+}());

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/mock-service/mockData.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/mock-service/mockData.js b/contrib/views/wfmanager/src/main/resources/ui/mock-service/mockData.js
new file mode 100644
index 0000000..7eb3ebb
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/mock-service/mockData.js
@@ -0,0 +1,316 @@
+/**
+ * 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.
+ */
+(function () {
+  'use strict';
+
+  function getJobs(){
+	return jobs;  
+  };
+  
+  function getJobById(id){
+	 /* jobs.find(function(job){
+		 return job.id == id;
+	  });*/
+	  return jobDetail;
+  }
+ 
+  var jobs = {
+   "total":1127,
+   "workflows":[
+      {
+         "appPath":null,
+         "acl":null,
+         "status":"FAILED",
+         "createdTime":"Mon, 18 Jul 2016 17:18:19 GMT",
+         "conf":null,
+         "lastModTime":"Mon, 18 Jul 2016 17:18:27 GMT",
+         "run":0,
+         "endTime":"Mon, 18 Jul 2016 17:18:27 GMT",
+         "externalId":"0001250-160321130408525-oozie-oozi-W@user-action@0",
+         "appName":"falcon-dr-hive-workflow",
+         "id":"0001251-160321130408525-oozie-oozi-W",
+         "startTime":"Mon, 18 Jul 2016 17:18:19 GMT",
+         "parentId":"0001250-160321130408525-oozie-oozi-W",
+         "toString":"Workflow id[0001251-160321130408525-oozie-oozi-W] status[FAILED]",
+         "group":null,
+         "consoleUrl":"http:\/\/sandbox.hortonworks.com:11000\/oozie?job=0001251-160321130408525-oozie-oozi-W",
+         "user":"root",
+         "actions":[
+
+         ]
+      },
+      {
+         "appPath":null,
+         "acl":null,
+         "status":"KILLED",
+         "createdTime":"Mon, 18 Jul 2016 17:18:06 GMT",
+         "conf":null,
+         "lastModTime":"Tue, 19 Jul 2016 17:18:17 GMT",
+         "run":0,
+         "endTime":"Tue, 19 Jul 2016 17:18:17 GMT",
+         "externalId":"hiveMirror11463038709928\/DEFAULT\/2016-05-19T16:02Z",
+         "appName":"FALCON_PROCESS_DEFAULT_hiveMirror11463038709928",
+         "id":"0001250-160321130408525-oozie-oozi-W",
+         "startTime":"Mon, 18 Jul 2016 17:18:07 GMT",
+         "parentId":"0000735-160321130408525-oozie-oozi-C@2077",
+         "toString":"Workflow id[0001250-160321130408525-oozie-oozi-W] status[KILLED]",
+         "group":null,
+         "consoleUrl":"http:\/\/sandbox.hortonworks.com:11000\/oozie?job=0001250-160321130408525-oozie-oozi-W",
+         "user":"root",
+         "actions":[
+
+         ]
+      },
+      {
+         "appPath":null,
+         "acl":null,
+         "status":"FAILED",
+         "createdTime":"Thu, 19 May 2016 16:01:47 GMT",
+         "conf":null,
+         "lastModTime":"Thu, 19 May 2016 16:01:50 GMT",
+         "run":0,
+         "endTime":"Thu, 19 May 2016 16:01:50 GMT",
+         "externalId":"0001248-160321130408525-oozie-oozi-W@user-action@0",
+         "appName":"falcon-dr-hive-workflow",
+         "id":"0001249-160321130408525-oozie-oozi-W",
+         "startTime":"Thu, 19 May 2016 16:01:47 GMT",
+         "parentId":"0001248-160321130408525-oozie-oozi-W",
+         "toString":"Workflow id[0001249-160321130408525-oozie-oozi-W] status[FAILED]",
+         "group":null,
+         "consoleUrl":"http:\/\/sandbox.hortonworks.com:11000\/oozie?job=0001249-160321130408525-oozie-oozi-W",
+         "user":"root",
+         "actions":[
+
+         ]
+      },
+      {
+         "appPath":null,
+         "acl":null,
+         "status":"KILLED",
+         "createdTime":"Thu, 19 May 2016 16:01:43 GMT",
+         "conf":null,
+         "lastModTime":"Tue, 19 Jul 2016 17:18:16 GMT",
+         "run":0,
+         "endTime":"Tue, 19 Jul 2016 17:18:15 GMT",
+         "externalId":"hiveMirror11463038709928\/DEFAULT\/2016-05-19T15:57Z",
+         "appName":"FALCON_PROCESS_DEFAULT_hiveMirror11463038709928",
+         "id":"0001248-160321130408525-oozie-oozi-W",
+         "startTime":"Thu, 19 May 2016 16:01:43 GMT",
+         "parentId":"0000735-160321130408525-oozie-oozi-C@2076",
+         "toString":"Workflow id[0001248-160321130408525-oozie-oozi-W] status[KILLED]",
+         "group":null,
+         "consoleUrl":"http:\/\/sandbox.hortonworks.com:11000\/oozie?job=0001248-160321130408525-oozie-oozi-W",
+         "user":"root",
+         "actions":[
+
+         ]
+      },
+      {
+         "appPath":null,
+         "acl":null,
+         "status":"FAILED",
+         "createdTime":"Thu, 19 May 2016 15:56:47 GMT",
+         "conf":null,
+         "lastModTime":"Thu, 19 May 2016 15:56:48 GMT",
+         "run":0,
+         "endTime":"Thu, 19 May 2016 15:56:48 GMT",
+         "externalId":"0001246-160321130408525-oozie-oozi-W@user-action@0",
+         "appName":"falcon-dr-hive-workflow",
+         "id":"0001247-160321130408525-oozie-oozi-W",
+         "startTime":"Thu, 19 May 2016 15:56:47 GMT",
+         "parentId":"0001246-160321130408525-oozie-oozi-W",
+         "toString":"Workflow id[0001247-160321130408525-oozie-oozi-W] status[FAILED]",
+         "group":null,
+         "consoleUrl":"http:\/\/sandbox.hortonworks.com:11000\/oozie?job=0001247-160321130408525-oozie-oozi-W",
+         "user":"root",
+         "actions":[
+
+         ]
+      },
+      {
+         "appPath":null,
+         "acl":null,
+         "status":"KILLED",
+         "createdTime":"Thu, 19 May 2016 15:56:45 GMT",
+         "conf":null,
+         "lastModTime":"Tue, 19 Jul 2016 17:18:15 GMT",
+         "run":0,
+         "endTime":"Tue, 19 Jul 2016 17:18:15 GMT",
+         "externalId":"hiveMirror11463038709928\/DEFAULT\/2016-05-19T15:52Z",
+         "appName":"FALCON_PROCESS_DEFAULT_hiveMirror11463038709928",
+         "id":"0001246-160321130408525-oozie-oozi-W",
+         "startTime":"Thu, 19 May 2016 15:56:45 GMT",
+         "parentId":"0000735-160321130408525-oozie-oozi-C@2075",
+         "toString":"Workflow id[0001246-160321130408525-oozie-oozi-W] status[KILLED]",
+         "group":null,
+         "consoleUrl":"http:\/\/sandbox.hortonworks.com:11000\/oozie?job=0001246-160321130408525-oozie-oozi-W",
+         "user":"root",
+         "actions":[
+
+         ]
+      },
+      {
+         "appPath":null,
+         "acl":null,
+         "status":"FAILED",
+         "createdTime":"Thu, 19 May 2016 13:12:02 GMT",
+         "conf":null,
+         "lastModTime":"Thu, 19 May 2016 13:12:03 GMT",
+         "run":0,
+         "endTime":"Thu, 19 May 2016 13:12:03 GMT",
+         "externalId":"0001244-160321130408525-oozie-oozi-W@user-action@0",
+         "appName":"falcon-dr-hive-workflow",
+         "id":"0001245-160321130408525-oozie-oozi-W",
+         "startTime":"Thu, 19 May 2016 13:12:02 GMT",
+         "parentId":"0001244-160321130408525-oozie-oozi-W",
+         "toString":"Workflow id[0001245-160321130408525-oozie-oozi-W] status[FAILED]",
+         "group":null,
+         "consoleUrl":"http:\/\/sandbox.hortonworks.com:11000\/oozie?job=0001245-160321130408525-oozie-oozi-W",
+         "user":"root",
+         "actions":[
+
+         ]
+      },
+      {
+         "appPath":null,
+         "acl":null,
+         "status":"KILLED",
+         "createdTime":"Thu, 19 May 2016 13:12:00 GMT",
+         "conf":null,
+         "lastModTime":"Tue, 19 Jul 2016 17:18:17 GMT",
+         "run":0,
+         "endTime":"Tue, 19 Jul 2016 17:18:17 GMT",
+         "externalId":"hiveMirror11463038709928\/DEFAULT\/2016-05-19T13:12Z",
+         "appName":"FALCON_PROCESS_DEFAULT_hiveMirror11463038709928",
+         "id":"0001244-160321130408525-oozie-oozi-W",
+         "startTime":"Thu, 19 May 2016 13:12:01 GMT",
+         "parentId":"0000735-160321130408525-oozie-oozi-C@2043",
+         "toString":"Workflow id[0001244-160321130408525-oozie-oozi-W] status[KILLED]",
+         "group":null,
+         "consoleUrl":"http:\/\/sandbox.hortonworks.com:11000\/oozie?job=0001244-160321130408525-oozie-oozi-W",
+         "user":"root",
+         "actions":[
+
+         ]
+      },
+      {
+         "appPath":null,
+         "acl":null,
+         "status":"FAILED",
+         "createdTime":"Thu, 19 May 2016 13:07:02 GMT",
+         "conf":null,
+         "lastModTime":"Thu, 19 May 2016 13:07:03 GMT",
+         "run":0,
+         "endTime":"Thu, 19 May 2016 13:07:03 GMT",
+         "externalId":"0001242-160321130408525-oozie-oozi-W@user-action@0",
+         "appName":"falcon-dr-hive-workflow",
+         "id":"0001243-160321130408525-oozie-oozi-W",
+         "startTime":"Thu, 19 May 2016 13:07:02 GMT",
+         "parentId":"0001242-160321130408525-oozie-oozi-W",
+         "toString":"Workflow id[0001243-160321130408525-oozie-oozi-W] status[FAILED]",
+         "group":null,
+         "consoleUrl":"http:\/\/sandbox.hortonworks.com:11000\/oozie?job=0001243-160321130408525-oozie-oozi-W",
+         "user":"root",
+         "actions":[
+
+         ]
+      },
+      {
+         "appPath":null,
+         "acl":null,
+         "status":"KILLED",
+         "createdTime":"Thu, 19 May 2016 13:07:01 GMT",
+         "conf":null,
+         "lastModTime":"Tue, 19 Jul 2016 17:18:16 GMT",
+         "run":0,
+         "endTime":"Tue, 19 Jul 2016 17:18:16 GMT",
+         "externalId":"hiveMirror11463038709928\/DEFAULT\/2016-05-19T13:07Z",
+         "appName":"FALCON_PROCESS_DEFAULT_hiveMirror11463038709928",
+         "id":"0001242-160321130408525-oozie-oozi-W",
+         "startTime":"Thu, 19 May 2016 13:07:01 GMT",
+         "parentId":"0000735-160321130408525-oozie-oozi-C@2042",
+         "toString":"Workflow id[0001242-160321130408525-oozie-oozi-W] status[KILLED]",
+         "group":null,
+         "consoleUrl":"http:\/\/sandbox.hortonworks.com:11000\/oozie?job=0001242-160321130408525-oozie-oozi-W",
+         "user":"root",
+         "actions":[
+
+         ]
+      },
+      {
+         "appPath":null,
+         "acl":null,
+         "status":"FAILED",
+         "createdTime":"Thu, 19 May 2016 13:02:02 GMT",
+         "conf":null,
+         "lastModTime":"Thu, 19 May 2016 13:02:03 GMT",
+         "run":0,
+         "endTime":"Thu, 19 May 2016 13:02:03 GMT",
+         "externalId":"0001240-160321130408525-oozie-oozi-W@user-action@0",
+         "appName":"falcon-dr-hive-workflow",
+         "id":"0001241-160321130408525-oozie-oozi-W",
+         "startTime":"Thu, 19 May 2016 13:02:02 GMT",
+         "parentId":"0001240-160321130408525-oozie-oozi-W",
+         "toString":"Workflow id[0001241-160321130408525-oozie-oozi-W] status[FAILED]",
+         "group":null,
+         "consoleUrl":"http:\/\/sandbox.hortonworks.com:11000\/oozie?job=0001241-160321130408525-oozie-oozi-W",
+         "user":"root",
+         "actions":[
+
+         ]
+      },
+      {
+         "appPath":null,
+         "acl":null,
+         "status":"KILLED",
+         "createdTime":"Thu, 19 May 2016 13:02:00 GMT",
+         "conf":null,
+         "lastModTime":"Tue, 19 Jul 2016 17:18:15 GMT",
+         "run":0,
+         "endTime":"Tue, 19 Jul 2016 17:18:15 GMT",
+         "externalId":"hiveMirror11463038709928\/DEFAULT\/2016-05-19T13:02Z",
+         "appName":"FALCON_PROCESS_DEFAULT_hiveMirror11463038709928",
+         "id":"0001240-160321130408525-oozie-oozi-W",
+         "startTime":"Thu, 19 May 2016 13:02:00 GMT",
+         "parentId":"0000735-160321130408525-oozie-oozi-C@2041",
+         "toString":"Workflow id[0001240-160321130408525-oozie-oozi-W] status[KILLED]",
+         "group":null,
+         "consoleUrl":"http:\/\/sandbox.hortonworks.com:11000\/oozie?job=0001240-160321130408525-oozie-oozi-W",
+         "user":"root",
+         "actions":[
+
+         ]
+      }
+   ],
+   "len":12,
+   "offset":1
+}
+
+
+var jobDetail = {"appPath":"hdfs:\/\/sandbox.hortonworks.com:8020\/tmp\/extensions\/hive-mirroring\/resources\/runtime\/hive-mirroring-workflow.xml","acl":null,"status":"FAILED","createdTime":"Mon, 18 Jul 2016 17:18:19 GMT","conf":"<configuration>\r\n  <property>\r\n    <name>falconInputNames<\/name>\r\n    <value>NONE<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>mapreduce.job.user.name<\/name>\r\n    <value>root<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>distcpMapBandwidth<\/name>\r\n    <value>100<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>falconInPaths<\/name>\r\n    <value>NONE<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>feedNames<\/name>\r\n    <value>NONE<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>falcon.libpath<\/name>\r\n    <value>\/apps\/falcon\/primaryCluster\/working\/lib<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>oozie.wf.application.lib<\/name>\r\n    <value>hdfs:\/\/sandbox.hortonworks.com:8020
 \/apps\/falcon\/primaryCluster\/staging\/falcon\/workflows\/process\/hiveMirror11463038709928\/f8319c1e7fce6107b9facd0f5360b176_1463394572377\/DEFAULT\/lib\/falcon-client-0.9.2.5.0.0-357.jar,hdfs:\/\/sandbox.hortonworks.com:8020\/apps\/falcon\/primaryCluster\/staging\/falcon\/workflows\/process\/hiveMirror11463038709928\/f8319c1e7fce6107b9facd0f5360b176_1463394572377\/DEFAULT\/lib\/falcon-common-0.9.2.5.0.0-357.jar,hdfs:\/\/sandbox.hortonworks.com:8020\/apps\/falcon\/primaryCluster\/staging\/falcon\/workflows\/process\/hiveMirror11463038709928\/f8319c1e7fce6107b9facd0f5360b176_1463394572377\/DEFAULT\/lib\/falcon-distcp-replication-0.9.2.5.0.0-357.jar,hdfs:\/\/sandbox.hortonworks.com:8020\/apps\/falcon\/primaryCluster\/staging\/falcon\/workflows\/process\/hiveMirror11463038709928\/f8319c1e7fce6107b9facd0f5360b176_1463394572377\/DEFAULT\/lib\/falcon-extensions-0.9.2.5.0.0-357.jar,hdfs:\/\/sandbox.hortonworks.com:8020\/apps\/falcon\/primaryCluster\/staging\/falcon\/workflows\/process\/
 hiveMirror11463038709928\/f8319c1e7fce6107b9facd0f5360b176_1463394572377\/DEFAULT\/lib\/falcon-feed-lifecycle-0.9.2.5.0.0-357.jar,hdfs:\/\/sandbox.hortonworks.com:8020\/apps\/falcon\/primaryCluster\/staging\/falcon\/workflows\/process\/hiveMirror11463038709928\/f8319c1e7fce6107b9facd0f5360b176_1463394572377\/DEFAULT\/lib\/falcon-hadoop-dependencies-0.9.2.5.0.0-357.jar,hdfs:\/\/sandbox.hortonworks.com:8020\/apps\/falcon\/primaryCluster\/staging\/falcon\/workflows\/process\/hiveMirror11463038709928\/f8319c1e7fce6107b9facd0f5360b176_1463394572377\/DEFAULT\/lib\/falcon-hive-replication-0.9.2.5.0.0-357.jar,hdfs:\/\/sandbox.hortonworks.com:8020\/apps\/falcon\/primaryCluster\/staging\/falcon\/workflows\/process\/hiveMirror11463038709928\/f8319c1e7fce6107b9facd0f5360b176_1463394572377\/DEFAULT\/lib\/falcon-messaging-0.9.2.5.0.0-357.jar,hdfs:\/\/sandbox.hortonworks.com:8020\/apps\/falcon\/primaryCluster\/staging\/falcon\/workflows\/process\/hiveMirror11463038709928\/f8319c1e7fce6107b9facd0f5
 360b176_1463394572377\/DEFAULT\/lib\/falcon-metrics-0.9.2.5.0.0-357.jar,hdfs:\/\/sandbox.hortonworks.com:8020\/apps\/falcon\/primaryCluster\/staging\/falcon\/workflows\/process\/hiveMirror11463038709928\/f8319c1e7fce6107b9facd0f5360b176_1463394572377\/DEFAULT\/lib\/falcon-oozie-adaptor-0.9.2.5.0.0-357.jar,hdfs:\/\/sandbox.hortonworks.com:8020\/apps\/falcon\/primaryCluster\/staging\/falcon\/workflows\/process\/hiveMirror11463038709928\/f8319c1e7fce6107b9facd0f5360b176_1463394572377\/DEFAULT\/lib\/falcon-prism-0.9.2.5.0.0-357-classes.jar,hdfs:\/\/sandbox.hortonworks.com:8020\/apps\/falcon\/primaryCluster\/staging\/falcon\/workflows\/process\/hiveMirror11463038709928\/f8319c1e7fce6107b9facd0f5360b176_1463394572377\/DEFAULT\/lib\/falcon-rerun-0.9.2.5.0.0-357.jar,hdfs:\/\/sandbox.hortonworks.com:8020\/apps\/falcon\/primaryCluster\/staging\/falcon\/workflows\/process\/hiveMirror11463038709928\/f8319c1e7fce6107b9facd0f5360b176_1463394572377\/DEFAULT\/lib\/falcon-retention-0.9.2.5.0.0-357.j
 ar,hdfs:\/\/sandbox.hortonworks.com:8020\/apps\/falcon\/primaryCluster\/staging\/falcon\/workflows\/process\/hiveMirror11463038709928\/f8319c1e7fce6107b9facd0f5360b176_1463394572377\/DEFAULT\/lib\/falcon-scheduler-0.9.2.5.0.0-357.jar<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>sourceTables<\/name>\r\n    <value>*<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>entityType<\/name>\r\n    <value>PROCESS<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>sourceDatabases<\/name>\r\n    <value>xademo,default<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>feedInstancePaths<\/name>\r\n    <value>NONE<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>oozie.bundle.application.path<\/name>\r\n    <value>hdfs:\/\/sandbox.hortonworks.com:8020\/apps\/falcon\/primaryCluster\/staging\/falcon\/workflows\/process\/hiveMirror11463038709928\/f8319c1e7fce6107b9facd0f5360b176_1463394572377<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>logDir<\/name>\r\n  
   <value>hdfs:\/\/sandbox.hortonworks.com:8020\/apps\/falcon\/primaryCluster\/staging\/falcon\/workflows\/process\/hiveMirror11463038709928\/logs<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>oozie.use.system.libpath<\/name>\r\n    <value>true<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>userJMSNotificationEnabled<\/name>\r\n    <value>true<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>oozie.wf.external.id<\/name>\r\n    <value>0001250-160321130408525-oozie-oozi-W@user-action@0<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>oozie.wf.workflow.notification.url<\/name>\r\n    <value>http:\/\/sandbox.hortonworks.com:11000\/oozie\/callback?id=0001250-160321130408525-oozie-oozi-W@user-action&amp;status=$status<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>datasource<\/name>\r\n    <value>NA<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>brokerUrl<\/name>\r\n    <value>tcp:\/\/localhost:61616<\/value>\r\n  <\/property>\r\n  <proper
 ty>\r\n    <name>sourceCluster<\/name>\r\n    <value>testCluster1<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>distcpMaxMaps<\/name>\r\n    <value>1<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>oozie.wf.subworkflow.classpath.inheritance<\/name>\r\n    <value>true<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>targetNN<\/name>\r\n    <value>hdfs:\/\/sandbox.hortonworks.com:8020<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>brokerTTL<\/name>\r\n    <value>4320<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>userWorkflowName<\/name>\r\n    <value>hive-mirroring-workflow<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>clusterForJobRun<\/name>\r\n    <value>testCluster1<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>srcClusterName<\/name>\r\n    <value>NA<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>userBrokerUrl<\/name>\r\n    <value>tcp:\/\/sandbox.hortonworks.com:61616?daemon=true<\/value>\r\n  <\/property>\r
 \n  <property>\r\n    <name>replicationMaxMaps<\/name>\r\n    <value>5<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>user.name<\/name>\r\n    <value>root<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>oozie.libpath<\/name>\r\n    <value>\/apps\/falcon\/primaryCluster\/staging\/falcon\/workflows\/process\/hiveMirror11463038709928\/f8319c1e7fce6107b9facd0f5360b176_1463394572377\/DEFAULT\/lib<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>oozie.bundle.id<\/name>\r\n    <value>0000734-160321130408525-oozie-oozi-B<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>jobPriority<\/name>\r\n    <value>NORMAL<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>oozie.action.yarn.tag<\/name>\r\n    <value>0000735-160321130408525-oozie-oozi-C@2077@user-action<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>oozie.action.subworkflow.depth<\/name>\r\n    <value>1<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>oozie.wf.application.path<\/name>\r\
 n    <value>hdfs:\/\/sandbox.hortonworks.com:8020\/tmp\/extensions\/hive-mirroring\/resources\/runtime\/hive-mirroring-workflow.xml<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>targetMetastoreUri<\/name>\r\n    <value>thrift:\/\/sandbox.hortonworks.com:9083<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>oozie.coord.application.path<\/name>\r\n    <value>hdfs:\/\/sandbox.hortonworks.com:8020\/apps\/falcon\/primaryCluster\/staging\/falcon\/workflows\/process\/hiveMirror11463038709928\/f8319c1e7fce6107b9facd0f5360b176_1463394572377\/DEFAULT\/coordinator.xml<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>sourceMetastoreUri<\/name>\r\n    <value>thrift:\/\/sandbox.hortonworks.com:9083<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>shouldRecord<\/name>\r\n    <value>false<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>timeStamp<\/name>\r\n    <value>2016-05-19-16-01<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>clusterForJobRunWrite
 EP<\/name>\r\n    <value>hdfs:\/\/sandbox.hortonworks.com:8020<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>ENTITY_PATH<\/name>\r\n    <value>\/apps\/falcon\/primaryCluster\/staging\/falcon\/workflows\/process\/hiveMirror11463038709928\/f8319c1e7fce6107b9facd0f5360b176_1463394572377\/DEFAULT\/coordinator.xml<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>nominalTime<\/name>\r\n    <value>2016-05-19-16-02<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>systemJMSNotificationEnabled<\/name>\r\n    <value>true<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>userWorkflowEngine<\/name>\r\n    <value>oozie<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>oozie.wf.parent.id<\/name>\r\n    <value>0001250-160321130408525-oozie-oozi-W<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>sourceNN<\/name>\r\n    <value>hdfs:\/\/sandbox.hortonworks.com:8020<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>queueName<\/name>\r\n    <value>default
 <\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>falconDataOperation<\/name>\r\n    <value>GENERATE<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>workflowEngineUrl<\/name>\r\n    <value>http:\/\/sandbox.hortonworks.com:11000\/oozie\/<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>brokerImplClass<\/name>\r\n    <value>org.apache.activemq.ActiveMQConnectionFactory<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>userBrokerImplClass<\/name>\r\n    <value>org.apache.activemq.ActiveMQConnectionFactory<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>maxEvents<\/name>\r\n    <value>-1<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>ENTITY_NAME<\/name>\r\n    <value>FALCON_PROCESS_DEFAULT_hiveMirror11463038709928<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>availabilityFlag<\/name>\r\n    <value>NA<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>tdeEncryptionEnabled<\/name>\r\n    <value>false<\/value>\r\n  <\/property>\r\
 n  <property>\r\n    <name>targetCluster<\/name>\r\n    <value>testCluster1<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>entityName<\/name>\r\n    <value>hiveMirror11463038709928<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>falconInputFeeds<\/name>\r\n    <value>NONE<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>userWorkflowVersion<\/name>\r\n    <value>1.0<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>cluster<\/name>\r\n    <value>testCluster1<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>colo.name<\/name>\r\n    <value>testColo<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>nameNode<\/name>\r\n    <value>hdfs:\/\/sandbox.hortonworks.com:8020<\/value>\r\n  <\/property>\r\n  <property>\r\n    <name>jobTracker<\/name>\r\n    <value>sandbox.hortonworks.com:8050<\/value>\r\n  <\/property>\r\n<\/configuration>","lastModTime":"Mon, 18 Jul 2016 17:18:27 GMT","run":0,"endTime":"Mon, 18 Jul 2016 17:18:27 GMT","externalId":"0001250
 -160321130408525-oozie-oozi-W@user-action@0","appName":"falcon-dr-hive-workflow","id":"0001251-160321130408525-oozie-oozi-W","startTime":"Mon, 18 Jul 2016 17:18:19 GMT","parentId":"0001250-160321130408525-oozie-oozi-W","toString":"Workflow id[0001251-160321130408525-oozie-oozi-W] status[FAILED]","group":null,"consoleUrl":"http:\/\/sandbox.hortonworks.com:11000\/oozie?job=0001251-160321130408525-oozie-oozi-W","user":"root","actions":[{"errorMessage":null,"status":"OK","stats":null,"data":null,"transition":"last-event","externalStatus":"OK","cred":"null","conf":"","type":":START:","endTime":"Mon, 18 Jul 2016 17:18:21 GMT","externalId":"-","id":"0001251-160321130408525-oozie-oozi-W@:start:","startTime":"Mon, 18 Jul 2016 17:18:20 GMT","userRetryCount":0,"externalChildIDs":null,"name":":start:","errorCode":null,"trackerUri":"-","retries":0,"userRetryInterval":10,"toString":"Action name[:start:] status[OK]","consoleUrl":"-","userRetryMax":0},{"errorMessage":"variable [sourceHiveServer2Uri
 ] cannot be resolved","status":"FAILED","stats":null,"data":null,"transition":null,"externalStatus":null,"cred":"null","conf":"<java xmlns=\"uri:oozie:workflow:0.3\">\r\n  <job-tracker>${jobTracker}<\/job-tracker>\r\n  <name-node>${nameNode}<\/name-node>\r\n  <configuration>\r\n    <property>\r\n      <!-- hadoop 2 parameter -->\r\n      <name>oozie.launcher.mapreduce.job.user.classpath.first<\/name>\r\n      <value>true<\/value>\r\n    <\/property>\r\n    <property>\r\n      <name>mapred.job.queue.name<\/name>\r\n      <value>${queueName}<\/value>\r\n    <\/property>\r\n    <property>\r\n      <name>oozie.launcher.mapred.job.priority<\/name>\r\n      <value>${jobPriority}<\/value>\r\n    <\/property>\r\n    <property>\r\n      <name>oozie.use.system.libpath<\/name>\r\n      <value>true<\/value>\r\n    <\/property>\r\n    <property>\r\n      <name>oozie.action.sharelib.for.java<\/name>\r\n      <value>distcp,hive,hive2,hcatalog<\/value>\r\n    <\/property>\r\n  <\/configuration>\r\n
   <main-class>org.apache.falcon.hive.HiveDRTool<\/main-class>\r\n  <arg>-Dmapred.job.queue.name=${queueName}<\/arg>\r\n  <arg>-Dmapred.job.priority=${jobPriority}<\/arg>\r\n  <arg>-falconLibPath<\/arg>\r\n  <arg>${wf:conf(\"falcon.libpath\")}<\/arg>\r\n  <arg>-sourceCluster<\/arg>\r\n  <arg>${sourceCluster}<\/arg>\r\n  <arg>-sourceMetastoreUri<\/arg>\r\n  <arg>${sourceMetastoreUri}<\/arg>\r\n  <arg>-sourceHiveServer2Uri<\/arg>\r\n  <arg>${sourceHiveServer2Uri}<\/arg>\r\n  <arg>-sourceDatabase<\/arg>\r\n  <arg>${sourceDatabase}<\/arg>\r\n  <arg>-sourceTable<\/arg>\r\n  <arg>${sourceTable}<\/arg>\r\n  <arg>-sourceStagingPath<\/arg>\r\n  <arg>${sourceStagingPath}<\/arg>\r\n  <arg>-sourceNN<\/arg>\r\n  <arg>${sourceNN}<\/arg>\r\n  <arg>-targetCluster<\/arg>\r\n  <arg>${targetCluster}<\/arg>\r\n  <arg>-targetMetastoreUri<\/arg>\r\n  <arg>${targetMetastoreUri}<\/arg>\r\n  <arg>-targetHiveServer2Uri<\/arg>\r\n  <arg>${targetHiveServer2Uri}<\/arg>\r\n  <arg>-targetStagingPath<\/arg>\r\n  <a
 rg>${targetStagingPath}<\/arg>\r\n  <arg>-targetNN<\/arg>\r\n  <arg>${targetNN}<\/arg>\r\n  <arg>-maxEvents<\/arg>\r\n  <arg>${maxEvents}<\/arg>\r\n  <arg>-clusterForJobRun<\/arg>\r\n  <arg>${clusterForJobRun}<\/arg>\r\n  <arg>-clusterForJobRunWriteEP<\/arg>\r\n  <arg>${clusterForJobRunWriteEP}<\/arg>\r\n  <arg>-tdeEncryptionEnabled<\/arg>\r\n  <arg>${tdeEncryptionEnabled}<\/arg>\r\n  <arg>-jobName<\/arg>\r\n  <arg>${jobName}-${nominalTime}<\/arg>\r\n  <arg>-executionStage<\/arg>\r\n  <arg>lastevents<\/arg>\r\n<\/java>","type":"java","endTime":null,"externalId":null,"id":"0001251-160321130408525-oozie-oozi-W@last-event","startTime":null,"userRetryCount":0,"externalChildIDs":null,"name":"last-event","errorCode":"EL_ERROR","trackerUri":null,"retries":0,"userRetryInterval":10,"toString":"Action name[last-event] status[FAILED]","consoleUrl":null,"userRetryMax":0}]}
+
+ var server = {
+      //"properties":[{key: "authentication", value: "kerberos"}]
+      "properties":[{key: "authentication", value: "simple"}]
+    };
+
+  exports.getJobs = getJobs;
+  exports.getJobById = getJobById;
+  exports.server = server;
+
+})();
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/package.json
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/package.json b/contrib/views/wfmanager/src/main/resources/ui/package.json
index d04d57c..ab9426a 100644
--- a/contrib/views/wfmanager/src/main/resources/ui/package.json
+++ b/contrib/views/wfmanager/src/main/resources/ui/package.json
@@ -29,28 +29,30 @@
     "ember-cli-htmlbars": "^1.0.1",
     "ember-cli-htmlbars-inline-precompile": "^0.3.1",
     "ember-cli-inject-live-reload": "^1.3.1",
+    "ember-cli-less": "^1.5.3",
+    "ember-cli-moment-shim": "2.0.0",
     "ember-cli-qunit": "^1.2.1",
     "ember-cli-release": "0.2.8",
     "ember-cli-sri": "^2.0.0",
     "ember-cli-uglify": "^1.2.0",
+    "ember-cp-validations": "2.9.5",
     "ember-data": "2.7.0",
     "ember-disable-proxy-controllers": "^1.0.1",
     "ember-export-application-global": "^1.0.4",
     "ember-load-initializers": "^0.5.0",
+    "ember-moment": "6.1.0",
     "ember-resolver": "^2.0.3",
     "ember-spin-spinner": "0.2.4",
     "ember-truth-helpers": "1.2.0",
-    "loader.js": "^4.0.0",
-	"ember-uploader": "1.0.0",
-	"ember-validations": "~ 2.0.0-alpha.4"
+    "ember-uploader": "1.0.0",
+    "ember-uuid": "1.0.0",
+    "ember-validations": "~ 2.0.0-alpha.4",
+    "loader.js": "^4.0.0"
   },
   "ember-addon": {
     "paths": [
-      "lib/favicon"
+      "externaladdons/hdfs-directory-viewer"
     ],
-	"name": "files",
-	"paths": [
-	  "externaladdons/hdfs-directory-viewer"
-	]
+    "name": "files"
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/public/assets/favicon.ico
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/public/assets/favicon.ico b/contrib/views/wfmanager/src/main/resources/ui/public/assets/favicon.ico
new file mode 100644
index 0000000..5d95710
Binary files /dev/null and b/contrib/views/wfmanager/src/main/resources/ui/public/assets/favicon.ico differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/public/assets/join.png
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/public/assets/join.png b/contrib/views/wfmanager/src/main/resources/ui/public/assets/join.png
new file mode 100644
index 0000000..3fafaaf
Binary files /dev/null and b/contrib/views/wfmanager/src/main/resources/ui/public/assets/join.png differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/public/assets/logo.png
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/public/assets/logo.png b/contrib/views/wfmanager/src/main/resources/ui/public/assets/logo.png
new file mode 100644
index 0000000..e3b27c4
Binary files /dev/null and b/contrib/views/wfmanager/src/main/resources/ui/public/assets/logo.png differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/public/assets/play.png
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/public/assets/play.png b/contrib/views/wfmanager/src/main/resources/ui/public/assets/play.png
new file mode 100644
index 0000000..d6fa7ba
Binary files /dev/null and b/contrib/views/wfmanager/src/main/resources/ui/public/assets/play.png differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/public/assets/sitemap.png
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/public/assets/sitemap.png b/contrib/views/wfmanager/src/main/resources/ui/public/assets/sitemap.png
new file mode 100644
index 0000000..d0316a4
Binary files /dev/null and b/contrib/views/wfmanager/src/main/resources/ui/public/assets/sitemap.png differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/public/assets/stop.png
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/public/assets/stop.png b/contrib/views/wfmanager/src/main/resources/ui/public/assets/stop.png
new file mode 100644
index 0000000..a9e6336
Binary files /dev/null and b/contrib/views/wfmanager/src/main/resources/ui/public/assets/stop.png differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/public/loader.gif
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/public/loader.gif b/contrib/views/wfmanager/src/main/resources/ui/public/loader.gif
new file mode 100644
index 0000000..71a4cc7
Binary files /dev/null and b/contrib/views/wfmanager/src/main/resources/ui/public/loader.gif differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/public/sampledata/bundle.xml
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/public/sampledata/bundle.xml b/contrib/views/wfmanager/src/main/resources/ui/public/sampledata/bundle.xml
new file mode 100644
index 0000000..c435682
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/public/sampledata/bundle.xml
@@ -0,0 +1,32 @@
+<!--
+  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.
+-->
+<bundle-app name='bundle-app' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='uri:oozie:bundle:0.1'>
+          <coordinator name='coord-1'>
+                 <app-path>${nameNode}/user/${userName}/${examplesRoot}/apps/aggregator/coordinator.xml</app-path>
+                 <configuration>
+                     <property>
+                         <name>start</name>
+                         <value>${start}</value>
+                     </property>
+                     <property>
+                         <name>end</name>
+                         <value>${end}</value>
+                     </property>
+                 </configuration>
+          </coordinator>
+</bundle-app>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/public/sampledata/coordinator.xml
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/public/sampledata/coordinator.xml b/contrib/views/wfmanager/src/main/resources/ui/public/sampledata/coordinator.xml
new file mode 100644
index 0000000..7bb2629
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/public/sampledata/coordinator.xml
@@ -0,0 +1,113 @@
+<!--
+  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.
+-->
+<coordinator-app name="coord-input-logic" frequency="${coord:hours(1)}" start="${start}" end="${end}" timezone="UTC"
+    xmlns="uri:oozie:coordinator:0.5">
+    <controls>
+        <concurrency>1</concurrency>
+    </controls>
+	<parameters>
+		<configuration>
+			<property>
+				<name>ds</name>
+				<value>ewr</value>
+			</property>
+		</configuration>
+	</parameters>
+    <datasets>
+        <dataset name="data-1" frequency="${coord:minutes(20)}" initial-instance="2010-01-01T00:00Z" timezone="UTC">
+            <uri-template>${nameNode}/user/${coord:user()}/${examplesRoot}/input-data/rawLogs/${YEAR}/${MONTH}/${DAY}/${HOUR}/${MINUTE}</uri-template>
+        </dataset>
+        <dataset name="data-2" frequency="${coord:minutes(20)}" initial-instance="2010-01-01T00:00Z" timezone="UTC">
+            <uri-template>${nameNode}/user/${coord:user()}/${examplesRoot}/input-data/rawLogs-2/${YEAR}/${MONTH}/${DAY}/${HOUR}/${MINUTE}</uri-template>
+        </dataset>
+		 <dataset name="data-3" frequency="${coord:minutes(20)}" initial-instance="2010-01-01T00:00Z" timezone="UTC">
+            <uri-template>${nameNode}/user/${coord:user()}/${examplesRoot}/input-data/rawLogs-3/${YEAR}/${MONTH}/${DAY}/${HOUR}/${MINUTE}</uri-template>
+        </dataset>
+		<dataset name="data-4" frequency="${coord:minutes(20)}" initial-instance="2010-01-01T00:00Z" timezone="UTC">
+            <uri-template>${nameNode}/user/${coord:user()}/${examplesRoot}/input-data/rawLogs-4/${YEAR}/${MONTH}/${DAY}/${HOUR}/${MINUTE}</uri-template>
+        </dataset>
+        <dataset name="output" frequency="${coord:hours(1)}" initial-instance="2010-01-01T01:00Z" timezone="UTC">
+            <uri-template>${nameNode}/user/${coord:user()}/${examplesRoot}/output-data/inputLogic/${YEAR}/${MONTH}/${DAY}/${HOUR}</uri-template>
+        </dataset>
+		<dataset name="output-1" frequency="${coord:hours(1)}" initial-instance="2010-01-01T01:00Z" timezone="UTC">
+            <uri-template>${nameNode}/user/${coord:user()}/${examplesRoot}/output-data/inputLogic/${YEAR}/${MONTH}/${DAY}/${HOUR}</uri-template>
+        </dataset>
+    </datasets>
+    <input-events>
+        <data-in name="input-1" dataset="data-1">
+            <start-instance>${coord:current(-2)}</start-instance>
+            <end-instance>${coord:current(0)}</end-instance>
+        </data-in>
+        <data-in name="input-2" dataset="data-2">
+            <start-instance>${coord:current(-2)}</start-instance>
+            <end-instance>${coord:current(0)}</end-instance>
+        </data-in>
+		<data-in name="input-3" dataset="data-4">
+			<instance>2016-08-01T00:00Z</instance>
+			<instance>2016-08-02T00:00Z</instance>
+			<instance>2016-08-03T00:00Z</instance>
+		</data-in>
+    </input-events>
+	<!--input-events>
+		<or name="c1">
+			<data-in name="d1" dataset="data-1"></data-in>
+			<data-in name="d4" dataset="data-4"></data-in>
+			<and name="nc1">
+				<data-in name="d2" dataset="data-2"></data-in>
+				<data-in name="d3" dataset="data-3"></data-in>
+			</and>
+		</or>
+	</input-events-->
+    <input-logic>
+        <or name="input">
+              <data-in dataset="input-1"/>
+              <data-in dataset="input-2"/>
+        </or>
+    </input-logic>
+    <output-events>
+        <data-out name="output" dataset="output">
+            <instance>${coord:current(0)}</instance>
+        </data-out>
+		<data-out name="output-1" dataset="output-1">
+            <instance>${coord:current(0)}</instance>
+        </data-out>
+    </output-events>
+    <action>
+        <workflow>
+            <app-path>${nameNode}/user/${coord:user()}/${examplesRoot}/apps/coord-input-logic</app-path>
+            <configuration>
+                <property>
+                    <name>nameNode</name>
+                    <value>${nameNode}</value>
+                </property>
+                <property>
+                    <name>queueName</name>
+                    <value>${queueName}</value>
+                </property>
+                <property>
+                    <name>outputData</name>
+                    <value>${coord:dataOut('output')}</value>
+                </property>
+                <property>
+                    <name>inputData</name>
+                    <value>${coord:dataIn('input')}</value>
+                </property>
+            </configuration>
+        </workflow>
+    </action>
+</coordinator-app>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/.gitkeep b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/bundle-config-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/bundle-config-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/bundle-config-test.js
new file mode 100644
index 0000000..a3fe9f2
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/bundle-config-test.js
@@ -0,0 +1,40 @@
+/*
+*    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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('bundle-config', 'Integration | Component | bundle config', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{bundle-config}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#bundle-config}}
+      template block text
+    {{/bundle-config}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/bundle-coord-config-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/bundle-coord-config-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/bundle-coord-config-test.js
new file mode 100644
index 0000000..910d0e8
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/bundle-coord-config-test.js
@@ -0,0 +1,40 @@
+/*
+*    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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('bundle-coord-config', 'Integration | Component | bundle coord config', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{bundle-coord-config}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#bundle-coord-config}}
+      template block text
+    {{/bundle-coord-config}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/conditional-data-input-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/conditional-data-input-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/conditional-data-input-test.js
new file mode 100644
index 0000000..baacde2
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/conditional-data-input-test.js
@@ -0,0 +1,40 @@
+/*
+*    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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('conditional-data-input', 'Integration | Component | conditional data input', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{conditional-data-input}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#conditional-data-input}}
+      template block text
+    {{/conditional-data-input}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/confirmation-dialog-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/confirmation-dialog-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/confirmation-dialog-test.js
new file mode 100644
index 0000000..8a366aa
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/confirmation-dialog-test.js
@@ -0,0 +1,40 @@
+/*
+*    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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('confirmation-dialog', 'Integration | Component | confirmation dialog', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{confirmation-dialog}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#confirmation-dialog}}
+      template block text
+    {{/confirmation-dialog}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/coord-config-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/coord-config-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/coord-config-test.js
new file mode 100644
index 0000000..3eaee2b
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/coord-config-test.js
@@ -0,0 +1,40 @@
+/*
+ *    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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('coord-config', 'Integration | Component | coord config', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{coord-config}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#coord-config}}
+      template block text
+    {{/coord-config}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/data-input-output-config-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/data-input-output-config-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/data-input-output-config-test.js
new file mode 100644
index 0000000..86a11f2
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/data-input-output-config-test.js
@@ -0,0 +1,40 @@
+/*
+*    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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('data-input-output-config', 'Integration | Component | data input output config', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{data-input-output-config}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#data-input-output-config}}
+      template block text
+    {{/data-input-output-config}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/data-input-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/data-input-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/data-input-test.js
new file mode 100644
index 0000000..64c63eb
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/data-input-test.js
@@ -0,0 +1,40 @@
+/*
+*    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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('data-input', 'Integration | Component | data input', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{data-input}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#data-input}}
+      template block text
+    {{/data-input}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/dataset-config-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/dataset-config-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/dataset-config-test.js
new file mode 100644
index 0000000..622fae5
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/dataset-config-test.js
@@ -0,0 +1,40 @@
+/*
+*    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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('dataset-config', 'Integration | Component | dataset config', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{dataset-config}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#dataset-config}}
+      template block text
+    {{/dataset-config}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/date-with-expr-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/date-with-expr-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/date-with-expr-test.js
new file mode 100644
index 0000000..31da9c2
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/date-with-expr-test.js
@@ -0,0 +1,40 @@
+/*
+*    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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('date-with-expr', 'Integration | Component | date with expr', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{date-with-expr}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#date-with-expr}}
+      template block text
+    {{/date-with-expr}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/designer-workspace-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/designer-workspace-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/designer-workspace-test.js
new file mode 100644
index 0000000..a133fa1
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/designer-workspace-test.js
@@ -0,0 +1,40 @@
+/*
+*    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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('designer-workspace', 'Integration | Component | designer workspace', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{designer-workspace}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#designer-workspace}}
+      template block text
+    {{/designer-workspace}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/distcp-action-info-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/distcp-action-info-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/distcp-action-info-test.js
new file mode 100644
index 0000000..5165c24
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/distcp-action-info-test.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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('distcp-action-info', 'Integration | Component | distcp action info', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{distcp-action-info}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#distcp-action-info}}
+      template block text
+    {{/distcp-action-info}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7c7412ed/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/email-action-info-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/email-action-info-test.js b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/email-action-info-test.js
new file mode 100644
index 0000000..9b76e58
--- /dev/null
+++ b/contrib/views/wfmanager/src/main/resources/ui/tests/integration/components/email-action-info-test.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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('email-action-info', 'Integration | Component | email action info', {
+  integration: true
+});
+
+test('it renders', function(assert) {
+  // Set any properties with this.set('myProperty', 'value');
+  // Handle any actions with this.on('myAction', function(val) { ... });"
+
+  this.render(hbs`{{email-action-info}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:"
+  this.render(hbs`
+    {{#email-action-info}}
+      template block text
+    {{/email-action-info}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});