ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From atk...@apache.org
Subject [2/2] ambari git commit: AMBARI-22582 Clean up Configs page. (atkach)
Date Mon, 04 Dec 2017 18:31:07 GMT
AMBARI-22582 Clean up Configs page. (atkach)


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

Branch: refs/heads/trunk
Commit: 2e9c964650665028caa6351eebebe5f55e6d28ca
Parents: e77a31a
Author: Andrii Tkach <atkach@apache.org>
Authored: Mon Dec 4 18:41:04 2017 +0200
Committer: Andrii Tkach <atkach@apache.org>
Committed: Mon Dec 4 18:41:04 2017 +0200

----------------------------------------------------------------------
 ambari-web/app/assets/test/tests.js             |   2 +-
 .../controllers/main/service/info/configs.js    |   5 +
 ambari-web/app/messages.js                      |   3 +-
 .../mixins/common/configs/configs_comparator.js |   6 +-
 ambari-web/app/styles/application.less          |  24 +-
 ambari-web/app/styles/bootstrap_overrides.less  |   2 +-
 ambari-web/app/styles/config_history_flow.less  | 414 ----------
 .../app/styles/config_versions_control.less     | 144 ++++
 ambari-web/app/styles/widgets.less              |   7 +-
 .../configs/config_history_dropdown_row.hbs     |  24 -
 .../common/configs/config_history_flow.hbs      | 148 ----
 .../common/configs/config_versions_control.hbs  |  42 ++
 .../common/configs/config_versions_dropdown.hbs |  69 ++
 .../templates/common/configs/service_config.hbs |  97 ++-
 ambari-web/app/views.js                         |   3 +-
 .../views/common/configs/config_history_flow.js | 644 ----------------
 .../configs/config_versions_control_view.js     | 235 ++++++
 .../configs/config_versions_dropdown_view.js    |  52 ++
 .../views/common/configs/service_config_view.js |  66 ++
 .../common/configs/config_history_flow_test.js  | 756 -------------------
 .../config_versions_control_view_test.js        | 152 ++++
 .../common/configs/service_config_view_test.js  |  52 +-
 .../host_progress_popup_body_view_test.js       |   9 +-
 23 files changed, 896 insertions(+), 2060 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/2e9c9646/ambari-web/app/assets/test/tests.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/test/tests.js b/ambari-web/app/assets/test/tests.js
index de81764..990c489 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -372,7 +372,7 @@ var files = [
   'test/views/main/admin/highAvailability/nameNode/wizard_view_test',
   'test/views/main/admin/highAvailability/progress_view_test',
   'test/views/common/host_progress_popup_body_view_test',
-  'test/views/common/configs/config_history_flow_test',
+  'test/views/common/configs/config_versions_control_view_test',
   'test/views/common/configs/overriddenProperty_view_test',
   'test/views/common/configs/service_config_view_test',
   'test/views/common/configs/service_config_container_view_test',

http://git-wip-us.apache.org/repos/asf/ambari/blob/2e9c9646/ambari-web/app/controllers/main/service/info/configs.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/info/configs.js b/ambari-web/app/controllers/main/service/info/configs.js
index 8436086..a3a4206 100644
--- a/ambari-web/app/controllers/main/service/info/configs.js
+++ b/ambari-web/app/controllers/main/service/info/configs.js
@@ -43,6 +43,11 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.AddSecurityConfi
 
   selectedConfigGroup: null,
 
+  /**
+   * currently displayed service config version
+   */
+  displayedVersion: null,
+
   groupsStore: App.ServiceConfigGroup.find(),
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/2e9c9646/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index 06deecb..8b6ce72 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -360,6 +360,7 @@ Em.I18n.translations = {
   'common.express.downgrade': 'Express Downgrade',
   'common.views': 'Views',
   'common.critical.error': 'Critical',
+  'common.with': 'with',
 
   'models.alert_instance.tiggered.verbose': "Occurred on {0} <br> Checked on {1}",
   'models.alert_definition.triggered.verbose': "Occurred on {0}",
@@ -2260,7 +2261,7 @@ Em.I18n.translations = {
   'services.service.config.configHistory.leftArrow.tooltip': 'Show later versions',
   'services.service.config.configHistory.dismissIcon.tooltip': 'Dismiss',
   'services.service.config.configHistory.makeCurrent.message': 'Created from service config version {0}',
-  'services.service.config.configHistory.comparing': 'Comparing',
+  'services.service.config.configHistory.comparing': 'Comparing Changes',
   'services.service.config.setRecommendedValue': 'Set Recommended',
   'services.service.config.database.msg.jdbcSetup.detailed': 'To use {0} with Hive, you must <a href="{3}" target="_blank">' +
     'download the {4} from {0}</a>. Once downloaded to the Ambari Server host, run: <br/>' +

http://git-wip-us.apache.org/repos/asf/ambari/blob/2e9c9646/ambari-web/app/mixins/common/configs/configs_comparator.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/configs/configs_comparator.js b/ambari-web/app/mixins/common/configs/configs_comparator.js
index 748e77e..45cd106 100644
--- a/ambari-web/app/mixins/common/configs/configs_comparator.js
+++ b/ambari-web/app/mixins/common/configs/configs_comparator.js
@@ -46,13 +46,11 @@ App.ConfigsComparator = Em.Mixin.create({
       } else {
         compareServiceVersions = [this.get('compareServiceVersion').get('version')];
       }
+      this.set('isCompareMode', true);
       this.getCompareVersionConfigs(compareServiceVersions).done(function (json) {
         allConfigs.setEach('isEditable', false);
         self.initCompareConfig(allConfigs, json);
-        self.setProperties({
-          compareServiceVersion: null,
-          isCompareMode: true
-        });
+        self.set('compareServiceVersion', null);
         dfd.resolve(true);
       }).fail(function () {
         self.set('compareServiceVersion', null);

http://git-wip-us.apache.org/repos/asf/ambari/blob/2e9c9646/ambari-web/app/styles/application.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less
index 2a908b3..7629355 100644
--- a/ambari-web/app/styles/application.less
+++ b/ambari-web/app/styles/application.less
@@ -602,6 +602,8 @@ h1 {
 }
 
 #serviceConfig {
+  background: white;
+  padding: 15px;
 
   .alert{
     .glyphicon-refresh{
@@ -1768,7 +1770,7 @@ ul.inline li {
 }
 
 .full-width {
-  width: 100%
+  width: 100% !important;
 }
 
 .rack-id {
@@ -2564,26 +2566,6 @@ input[type="radio"].align-checkbox, input[type="checkbox"].align-checkbox {
   }
 }
 
-.config-manage-nav {
-  .config-groups-dropdown {
-    display: inline-block;
-    .btn.dropdown-toggle.first {
-      border-top-left-radius: 4px;
-      border-bottom-left-radius: 4px;
-      border-top-right-radius: 0;
-      border-bottom-right-radius: 0;
-    }
-    .spinner {
-      background-size: 20px;
-      height: 20px;
-      width: 20px;
-    }
-  }
-  .filter-combobox {
-    margin-bottom: 0;
-  }
-}
-
 .icon-undo {
   color: #F3B20B;
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/2e9c9646/ambari-web/app/styles/bootstrap_overrides.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/bootstrap_overrides.less b/ambari-web/app/styles/bootstrap_overrides.less
index e1a5ab5..3637c6b 100644
--- a/ambari-web/app/styles/bootstrap_overrides.less
+++ b/ambari-web/app/styles/bootstrap_overrides.less
@@ -286,7 +286,7 @@ select.form-control {
 }
 
 .nav-tabs > li.active > a, .nav-tabs > li.active > a:hover, .nav-tabs > li.active > a:focus {
-  background-color: #f0f0f0;
+  background-color: transparent;
 }
 
 @media (max-width: 992px) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/2e9c9646/ambari-web/app/styles/config_history_flow.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/config_history_flow.less b/ambari-web/app/styles/config_history_flow.less
deleted file mode 100644
index cc09d23..0000000
--- a/ambari-web/app/styles/config_history_flow.less
+++ /dev/null
@@ -1,414 +0,0 @@
-/**
- * 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 'common.less';
-
-#config_history_flow {
-  margin-bottom: 10px;
-  .version-slider {
-    .flow-element {
-      .version-box .box {
-        font-size: 13px;
-        .label-current {
-          padding-top: 2px;
-        }
-      }
-      .arrow-box {
-        margin-left: 5px;
-      }
-    }
-  }
-  .version-info-bar {
-    .label-current .glyphicon-ok {
-      display: inline;
-      color: #fff;
-    }
-  }
-}
-
-.dependencies-info-bar-wrapper {
-  z-index: 100;
-  margin: 0 0 20px;
-  .alert {
-    margin: 0;
-  }
-}
-
-#config_history_flow {
-  margin-top: -5px;
-  .version-slider {
-    width: 100%;
-    height: 75px;
-    margin: 5px 0;
-    .flow-element {
-      height: 75px;
-      width: 15.2%;
-      max-width: 146px;
-      .version-box {
-        position: relative;
-        height: 90%;
-      }
-      .version-box .box {
-        cursor: pointer;
-        width: 92%;
-        height: 100%;
-        background-color: #fff;
-        -webkit-border-radius: 4px;
-        -moz-border-radius: 4px;
-        border-radius: 4px;
-        border: 1px solid #d2d9dd;
-        font-size: 11px;
-        .top-label {
-          min-width: 20px;
-          padding: 3px 2px 0 2px;
-        }
-        .author,
-        .content {
-          text-align: center;
-          color: #555;
-          display: block;
-          overflow: hidden;
-          text-overflow: ellipsis;
-          white-space: nowrap;
-        }
-        .current-label {
-          text-align: center;
-          padding: 5px;
-        }
-        .stack-label {
-          margin-right: 6px;
-          text-align: right;
-          line-height: 11px;
-        }
-      }
-      .version-box .version-popover {
-        display: none;
-        position: absolute;
-        bottom: 50px;
-        left: -45px;
-        z-index: 1000;
-        float: left;
-        width: 380px;
-        padding: 8px;
-        list-style: none;
-        background-color: #fff;
-        border: 1px solid #c3c3c3;
-        -webkit-box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
-        -moz-box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
-        box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
-        -webkit-background-clip: padding-box;
-        -moz-background-clip: padding;
-        background-clip: padding-box;
-        font-size: 13px;
-        .content {
-          padding: 1px 5px 15px 5px;
-          text-align: left;
-          .notes{
-            padding-top: 6px;
-            overflow-wrap: break-word;
-            word-wrap: break-word;
-            white-space: pre-wrap;
-          }
-          .date{
-            padding-top: 5px;
-            color: #808080;
-            font-size: 11px;
-            white-space: nowrap;
-          }
-        }
-        .version-operations-buttons .btn {
-          font-size: 13px;
-        }
-      }
-      .version-box:hover{
-        .box {
-          background-color: #e6f1f6;
-        }
-      }
-      .version-box .box.displayed {
-        background-color: #e6f1f6;
-        .content {
-          color: #444;
-        }
-      }
-      .version-box .box.grayedOut {
-        background-color: #f4f4f4;
-        border: 1px solid #f4f4f4;
-        .author,
-        .content,
-        .stack-label {
-          color: #a6a6a6;
-        }
-        .current-label .label,
-        .top-label .label {
-          opacity: .5;
-        }
-
-      }
-
-    }
-    .first {
-      width: 14%;
-      margin-left: 10px;
-      .arrow-box {
-        display: none;
-      }
-      .version-box .box {
-        width: 100%;
-      }
-    }
-
-    .glyphicon-chevron-box {
-      margin-top: 8px;
-      width: 4%;
-      cursor: pointer;
-      .glyphicon-chevron-right,
-      .glyphicon-chevron-left{
-        color: #d2d9dd;
-      }
-      .glyphicon-chevron-left:hover,
-      .glyphicon-chevron-right:hover{
-        color: #808080;
-      }
-      &.disabled {
-        cursor: not-allowed;
-      }
-    }
-  }
-  .version-info-bar-wrapper {
-    margin: 0;
-    z-index: 100;
-  }
-
-  .version-info-bar {
-    background-color: @navigation-navy;
-    -webkit-box-shadow: inset 0 0 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1);
-    -moz-box-shadow: inset 0 0 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1);
-    box-shadow: inset 0 0 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1);
-    -webkit-border-radius: 4px;
-    -moz-border-radius: 4px;
-    border-radius: 4px;
-    padding: 5px;
-    clear:both;
-    margin-bottom: 5px;
-
-    .glyphicon-remove-circle {
-      color: #fff;
-      font-size: 1.5em;
-      padding-top: 4px;
-      margin-top: 0;
-      display: inline-block;
-      cursor: pointer;
-    }
-    .label-wrapper {
-      line-height: 30px;
-      color: #d3d3d3;
-      .label {
-        font-size: 14px;
-        padding: 4px;
-      }
-    }
-
-    ul#dropdown_menu {
-      position: absolute;
-      left: 0;
-      z-index: 1000;
-      min-width: 400px;
-      padding: 5px 0;
-      margin: 0;
-    }
-
-    #dropdown_content {
-      overflow: hidden;
-      &::-webkit-scrollbar {
-        display: none;
-      }
-    }
-
-    #dropdown_outer_container, #dropdown_menu_container {
-      min-width: 400px;
-      height: 300px;
-    }
-
-    #dropdown_outer_container {
-      position: relative;
-      overflow: hidden;
-    }
-
-    #dropdown_inner_container {
-      position: absolute;
-      left: 0;
-      overflow-x: hidden;
-      overflow-y: scroll;
-      &::-webkit-scrollbar {
-        display: none;
-      }
-    }
-
-    .dropdown-menu {
-      min-width: 400px;
-      margin-top: 4px !important;
-      font-size: 13px;
-      li {
-        height:35px;
-        line-height: 12px;
-        .glyphicon-caret-right {
-          font-size: 18px;
-          margin-right: 20px;
-        }
-      }
-      li:hover {
-        background-color: #666;
-        background-image: linear-gradient(to bottom, #666, #555);
-        color: #fff;
-      }
-      li#show_more:hover {
-        background: none;
-      }
-      li.not-allowed {
-        // the version which is displayed
-        cursor: not-allowed;
-        color: #808080;
-        .glyphicon-caret-right,
-        .dropdown-menu {
-          display: none;
-        }
-      }
-      li.not-allowed:hover {
-        background-color: #fff;
-        background-image: none;
-        color: #808080;
-      }
-
-      div.row, a {
-        padding-left: 10px;
-      }
-    }
-    .dropdown-submenu .dropdown-menu {
-      min-width: 200px;
-      max-width: 300px;
-      line-height: 20px;
-      font-size: 13px;
-      margin: 0;
-      padding: 8px;
-      color: #333;
-      cursor: default;
-      .content {
-        padding: 1px 5px 15px 5px;
-        .group {
-          text-align: right;
-          margin-top: -20px;
-        }
-        .date{
-          color: #808080;
-          font-size: 11px;
-          white-space: nowrap;
-        }
-        .notes{
-          word-wrap: break-word;
-          overflow-wrap: break-word;
-          white-space: pre-wrap;
-        }
-      }
-      .version-operations-buttons .btn {
-        font-size: 13px;
-      }
-    }
-  }
-
-  #config_version_popup {
-    z-index: 1001;
-    line-height: 20px;
-    padding: 8px;
-    font-size: 13px;
-    .content {
-      padding: 1px 5px 15px 5px;
-      .group {
-        text-align: right;
-        margin-top: -20px;
-      }
-      .date{
-        color: #808080;
-        font-size: 11px;
-        white-space: nowrap;
-      }
-      .notes{
-        word-wrap: break-word;
-        overflow-wrap: break-word;
-        white-space: pre-wrap;
-      }
-    }
-    .version-operations-buttons .btn {
-      font-size: 13px;
-    }
-  }
-  .stack {
-    padding: 1px 10px;
-    font-size: 11px;
-  }
-}
-
-#config_history {
-  .table {
-    .filter-input-width{
-      width: ~"calc(100% - 20px)";
-    }
-    // service name column
-    th:first-child,
-    td:first-child {
-      width: 15%;
-    }
-    // config group, create time columns
-    th:first-child + th,
-    td:first-child + td,
-    th:first-child + th + th,
-    td:first-child + td + td {
-      width: 20%;
-      word-wrap: break-word;
-    }
-    // author column
-    th:first-child + th + th + th,
-    td:first-child + td + td + td {
-      width: 180px;
-    }
-    // notes column
-    th:first-child + th + th + th + th,
-    td:first-child + td + td + td + td {
-      word-wrap: break-word;
-    }
-    td.notes .show-more-button {
-      font-size: @default-font-size - 1;
-    }
-  }
-  a {
-    cursor: pointer;
-  }
-}
-
-
-// Firefox specific styles
-@-moz-document url-prefix() {
-  #config_history_flow {
-    .version-info-bar {
-      .dropdown-menu {
-        li {
-          line-height: 30px !important;
-        }
-      }
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/2e9c9646/ambari-web/app/styles/config_versions_control.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/config_versions_control.less b/ambari-web/app/styles/config_versions_control.less
new file mode 100644
index 0000000..e7375d6
--- /dev/null
+++ b/ambari-web/app/styles/config_versions_control.less
@@ -0,0 +1,144 @@
+/**
+ * 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 'common.less';
+
+@button-width: 150px;
+@border-color: #EBECF1;
+
+#config-versions-control {
+  .dropdown-menu {
+    min-width: 600px;
+    li {
+      padding: 3px 20px;
+    }
+  }
+  .versions-list {
+    max-height: 405px;
+    overflow-y: auto;
+    padding-left: 0;
+    margin-bottom: 0;
+    li {
+      list-style-type: none;
+    }
+  }
+  .grey-text {
+    color: @top-nav-brand-color;
+  }
+  .current-color {
+    color: @health-status-green;
+  }
+  .notes-color {
+    color: #666;
+  }
+  .version-info.selected {
+    background-color: rgb(242, 249, 242);
+    border: 2px solid @border-color;
+    box-shadow: none;
+  }
+  .btn.dropdown-toggle {
+    padding: 10px;
+    text-align: left;
+    span {
+      text-transform: capitalize;
+    }
+    strong {
+      margin-left: 10px;
+      margin-right: 5px;
+    }
+  }
+  .search-input {
+    width: 100%;
+    margin: 5px 0 10px 0;
+    .btn {
+      padding: 10px;
+    }
+  }
+  .version-info {
+    border: 1px solid @border-color;
+    box-shadow: 0 0 5px 2px @border-color;
+    border-radius: 3px;
+    padding: 0 10px;
+    width: 93%;
+    display: inline-block;
+    cursor: pointer;
+    min-height: 60px;
+  }
+  .compare-button {
+    width: 5%;
+    vertical-align: top;
+    padding: 0 6px;
+    margin: 15px 0 0 6px;
+    height: 30px;
+    cursor: pointer;
+  }
+  .make-current {
+    color: @health-status-green;
+    border-color: @health-status-green;
+  }
+  .compare-bar {
+    background-color: @border-color;
+    padding: 10px 15px;
+    .close {
+      line-height: 30px;
+    }
+  }
+}
+
+.config-manage-nav {
+  .config-groups-dropdown {
+    display: inline-block;
+    width: @button-width;
+    .btn.dropdown-toggle {
+      width: 100%;
+      text-align: left;
+      padding: 10px;
+    }
+    .caret {
+      float: right;
+      margin-top: 5px;
+    }
+  }
+  .filter-combobox {
+    display: inline-block;
+    width: @button-width;
+  }
+  .spinner {
+    background-size: 20px;
+    height: 20px;
+    width: 20px;
+  }
+}
+
+div.config-manage-nav.pull-bottom {
+  margin-top: 0;
+}
+
+.config-manage-nav.pull-top {
+  margin-top: -42px;
+}
+
+.configs-save-panel {
+  position: fixed;
+  background: white;
+  padding: 15px 30px 20px;
+  bottom: 0;
+  right: 0;
+  width: 100%;
+  z-index: 3;
+  box-shadow: 0 -3px 5px 2px @border-color;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/2e9c9646/ambari-web/app/styles/widgets.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/widgets.less b/ambari-web/app/styles/widgets.less
index 9bf60f0..a11c30f 100644
--- a/ambari-web/app/styles/widgets.less
+++ b/ambari-web/app/styles/widgets.less
@@ -143,6 +143,9 @@
       left: -@overriden-property-widget-padding;
     }
   }
+  .input-group-btn {
+    width: auto;
+  }
 }
 
 .widget-config-comparison .widget-config&.slider-widget {
@@ -494,6 +497,4 @@
   padding: 10px 5px 0 10px;
 }
 
-.input-group-btn {
-  width: auto;
-}
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/2e9c9646/ambari-web/app/templates/common/configs/config_history_dropdown_row.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/configs/config_history_dropdown_row.hbs b/ambari-web/app/templates/common/configs/config_history_dropdown_row.hbs
deleted file mode 100644
index 80e6878..0000000
--- a/ambari-web/app/templates/common/configs/config_history_dropdown_row.hbs
+++ /dev/null
@@ -1,24 +0,0 @@
-{{!
-* 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="row version-in-dropdown" {{action doAction view.serviceVersion view.actionTypes.SWITCH target="view"}}>
-  <div class="col-md-2">{{view.serviceVersion.versionText}}</div>
-  <div class="col-md-6">{{view.serviceVersion.createdDate}}</div>
-  <div class="col-md-3">{{view.serviceVersion.authorFormatted}}</div>
-  <div class="pull-right"><i class="glyphicon glyphicon-caret-right"></i></div>
-</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/2e9c9646/ambari-web/app/templates/common/configs/config_history_flow.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/configs/config_history_flow.hbs b/ambari-web/app/templates/common/configs/config_history_flow.hbs
deleted file mode 100644
index 99cd140..0000000
--- a/ambari-web/app/templates/common/configs/config_history_flow.hbs
+++ /dev/null
@@ -1,148 +0,0 @@
-{{!
-* 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="config_history_flow" {{bindAttr class="view.parentView.supportsConfigLayout:with-enhanced-config"}}>
-  {{! Slider with config versions }}
-  <div class="version-slider">
-    <div {{bindAttr class=":glyphicon :glyphicon-chevron-box :pull-left view.showLeftArrow::disabled"}} {{action shiftBack target="view"}} data-toggle="arrow-tooltip"
-      {{bindAttr data-original-title="view.leftArrowTooltip"}}><i class="glyphicon-chevron-left glyphicon glyphicon-3x"></i></div>
-    <div {{bindAttr class=":glyphicon :glyphicon-chevron-box :pull-left view.showRightArrow::disabled"}} {{action shiftForward target="view"}} data-toggle="arrow-tooltip"
-      {{bindAttr data-original-title="view.rightArrowTooltip"}}><i class="glyphicon-chevron-right glyphicon glyphicon-3x"></i></div>
-    {{#each sV in view.visibleServiceVersion}}
-      {{view App.ConfigsServiceVersionBoxView serviceVersionBinding="sV"}}
-    {{/each}}
-  </div>
-  {{! Slider with config versions end }}
-
-  <div class="version-info-bar-wrapper">
-    {{! Compare config versions bar }}
-    {{#isAuthorized "SERVICE.COMPARE_CONFIGS"}}
-      <div {{bindAttr class="view.showCompareVersionBar::hidden :version-info-bar"}}>
-        <div class="row">
-          <div class="col-md-1 remove-compare-bar" {{action removeCompareVersionBar target="view"}} data-toggle="arrow-tooltip" {{translateAttr data-original-title="services.service.config.configHistory.dismissIcon.tooltip"}}>
-            <i class="glyphicon-remove-circle glyphicon glyphicon-large"></i>
-          </div>
-          <div class="label-wrapper col-md-8" data-toggle="tooltip" {{bindAttr data-original-title="view.compareServiceVersion.fullNotes"}}>
-            {{t services.service.config.configHistory.comparing}}
-            <span class="label label-info current-version-label">{{view.displayedServiceVersion.versionText}}</span>
-            ...
-            <span class="label label-info compare-version-label">{{view.compareServiceVersion.versionText}}</span>
-            {{#if view.compareServiceVersion.isCurrent}}
-              <span class="label label-success">{{t common.current}}</span>
-            {{/if}}
-              <strong>{{view.compareServiceVersion.authorFormatted}}</strong>&nbsp;{{t dashboard.configHistory.info-bar.authoredOn}}
-              &nbsp;<strong>{{view.compareServiceVersion.createdDate}}</strong>
-          </div>
-          {{#isAuthorized "SERVICE.MODIFY_CONFIGS"}}
-            <div class="operations-button col-md-3">
-              <button class="pull-right btn btn-success" {{action doAction view.serviceVersionsReferences.compare view.actionTypes.REVERT target="view"}} {{bindAttr disabled="view.versionActionsDisabled" class="view.compareServiceVersion.canBeMadeCurrent::hidden"}}>{{view.compareServiceVersion.makeCurrentButtonText}}</button>
-            </div>
-          {{/isAuthorized}}
-        </div>
-      </div>
-    {{/isAuthorized}}
-    {{! Compare config versions bar end }}
-
-    {{! Popup for config version }}
-    {{#view App.ConfigHistoryDropdownSubMenuView id="config_version_popup"}}
-      {{#if view.parentView.hoveredServiceVersion}}
-        <div class="content">
-          <span class="label label-info">{{view.parentView.hoveredServiceVersion.versionText}}</span>
-          <span class="stack">{{view.parentView.hoveredServiceVersion.stackVersion}}</span>
-          <div class="group"><strong>{{view.parentView.hoveredServiceVersion.configGroupName}}</strong></div>
-          <div class="date"><strong>{{view.parentView.hoveredServiceVersion.authorFormatted}}</strong>&nbsp;{{t dashboard.configHistory.info-bar.authoredOn}}&nbsp;<strong>{{view.parentView.hoveredServiceVersion.createdDate}}</strong></div>
-          <div class="notes">{{view.parentView.hoveredServiceVersion.fullNotes}}</div>
-        </div>
-        <div class="version-operations-buttons">
-          <button {{bindAttr disabled="view.parentView.hoveredServiceVersion.disabledActionAttr.view" class=":btn :btn-default view.parentView.hoveredServiceVersion.isDisplayed:not-allowed-cursor" title="view.parentView.hoveredServiceVersion.disabledActionMessages.view"}} {{action doAction undefined view.parentView.actionTypes.SWITCH target="view.parentView"}}><i class="glyphicon glyphicon-search"></i>&nbsp;{{t common.view}}</button>
-          {{#havePermissions "SERVICE.COMPARE_CONFIGS"}}
-            <button {{bindAttr disabled="view.parentView.hoveredServiceVersion.disabledActionAttr.compare" class=":btn :btn-default view.parentView.hoveredServiceVersion.isDisplayed:not-allowed-cursor" title="view.parentView.hoveredServiceVersion.disabledActionMessages.compare"}} {{action doAction undefined view.parentView.actionTypes.COMPARE target="view.parentView"}}><i class="glyphicon glyphicon-copy"></i>&nbsp;{{t common.compare}}</button>
-          {{/havePermissions}}
-          {{#havePermissions "SERVICE.MODIFY_CONFIGS"}}
-            <button {{bindAttr disabled="view.parentView.hoveredServiceVersion.disabledActionAttr.revert" class=":btn :btn-default view.parentView.hoveredServiceVersion.isCurrent:not-allowed-cursor view.parentView.hoveredServiceVersion.isCompatible::hidden" title="view.parentView.hoveredServiceVersion.disabledActionMessages.revert"}} {{action doAction undefined view.parentView.actionTypes.REVERT target="view.parentView"}}>{{t dashboard.configHistory.info-bar.revert.button}}</button>
-          {{/havePermissions}}
-        </div>
-      {{/if}}
-    {{/view}}
-    {{! Popup for config version }}
-
-    {{! Config Version Bar }}
-    <div class="version-info-bar">
-      <div class="row">
-        <div class="btn-group col-md-2">
-          <button id="toggle-dropdown-button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" href="#" {{action hideFullList target="view"}} {{bindAttr disabled="view.versionActionsDisabled"}}>
-            <i class="glyphicon glyphicon-random"></i>
-            <span class="caret"></span>
-          </button>
-          <div id="dropdown_content" class="dropdown-menu">
-            <div id="dropdown_outer_container">
-              <div id="dropdown_inner_container">
-                <div id="dropdown_menu_container">
-                  <ul id="dropdown_menu">
-                    {{#each serviceVersion in view.dropDownList}}
-                      {{view App.ConfigHistoryDropdownRowView serviceVersionBinding="serviceVersion"}}
-                    {{/each}}
-                    {{#unless view.showFullList}}
-                      <li class="align-center pointer" id="show_more">
-                        <a {{action openFullList target="view"}}>
-                          {{t dashboard.configHistory.info-bar.showMore}}&nbsp;{{controller.selectedService.displayName}}
-                          &nbsp;<span class="lowercase ellipsis">{{t dashboard.configHistory.title}}</span>
-                        </a>
-                      </li>
-                    {{/unless}}
-                  </ul>
-                </div>
-              </div>
-            </div>
-          </div>
-        </div>
-        <div class="label-wrapper col-md-6" data-toggle="tooltip" {{bindAttr data-original-title="view.displayedServiceVersion.fullNotes"}}>
-          {{#if view.displayedServiceVersion.versionText}}
-            <span class="label label-info current-version-label">{{view.displayedServiceVersion.versionText}}</span>
-          {{/if}}
-          {{#if view.displayedServiceVersion.isCurrent}}
-              <span class="label label-current label-success" data-toggle="tooltip" {{translateAttr title="common.current"}}>
-                <i class="glyphicon glyphicon-ok"></i>
-              </span>
-          {{/if}}
-          {{#if view.displayedServiceVersion.author}}
-            &nbsp;<strong>{{view.displayedServiceVersion.author}}</strong>&nbsp;{{t dashboard.configHistory.info-bar.authoredOn}}&nbsp;<strong>{{view.displayedServiceVersion.createdDate}}</strong>
-          {{/if}}
-        </div>
-        {{#isAuthorized "SERVICE.MODIFY_CONFIGS"}}
-          <div class="operations-button col-md-4">
-            <div {{bindAttr class="view.displayedServiceVersion.isCurrent::hidden :pull-right"}}>
-              <button class="btn btn-default" {{action doCancel target="controller"}} {{bindAttr disabled="view.isDiscardDisabled"}}>
-                {{t common.discard}}
-              </button>
-              <button class="btn btn-success" {{action save target="view"}} {{bindAttr disabled="view.isSaveDisabled"}}>
-                {{t common.save}}
-              </button>
-            </div>
-            <div class="pull-right">
-              <button class="btn btn-success" {{action doAction view.serviceVersionsReferences.displayed view.actionTypes.REVERT target="view"}} {{bindAttr disabled="view.versionActionsDisabled" class="view.displayedServiceVersion.canBeMadeCurrent::hidden"}}>
-                {{view.displayedServiceVersion.makeCurrentButtonText}}
-              </button>
-            </div>
-          </div>
-        {{/isAuthorized}}
-      </div>
-    </div>
-    {{! Config Version Bar end }}
-  </div>
-</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/2e9c9646/ambari-web/app/templates/common/configs/config_versions_control.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/configs/config_versions_control.hbs b/ambari-web/app/templates/common/configs/config_versions_control.hbs
new file mode 100644
index 0000000..251276b
--- /dev/null
+++ b/ambari-web/app/templates/common/configs/config_versions_control.hbs
@@ -0,0 +1,42 @@
+{{!
+* 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="config-versions-control">
+  {{#if view.isCompareMode}}
+    <div class="compare-bar">
+      <i class="glyphicon glyphicon-duplicate" aria-hidden="true"></i>
+      <span>{{t services.service.config.configHistory.comparing}}:</span>
+      {{view App.ConfigVersionsDropdownView
+             serviceVersionsBinding="view.primaryServiceVersionsInCompare"
+             isCompareMode="true"}}
+      <span class="grey-text">{{t common.with}}</span>
+      {{view App.ConfigVersionsDropdownView
+             serviceVersionsBinding="view.secondaryServiceVersionsInCompare"
+             isSecondary="true"
+             isCompareMode="true"}}
+      <a {{action removeCompareVersionBar target="view"}} class="pull-right close">&times;</a>
+    </div>
+  {{else}}
+    {{view App.ConfigVersionsDropdownView serviceVersionsBinding="view.serviceVersions"}}
+    {{#unless view.displayedServiceVersion.isCurrent}}
+      <button class="btn btn-default make-current" {{action makeCurrent view.displayedServiceVersion target="view"}}>
+        {{t dashboard.configHistory.info-bar.revert.button}}
+      </button>
+    {{/unless}}
+  {{/if}}
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/2e9c9646/ambari-web/app/templates/common/configs/config_versions_dropdown.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/configs/config_versions_dropdown.hbs b/ambari-web/app/templates/common/configs/config_versions_dropdown.hbs
new file mode 100644
index 0000000..18083f9
--- /dev/null
+++ b/ambari-web/app/templates/common/configs/config_versions_dropdown.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.
+}}
+
+<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true"
+        aria-expanded="false">
+  {{t common.version}}:
+  <span class="pull-right"><strong>{{view.displayedServiceVersion.version}}</strong><span class="caret"></span></span>
+</button>
+<div class="dropdown-menu">
+  <li class="input-group search-input">
+    {{view Em.TextField valueBinding="view.filterValue" class="form-control" placeholderBinding="view.searchLabel"}}
+    <span class="input-group-btn">
+            <button class="btn btn-default" type="button">
+              <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
+            </button>
+          </span>
+  </li>
+  <ul class="versions-list">
+    {{#each item in view.filteredServiceVersions}}
+      <li>
+        <div {{bindAttr class="item.isDisplayed:selected view.isCompareMode:full-width :version-info"}}
+          {{action mainClickAction item target="view"}}>
+          <div class="row">
+            <div class="col-md-4">
+              <span class="h2">{{t common.version}}&nbsp;{{item.version}}&nbsp;</span>
+              <span class="description grey-text">{{item.stackVersion}}</span>
+            </div>
+            <div class="col-md-8 description grey-text">
+                <span class="pull-right">
+                  <strong>{{item.authorFormatted}}</strong>
+                  &nbsp;{{t dashboard.configHistory.info-bar.authoredOn}}&nbsp;
+                  <strong>{{item.createdDate}}</strong>
+                </span>
+            </div>
+          </div>
+          <div class="row">
+            <div class="col-md-10 description notes-color">{{item.fullNotes}}</div>
+            <div class="col-md-2">
+              {{#if item.isCurrent}}
+                <strong class="pull-right current-color">{{t common.current}}</strong>
+              {{/if}}
+            </div>
+          </div>
+        </div>
+        {{#unless view.isCompareMode}}
+          <button {{bindAttr class="item.isDisplayed:hide :compare-button :btn :btn-default"}}
+            {{action compare item target="view.parentView"}}>
+            <i class="glyphicon glyphicon-duplicate" aria-hidden="true"></i>
+          </button>
+        {{/unless}}
+      </li>
+    {{/each}}
+  </ul>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/2e9c9646/ambari-web/app/templates/common/configs/service_config.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/configs/service_config.hbs b/ambari-web/app/templates/common/configs/service_config.hbs
index f071dd2..b097b16 100644
--- a/ambari-web/app/templates/common/configs/service_config.hbs
+++ b/ambari-web/app/templates/common/configs/service_config.hbs
@@ -45,54 +45,61 @@
     </div>
   {{/if}}
 {{/if}}
-{{#if view.supportsHostOverrides}}
-  <div class="alert alert-info config-manage-nav">
 
-    {{t common.group}}&nbsp;
-	  <span class="btn-group config-groups-dropdown">
-      {{#if controller.configGroupsAreLoaded}}
-        <button {{bindAttr disabled="controller.isHostsConfigsPage"}} style="text-transform: none;" class="btn btn-default dropdown-toggle first"
-                                                                      data-toggle="dropdown">{{selectedConfigGroup.displayNameHosts}}</button>
-        <button {{bindAttr disabled="controller.isHostsConfigsPage"}} class="btn btn-default dropdown-toggle" data-toggle="dropdown">
-          <span class="caret"></span>
-        </button>
-        <ul class="dropdown-menu config-groups-dropdown-menu">
-          <!-- available config group menu links -->
-          {{#each configGroup in configGroups}}
-            <li>
-              <a href="#" {{action "selectConfigGroup" configGroup target="controller"}}>
-                {{configGroup.displayNameHosts}}
-              </a>
-            </li>
-          {{/each}}
-        </ul>
+
+<div>
+  <div class="mbm">
+    {{#if view.isOnTheServicePage}}
+      {{#if allVersionsLoaded}}
+        {{view App.ConfigVersionsControlView}}
       {{else}}
-        {{view App.SpinnerView classNames="pull-left"}}
+        {{view App.SpinnerView}}
       {{/if}}
-		</span>
+    {{/if}}
+  </div>
+  {{#if view.supportsHostOverrides}}
+    <div {{bindAttr class="controller.isCompareMode:pull-bottom :pull-top :config-manage-nav :pull-right"}}>
       {{#if controller.isHostsConfigsPage}}
         {{#isAuthorized "SERVICE.MANAGE_CONFIG_GROUPS"}}
           &nbsp;<a href="#" {{action "switchHostGroup" target="controller"}}>{{t common.change}}</a>
         {{/isAuthorized}}
+      {{/if}}
+      {{t common.configGroup}}&nbsp;
+      {{#if controller.configGroupsAreLoaded}}
+        <div class="btn-group config-groups-dropdown">
+          <button {{bindAttr disabled="controller.isHostsConfigsPage"}}
+            class="btn btn-default dropdown-toggle"
+            data-toggle="dropdown">
+            {{selectedConfigGroup.displayNameHosts}}
+            <span class="caret"></span>
+          </button>
+          <ul class="dropdown-menu config-groups-dropdown-menu">
+            {{#isAuthorized "SERVICE.MANAGE_CONFIG_GROUPS"}}
+              <li>
+                <a href="#" class="link-left-pad" {{action "manageConfigurationGroup" target="controller"}}>{{t
+                  services.service.actions.manage_configuration_groups.short}}</a>
+              </li>
+              <li role="separator" class="divider"></li>
+            {{/isAuthorized}}
+            <!-- available config group menu links -->
+            {{#each configGroup in configGroups}}
+              <li>
+                <a href="#" {{action "selectConfigGroup" configGroup target="controller"}}>
+                  {{configGroup.displayNameHosts}}
+                </a>
+              </li>
+            {{/each}}
+          </ul>
+        </div>
       {{else}}
-        {{#isAuthorized "SERVICE.MANAGE_CONFIG_GROUPS"}}
-            <a href="#" class="link-left-pad" {{action "manageConfigurationGroup" target="controller"}}>{{t services.service.actions.manage_configuration_groups.short}}</a>
-        {{/isAuthorized}}
+        {{view App.SpinnerView classNames="pull-left"}}
       {{/if}}
-    <div class="pull-right">
-      {{view App.FilterComboCleanableView filterBinding="view.filter" columnsBinding="view.columns" popoverDescriptionBinding="view.propertyFilterPopover"}}
-    </div>
-    <div class="clearfix"></div>
-  </div>
-{{/if}}
+      {{view App.FilterComboCleanableView classNames="col-lg-4" filterBinding="view.filter"
+             columnsBinding="view.columns" popoverDescriptionBinding="view.propertyFilterPopover"}}
 
-{{#if view.isOnTheServicePage}}
-  {{#if allVersionsLoaded}}
-    {{view App.ConfigHistoryFlowView serviceBinding="selectedService"}}
-  {{else}}
-    {{view App.SpinnerView}}
+    </div>
   {{/if}}
-{{/if}}
+</div>
 
 {{#if versionLoaded}}
   {{#unless hideDependenciesInfoBar}}
@@ -149,10 +156,24 @@
     {{view App.ConfigCategoryContainerView categoriesBinding="selectedService.configCategories" canEditBinding="view.canEdit" serviceBinding="selectedService" serviceConfigsBinding="selectedService.configs" supportsHostOverridesBinding="view.supportsHostOverrides"}}
   {{/if}}
   {{#if view.isAllConfigsHidden}}
-    <div class="alert alert-info col-sm-12">
+    <div class="alert alert-info">
       {{t services.service.config.nothing.to.display}}
     </div>
   {{/if}}
 {{else}}
   {{view App.SpinnerView}}
 {{/if}}
+
+<div class="configs-save-panel" {{bindAttr class="view.showSavePanel::hidden"}}>
+  <div class="pull-right">
+    <button class="btn btn-default" {{action doCancel target="controller"}}
+      {{bindAttr disabled="view.isDiscardDisabled"}}>
+      {{t common.discard}}
+    </button> &nbsp;
+    <button class="btn btn-success" {{action save target="view"}}
+      {{bindAttr disabled="view.isSaveDisabled"}}>
+      {{t common.save}}
+    </button>
+  </div>
+  <div class="clearfix"></div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/2e9c9646/ambari-web/app/views.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views.js b/ambari-web/app/views.js
index 394e390..e18182f 100644
--- a/ambari-web/app/views.js
+++ b/ambari-web/app/views.js
@@ -75,7 +75,8 @@ require('views/common/configs/config_category_container_view');
 require('views/common/configs/overriddenPropertyRow_view');
 require('views/common/configs/overriddenProperty_view');
 require('views/common/configs/compare_property_view');
-require('views/common/configs/config_history_flow');
+require('views/common/configs/config_versions_control_view');
+require('views/common/configs/config_versions_dropdown_view');
 require('views/common/configs/selectable_popup_body_view');
 require('views/common/configs/custom_category_views/notification_configs_view');
 require('views/common/configs/config_diff_view');

http://git-wip-us.apache.org/repos/asf/ambari/blob/2e9c9646/ambari-web/app/views/common/configs/config_history_flow.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/configs/config_history_flow.js b/ambari-web/app/views/common/configs/config_history_flow.js
deleted file mode 100644
index 32a5e71..0000000
--- a/ambari-web/app/views/common/configs/config_history_flow.js
+++ /dev/null
@@ -1,644 +0,0 @@
-/**
- * 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.
- */
-
-var App = require('app');
-
-App.ConfigHistoryFlowView = Em.View.extend({
-  templateName: require('templates/common/configs/config_history_flow'),
-
-  /**
-   * index of the first element(service version box) in viewport
-   */
-  startIndex: 0,
-  showLeftArrow: false,
-  showRightArrow: false,
-  leftArrowTooltip: Em.computed.ifThenElse('showLeftArrow', Em.I18n.t('services.service.config.configHistory.leftArrow.tooltip'), null),
-  rightArrowTooltip: Em.computed.ifThenElse('showRightArrow', Em.I18n.t('services.service.config.configHistory.rightArrow.tooltip'), null),
-  VERSIONS_IN_FLOW: 6,
-  VERSIONS_IN_DROPDOWN: 25,
-  /**
-   * flag identify whether to show all versions or short list of them
-   */
-  showFullList: false,
-  compareServiceVersion: null,
-
-  /**
-   * types of actions that can't be done to service config versions
-   */
-  actionTypes: {
-    SWITCH: 'switchVersion',
-    COMPARE: 'compare',
-    REVERT: 'revert'
-  },
-
-  /**
-   * serviceVersion object that is currently being hovered in the dropdown menu
-   */
-  hoveredServiceVersion: null,
-  /**
-   * flag to check if sub-menu popup is currently being hovered
-   */
-  displaySubMenuFlag: false,
-  /**
-   * flag to check if any dropdown item is currently hovered by the user
-   */
-  isHovered: false,
-
-  /**
-   * In reason of absence of properties dynamic values support which passed to an action,
-   * used property map to get latest values of properties for action
-   */
-  serviceVersionsReferences: {
-    displayed: Em.Object.create({
-      isReference: true,
-      property: 'displayedServiceVersion'
-    }),
-    compare: Em.Object.create({
-      isReference: true,
-      property: 'compareServiceVersion'
-    })
-  },
-
-  allServiceVersions: function() {
-    return App.ServiceConfigVersion.find().filterProperty('serviceName', this.get('serviceName'));
-  }.property('serviceName'),
-
-  showCompareVersionBar: Em.computed.bool('compareServiceVersion'),
-
-  isSaveDisabled: Em.computed.or('controller.isSubmitDisabled', '!controller.versionLoaded', '!controller.isPropertiesChanged'),
-
-  serviceName: Em.computed.alias('controller.content.serviceName'),
-
-  displayedServiceVersion: Em.computed.findBy('serviceVersions', 'isDisplayed', true),
-  /**
-   * identify whether to show link that open whole content of notes
-   */
-  showMoreLink: Em.computed.gt('displayedServiceVersion.notes.length', 100),
-  /**
-   * formatted notes ready to display
-   */
-  shortNotes: Em.computed.truncate('displayedServiceVersion.notes', 100, 100),
-
-  serviceVersions: function () {
-    var isDefaultGroupSelected = this.get('controller.selectedConfigGroup.isDefault');
-    var groupId = this.get('controller.selectedConfigGroup.id');
-    var self = this;
-
-    this.get('allServiceVersions').forEach(function (version) {
-      version.set('isDisabled', !(version.get('groupId') === groupId || isDefaultGroupSelected && version.get('groupName') === App.ServiceConfigGroup.defaultGroupName));
-    }, this);
-
-    var serviceVersions = this.get('allServiceVersions').filter(function(s) {
-      return s.get('groupId') === groupId || s.get('groupName') === App.ServiceConfigGroup.defaultGroupName;
-    });
-
-    if (!serviceVersions.findProperty('isDisplayed')) {
-      //recompute serviceVersions if displayed version absent
-      Em.run.next(function() {
-        self.propertyDidChange('controller.selectedConfigGroup.name');
-      });
-    }
-
-    return serviceVersions.sort(function (a, b) {
-      return Em.get(b, 'createTime') - Em.get(a, 'createTime');
-    });
-  }.property('serviceName', 'controller.selectedConfigGroup.name'),
-
-  /**
-   * disable versions visible to the user to prevent actions on them
-   */
-  disableVersions: function () {
-    this.get('allServiceVersions').setEach('isDisabled', true);
-  },
-
-  /**
-   * service versions which in viewport and visible to user
-   */
-  visibleServiceVersion: function () {
-    return this.get('serviceVersions').slice(this.get('startIndex'), this.get('startIndex') + this.VERSIONS_IN_FLOW);
-  }.property('startIndex', 'serviceVersions'),
-
-  /**
-   * enable actions to manipulate version only after it's loaded
-   */
-  versionActionsDisabled: Em.computed.or('!controller.versionLoaded', '!dropDownList.length'),
-
-  /**
-   * enable discard to manipulate version only after it's loaded and any property is changed
-   */
-  isDiscardDisabled: Em.computed.or('!controller.versionLoaded', '!controller.isPropertiesChanged'),
-  /**
-   * list of service versions
-   * by default 6 is number of items in short list
-   */
-  dropDownList: function () {
-    var serviceVersions = this.get('serviceVersions').slice(0);
-    if (this.get('showFullList')) {
-      return serviceVersions;
-    }
-    return serviceVersions.slice(0, this.VERSIONS_IN_DROPDOWN);
-  }.property('serviceVersions', 'showFullList', 'displayedServiceVersion'),
-
-  openFullList: function (event) {
-    event.stopPropagation();
-    this.set('showFullList', true);
-  },
-
-  hideFullList: function (event) {
-    this.set('showFullList', !(this.get('serviceVersions.length') > this.VERSIONS_IN_DROPDOWN));
-  },
-
-  didInsertElement: function () {
-    App.tooltip(this.$('[data-toggle=tooltip]'),{
-      placement: 'bottom',
-      html: false
-    });
-    App.tooltip(this.$('[data-toggle=arrow-tooltip]'),{
-      placement: 'top'
-    });
-    this.$(".version-info-bar-wrapper").stick_in_parent({parent: '#serviceConfig', offset_top: 10});
-    this.onChangeConfigGroup();
-  },
-
-  willDestroyElement: function() {
-    this.$('.version-info-bar-wrapper').trigger('sticky_kit:detach').off();
-    this.$('[data-toggle=tooltip]').tooltip('destroy');
-    this.$('[data-toggle=arrow-tooltip]').tooltip('destroy');
-  },
-
-  willInsertElement: function () {
-    this.setDisplayVersion();
-  },
-
-  setDisplayVersion: function () {
-    var serviceVersions = this.get('serviceVersions');
-    var startIndex = 0;
-    var currentIndex = 0;
-    var selectedVersion = this.get('controller.selectedVersion');
-
-    serviceVersions.setEach('isDisplayed', false);
-
-    serviceVersions.forEach(function (serviceVersion, index) {
-      if (selectedVersion === serviceVersion.get('version')) {
-        serviceVersion.set('isDisplayed', true);
-        currentIndex = index;
-      }
-    }, this);
-
-    // show current version as the last one
-    if (currentIndex + 1 > this.VERSIONS_IN_FLOW) {
-      startIndex = currentIndex + 1 - this.VERSIONS_IN_FLOW;
-    }
-    this.set('startIndex', startIndex);
-    this.adjustFlowView();
-  }.observes('allVersionsLoaded'),
-
-  onChangeConfigGroup: function () {
-    var serviceVersions = this.get('serviceVersions');
-    var selectedGroupName = this.get('controller.selectedConfigGroup.name');
-    var preselectedVersion = this.get('controller.selectedVersion');
-    var startIndex = 0;
-    var currentIndex = 0;
-    var isCurrentInDefaultGroupIndex = null;
-
-
-    serviceVersions.setEach('isDisplayed', false);
-    // display selected version from config history
-    serviceVersions.forEach(function (serviceVersion, index) {
-      // find selected version in group
-      if (serviceVersion.get('version') === preselectedVersion && serviceVersion.get('groupName') === selectedGroupName) {
-        serviceVersion.set('isDisplayed', true);
-        currentIndex = index + 1;
-      }
-    });
-    // display current in selected group
-    if (!currentIndex) {
-      serviceVersions.forEach(function (serviceVersion, index) {
-        // find current in selected group
-        if (serviceVersion.get('isCurrent') && serviceVersion.get('groupName') === selectedGroupName) {
-          serviceVersion.set('isDisplayed', true);
-          currentIndex = index + 1;
-        }
-        if (serviceVersion.get('isCurrent') && serviceVersion.get('groupName') === App.ServiceConfigGroup.defaultGroupName) {
-          isCurrentInDefaultGroupIndex = index;
-        }
-      });
-      // if there is no current version in selected group show current version from default group
-      if (!currentIndex && !Em.isNone(isCurrentInDefaultGroupIndex)) {
-        serviceVersions[isCurrentInDefaultGroupIndex].set('isDisplayed', true);
-        currentIndex = isCurrentInDefaultGroupIndex + 1;
-      }
-    }
-    // show current version as the last one
-    if (currentIndex > this.VERSIONS_IN_FLOW) {
-      startIndex = currentIndex - this.VERSIONS_IN_FLOW;
-    }
-    this.set('startIndex', startIndex);
-    this.adjustFlowView();
-  }.observes('controller.selectedConfigGroup'),
-
-  /**
-   *  define the first element in viewport
-   *  change visibility of arrows
-   */
-  adjustFlowView: function () {
-    var startIndex = this.get('startIndex');
-    this.get('serviceVersions').forEach(function (serviceVersion, index) {
-      serviceVersion.set('first', index === startIndex);
-    });
-    this.set('showLeftArrow', startIndex !== 0);
-    this.set('showRightArrow', (this.get('serviceVersions.length') > this.VERSIONS_IN_FLOW) && ((startIndex + this.VERSIONS_IN_FLOW) < this.get('serviceVersions.length')));
-  },
-
-  /**
-   * check action constraints prior to invoke it
-   * @param event
-   */
-  doAction: function (event) {
-    var type = event.contexts[1],
-        controller = this.get('controller'),
-        self = this;
-    if (!controller.get('versionLoaded')) {
-      return;
-    }
-    // action from right popup of pull down version list will have context[0] == undefined, and use 'hoveredServiceVersion'.
-    // refer to AMBARI-19871 for more info
-    var configVersion = event.contexts[0] || this.get('hoveredServiceVersion');
-    if (type === 'switchVersion') {
-      if (configVersion && configVersion.get("isDisplayed"))  return;
-    } else {
-      var isDisabled = configVersion ? configVersion.get('isDisabled') : false;
-      if (isDisabled) return;
-    }
-
-    function callback() {
-      self[type].call(self, event);
-    }
-
-    Em.run.next(function() {
-      if (controller.hasUnsavedChanges()) {
-        controller.showSavePopup(null, callback);
-        return;
-      }
-
-      self.disableVersions();
-      callback();
-    });
-    $("#config_version_popup").removeAttr('style');
-  },
-
-  /**
-   * switch configs view version to chosen
-   */
-  switchVersion: function (event) {
-    var configVersion = event.contexts[0] || this.get('hoveredServiceVersion');
-    var version = configVersion.get('version');
-    var versionIndex = 0;
-    this.set('compareServiceVersion', null);
-    this.get('serviceVersions').forEach(function (serviceVersion, index) {
-      if (serviceVersion.get('version') === version) {
-        serviceVersion.set('isDisplayed', true);
-        versionIndex = index;
-      } else {
-        serviceVersion.set('isDisplayed', false);
-      }
-    });
-    this.shiftFlowOnSwitch(versionIndex);
-    this.get('controller').loadSelectedVersion(version);
-  },
-
-  /**
-   * add config values of chosen version to view for comparison
-   * add a second version-info-bar for the chosen version
-   */
-  compare: function (event) {
-    var serviceConfigVersion = event.contexts[0] || this.get('hoveredServiceVersion');
-    this.set('controller.compareServiceVersion', serviceConfigVersion);
-    this.set('compareServiceVersion', serviceConfigVersion);
-
-    var controller = this.get('controller');
-    controller.get('stepConfigs').clear();
-    controller.loadCompareVersionConfigs(controller.get('allConfigs')).done(function() {
-      controller.onLoadOverrides(controller.get('allConfigs'));
-    });
-  },
-  removeCompareVersionBar: function () {
-    var displayedVersion = this.get('displayedServiceVersion.version');
-    var versionIndex = 0;
-
-    this.set('compareServiceVersion', null);
-    this.get('serviceVersions').forEach(function (serviceVersion, index) {
-      if (serviceVersion.get('version') === displayedVersion) {
-        serviceVersion.set('isDisplayed', true);
-        versionIndex = index;
-      } else {
-        serviceVersion.set('isDisplayed', false);
-      }
-    });
-    this.set('isCompareMode', false);
-    this.shiftFlowOnSwitch(versionIndex);
-    this.get('controller').loadSelectedVersion(displayedVersion);
-  },
-  clearCompareVersionBar: function () {
-    if (this.get('controller.isCompareMode') === false) {
-      this.set('compareServiceVersion', null);
-    }
-  }.observes('controller.isCompareMode'),
-  /**
-   * revert config values to chosen version and apply reverted configs to server
-   */
-  revert: function (event) {
-    var self = this;
-    var serviceConfigVersion = event.contexts[0] || this.get('hoveredServiceVersion') || Em.Object.create({
-      version: this.get('displayedServiceVersion.version'),
-      serviceName: this.get('displayedServiceVersion.serviceName'),
-      notes:''
-    });
-    if (serviceConfigVersion.get('isReference')) {
-      serviceConfigVersion = this.get(serviceConfigVersion.get('property'));
-    }
-    var versionText = serviceConfigVersion.get('versionText');
-    return App.ModalPopup.show({
-      header: Em.I18n.t('dashboard.configHistory.info-bar.makeCurrent.popup.title'),
-      serviceConfigNote: Em.I18n.t('services.service.config.configHistory.makeCurrent.message').format(versionText),
-      bodyClass: Em.View.extend({
-        templateName: require('templates/common/configs/save_configuration'),
-        classNames: ['col-md-12'],
-        notesArea: Em.TextArea.extend({
-          classNames: ['full-width'],
-          value: Em.I18n.t('services.service.config.configHistory.makeCurrent.message').format(versionText),
-          onChangeValue: function() {
-            this.get('parentView.parentView').set('serviceConfigNote', this.get('value'));
-          }.observes('value')
-        })
-      }),
-      primary: Em.I18n.t('dashboard.configHistory.info-bar.revert.button'),
-      secondary: Em.I18n.t('common.discard'),
-      third: Em.I18n.t('common.cancel'),
-      onPrimary: function () {
-        serviceConfigVersion.set('serviceConfigNote', this.get('serviceConfigNote'));
-        self.sendRevertCall(serviceConfigVersion);
-        this.hide();
-      },
-      onSecondary: function () {
-        // force <code>serviceVersions</code> recalculating
-        self.propertyDidChange('controller.selectedConfigGroup.name');
-        this._super();
-      },
-      onThird: function () {
-        this.onSecondary();
-      }
-    });
-  },
-
-  /**
-   * send PUT call to revert config to selected version
-   * @param serviceConfigVersion
-   */
-  sendRevertCall: function (serviceConfigVersion) {
-    App.ajax.send({
-      name: 'service.serviceConfigVersion.revert',
-      sender: this,
-      data: {
-        data: {
-          "Clusters": {
-            "desired_service_config_versions": {
-              "service_config_version": serviceConfigVersion.get('version'),
-              "service_name": serviceConfigVersion.get('serviceName'),
-              "service_config_version_note": serviceConfigVersion.get('serviceConfigNote')
-            }
-          }
-        }
-      },
-      success: 'sendRevertCallSuccess'
-    });
-  },
-
-  sendRevertCallSuccess: function (data, opt, params) {
-    // revert to an old version would generate a new version with latest version number,
-    // so, need to loadStep to update
-    App.router.get('updateController').updateComponentConfig(Em.K);
-    this.get('controller').loadStep();
-  },
-
-  /**
-   * save configuration
-   * @return {object}
-   */
-  save: function () {
-    var self = this;
-    var passwordWasChanged = this.get('controller.passwordConfigsAreChanged');
-    return App.ModalPopup.show({
-      header: Em.I18n.t('dashboard.configHistory.info-bar.save.popup.title'),
-      serviceConfigNote: '',
-      bodyClass: Em.View.extend({
-        templateName: require('templates/common/configs/save_configuration'),
-        classNames: ['col-md-12'],
-        showPasswordChangeWarning: passwordWasChanged,
-        notesArea: Em.TextArea.extend({
-          classNames: ['full-width'],
-          value: passwordWasChanged ? Em.I18n.t('dashboard.configHistory.info-bar.save.popup.notesForPasswordChange') : '',
-          placeholder: Em.I18n.t('dashboard.configHistory.info-bar.save.popup.placeholder'),
-          didInsertElement: function () {
-            if (this.get('value')) {
-              this.onChangeValue();
-            }
-          },
-          onChangeValue: function() {
-            this.get('parentView.parentView').set('serviceConfigNote', this.get('value'));
-          }.observes('value')
-        })
-      }),
-      footerClass: Em.View.extend({
-        templateName: require('templates/main/service/info/save_popup_footer')
-      }),
-      primary: Em.I18n.t('common.save'),
-      secondary: Em.I18n.t('common.cancel'),
-      onSave: function () {
-        var newVersionToBeCreated = App.ServiceConfigVersion.find().filterProperty('serviceName', self.get('serviceName')).get('length') + 1;
-        self.get('controller').setProperties({
-          saveConfigsFlag: true,
-          serviceConfigVersionNote: this.get('serviceConfigNote'),
-          preSelectedConfigVersion: Em.Object.create({
-            version: newVersionToBeCreated,
-            serviceName: self.get('displayedServiceVersion.serviceName'),
-            groupName: self.get('controller.selectedConfigGroup.name')
-          })
-        });
-        self.get('controller').saveStepConfigs();
-        this.hide();
-      },
-      onDiscard: function () {
-        this.hide();
-        self.set('controller.preSelectedConfigVersion', null);
-        self.get('controller').loadStep();
-      },
-      onCancel: function () {
-        this.hide();
-      }
-    });
-  },
-  /**
-   * move back to the later service version
-   */
-  shiftBack: function () {
-    if (!this.get('showLeftArrow')) return;
-    this.decrementProperty('startIndex');
-    this.adjustFlowView();
-  },
-  /**
-   * move forward to the previous service version
-   */
-  shiftForward: function () {
-    if (!this.get('showRightArrow')) return;
-    this.incrementProperty('startIndex');
-    this.adjustFlowView();
-  },
-  /**
-   * shift flow view to position where selected version is visible
-   * @param versionIndex
-   */
-  shiftFlowOnSwitch: function (versionIndex) {
-    var serviceVersions = this.get('serviceVersions');
-
-    if ((this.get('startIndex') + this.VERSIONS_IN_FLOW) < versionIndex || versionIndex < this.get('startIndex')) {
-      versionIndex = (serviceVersions.length < (versionIndex + this.VERSIONS_IN_FLOW)) ? serviceVersions.length - this.VERSIONS_IN_FLOW : versionIndex;
-      this.set('startIndex', versionIndex);
-      this.adjustFlowView();
-    }
-  }
-});
-
-App.ConfigsServiceVersionBoxView = Em.View.extend({
-
-  /**
-   * bound from template
-   */
-  serviceVersion: null,
-
-  actionTypesBinding: 'parentView.actionTypes',
-
-  disabledActionAttr: Em.computed.alias('serviceVersion.disabledActionAttr'),
-
-  disabledActionMessages: Em.computed.alias('serviceVersion.disabledActionMessages'),
-
-  templateName: require('templates/common/configs/service_version_box'),
-
-  didInsertElement: function () {
-    this._super();
-    this.$('.version-box').hoverIntent(function() {
-      $(this).find('.version-popover').delay(700).fadeIn(200).end();
-    }, function() {
-      $(this).find('.version-popover').stop().fadeOut(200).end();
-    });
-    App.tooltip(this.$('[data-toggle=tooltip]'), {
-      placement: 'bottom'
-    });
-    App.tooltip(this.$('[data-toggle=arrow-tooltip]'), {
-      placement: 'top'
-    });
-  },
-
-  willDestroyElement: function() {
-    this.$('.version-box').off();
-    this.$('[data-toggle=tooltip]').tooltip('destroy');
-    this.$('[data-toggle=arrow-tooltip]').tooltip('destroy');
-  }
-});
-
-App.ConfigHistoryDropdownRowView = Em.View.extend({
-
-  templateName: require('templates/common/configs/config_history_dropdown_row'),
-
-  tagName: "li",
-
-  classNameBindings: [':pointer', ':dropdown-submenu', 'isDisplayed:not-allowed'],
-
-  serviceVersion: null,
-
-  isDisplayed: function() {
-    var serviceVersion = this.get('serviceVersion');
-    if(serviceVersion) {
-      return serviceVersion.get('isDisplayed');
-    }
-    return false;
-  }.property('serviceVersion'),
-
-  actionTypesBinding: 'parentView.actionTypes',
-
-  doAction: function(event) {
-    this.get('parentView').doAction(event);
-  },
-
-  eventManager: Ember.Object.create({
-    mouseEnter: function(event, view) {
-      var serviceVersion = view.get('serviceVersion');
-      var version = serviceVersion.get('version');
-      var $el = $('#config_version_popup');
-      var $currentTarget = $(event.currentTarget);
-      var parentView = view.get('parentView');
-      parentView.set('hoveredServiceVersion', null);
-      if (!serviceVersion.get("isDisplayed"))  {
-        parentView.set('hoveredServiceVersion', serviceVersion);
-        parentView.set('isHovered', true);
-        var elHeight = $el.outerHeight(),
-          pagePosition = window.innerHeight + window.pageYOffset,
-          elBottomPosition = $currentTarget[0].getBoundingClientRect().top + elHeight,
-          shouldShowUp = elBottomPosition > pagePosition;
-        $el.css({
-          "position": "fixed",
-          "top": $currentTarget[0].getBoundingClientRect().top,
-          "left": $currentTarget[0].getBoundingClientRect().left + 400,
-          "margin-top": -(elHeight/3),
-          "display": "block"
-        });
-        if (shouldShowUp) {
-          $el.css('margin-top', -(elHeight - $currentTarget.outerHeight()));
-        }
-      }
-      $el = null;
-    },
-    mouseLeave: function(event, view) {
-      var parentView = view.get('parentView');
-      parentView.set('isHovered', false);
-      Em.run.later(function() {
-        if(!parentView.get('displaySubMenuFlag') && !parentView.get('isHovered')) {
-          $('#config_version_popup').removeAttr('style');
-        }
-      }, 200);
-    }
-  })
-});
-
-App.ConfigHistoryDropdownSubMenuView = Em.View.extend({
-
-  tagName: 'ul',
-
-  classNameBindings: [':dropdown-menu', ':version-info-operations'],
-
-  eventManager: Ember.Object.create({
-    mouseEnter: function(event, view) {
-      view.get('parentView').set('displaySubMenuFlag', true);
-    },
-    mouseLeave: function(event, view) {
-      var parentView = view.get('parentView');
-      parentView.set('displaySubMenuFlag', false);
-      $("#config_version_popup").removeAttr('style');
-    }
-  })
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/2e9c9646/ambari-web/app/views/common/configs/config_versions_control_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/configs/config_versions_control_view.js b/ambari-web/app/views/common/configs/config_versions_control_view.js
new file mode 100644
index 0000000..d5f8807
--- /dev/null
+++ b/ambari-web/app/views/common/configs/config_versions_control_view.js
@@ -0,0 +1,235 @@
+/**
+ * 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.
+ */
+
+var App = require('app');
+
+App.ConfigVersionsControlView = Em.View.extend({
+  templateName: require('templates/common/configs/config_versions_control'),
+
+  serviceName: Em.computed.alias('controller.content.serviceName'),
+
+  /**
+   * @type {?App.ServiceConfigVersion}
+   */
+  compareServiceVersion: null,
+
+  displayedServiceVersion: Em.computed.findBy('serviceVersions', 'isDisplayed', true),
+
+  isCompareMode: Em.computed.notEqual('compareServiceVersion', null),
+
+  allServiceVersions: function() {
+    return App.ServiceConfigVersion.find().filterProperty('serviceName', this.get('serviceName'));
+  }.property('serviceName'),
+
+  serviceVersions: function () {
+    const isDefaultGroupSelected = this.get('controller.selectedConfigGroup.isDefault');
+    const groupId = this.get('controller.selectedConfigGroup.id');
+
+    this.get('allServiceVersions').forEach(function (version) {
+      version.set('isDisabled', !(version.get('groupId') === groupId || isDefaultGroupSelected && version.get('groupName') === App.ServiceConfigGroup.defaultGroupName));
+    }, this);
+
+    const serviceVersions = this.get('allServiceVersions').filter(function(s) {
+      return s.get('groupId') === groupId || s.get('groupName') === App.ServiceConfigGroup.defaultGroupName;
+    });
+
+    if (!serviceVersions.findProperty('isDisplayed')) {
+      //recompute serviceVersions if displayed version absent
+      Em.run.next(() => this.propertyDidChange('controller.selectedConfigGroup.name'));
+    }
+
+    return serviceVersions.sort(function (a, b) {
+      return Em.get(b, 'createTime') - Em.get(a, 'createTime');
+    });
+  }.property('serviceName', 'controller.selectedConfigGroup.name'),
+
+  primaryServiceVersionsInCompare: function() {
+    return this.get('serviceVersions').filter((sv) => sv.get('version') !== this.get('compareServiceVersion.version'));
+  }.property('serviceVersions', 'compareServiceVersion'),
+
+  secondaryServiceVersionsInCompare: function() {
+    if (this.get('compareServiceVersion')) {
+      return this.get('serviceVersions')
+        .filter((serviceVersion) => !serviceVersion.get('isDisplayed'))
+        .map((serviceVersion) => {
+        const copy = Em.Object.create({
+          version: serviceVersion.get('version'),
+          stackVersion: serviceVersion.get('stackVersion'),
+          authorFormatted: serviceVersion.get('authorFormatted'),
+          createdDate: serviceVersion.get('createdDate'),
+          fullNotes: serviceVersion.get('fullNotes'),
+          isCurrent: serviceVersion.get('isCurrent'),
+        });
+        copy.set('isDisplayed', serviceVersion.get('version') === this.get('compareServiceVersion.version'));
+        return copy;
+      });
+    } else {
+      return [];
+    }
+  }.property('serviceVersions', 'compareServiceVersion'),
+
+  willInsertElement: function () {
+    this.setDisplayVersion();
+  },
+
+  setDisplayVersion: function () {
+    const serviceVersions = this.get('serviceVersions');
+    const selectedVersion = this.get('controller.selectedVersion');
+    serviceVersions.forEach(function (serviceVersion) {
+      serviceVersion.set('isDisplayed', selectedVersion === serviceVersion.get('version'));
+    });
+    this.set('controller.displayedVersion', this.get('serviceVersions').findProperty('isDisplayed'));
+  },
+
+  onChangeConfigGroup: function () {
+    const serviceVersions = this.get('serviceVersions');
+    const selectedGroupName = this.get('controller.selectedConfigGroup.name');
+    const preselectedVersion = this.get('controller.selectedVersion');
+
+    serviceVersions.forEach(function (serviceVersion) {
+      const isSelected = serviceVersion.get('version') === preselectedVersion && serviceVersion.get('groupName') === selectedGroupName;
+      serviceVersion.set('isDisplayed', isSelected);
+    });
+
+    if (!serviceVersions.someProperty('isDisplayed')) {
+      serviceVersions.forEach(function (serviceVersion) {
+        if (serviceVersion.get('isCurrent') && serviceVersion.get('groupName') === selectedGroupName) {
+          serviceVersion.set('isDisplayed', true);
+        }
+      });
+    }
+  }.observes('controller.selectedConfigGroup'),
+
+  /**
+   * switch configs view version to chosen
+   */
+  switchVersion: function (event) {
+    const version = event.contexts[0];
+    if (this.get('serviceVersions').filterProperty('isDisplayed').someProperty('version', version)) {
+      return;
+    }
+
+    this.get('serviceVersions').forEach(function (serviceVersion) {
+      serviceVersion.set('isDisplayed', serviceVersion.get('version') === version);
+    });
+    this.get('controller').loadSelectedVersion(version);
+    this.set('controller.displayedVersion', this.get('serviceVersions').findProperty('isDisplayed'));
+  },
+
+  switchPrimaryInCompare: function(event) {
+    this.switchVersion({contexts: [event.contexts[0].get('version')]});
+    this.set('controller.compareServiceVersion', this.get('compareServiceVersion'));
+  },
+
+  /**
+   * add config values of chosen version to view for comparison
+   * add a second version-info-bar for the chosen version
+   */
+  compare: function (event) {
+    const serviceConfigVersion = event.contexts[0];
+    this.set('controller.compareServiceVersion', serviceConfigVersion);
+    this.set('compareServiceVersion', serviceConfigVersion);
+
+    const controller = this.get('controller');
+    controller.get('stepConfigs').clear();
+    controller.loadCompareVersionConfigs(controller.get('allConfigs')).done(function() {
+      controller.onLoadOverrides(controller.get('allConfigs'));
+    });
+  },
+
+  removeCompareVersionBar: function () {
+    const displayedVersion = this.get('displayedServiceVersion.version');
+
+    this.set('compareServiceVersion', null);
+    this.set('controller.compareServiceVersion', null);
+    this.get('serviceVersions').forEach(function (serviceVersion) {
+      serviceVersion.set('isDisplayed', serviceVersion.get('version') === displayedVersion);
+    });
+    this.get('controller').loadSelectedVersion(displayedVersion);
+  },
+
+  /**
+   * revert config values to chosen version and apply reverted configs to server
+   */
+  makeCurrent: function (event) {
+    const self = this;
+    const serviceConfigVersion = event.contexts[0];
+    const versionText = serviceConfigVersion.get('versionText');
+    return App.ModalPopup.show({
+      header: Em.I18n.t('dashboard.configHistory.info-bar.makeCurrent.popup.title'),
+      serviceConfigNote: Em.I18n.t('services.service.config.configHistory.makeCurrent.message').format(versionText),
+      bodyClass: Em.View.extend({
+        templateName: require('templates/common/configs/save_configuration'),
+        classNames: ['col-md-12'],
+        notesArea: Em.TextArea.extend({
+          classNames: ['full-width'],
+          value: Em.I18n.t('services.service.config.configHistory.makeCurrent.message').format(versionText),
+          onChangeValue: function() {
+            this.get('parentView.parentView').set('serviceConfigNote', this.get('value'));
+          }.observes('value')
+        })
+      }),
+      primary: Em.I18n.t('dashboard.configHistory.info-bar.revert.button'),
+      secondary: Em.I18n.t('common.discard'),
+      third: Em.I18n.t('common.cancel'),
+      onPrimary: function () {
+        serviceConfigVersion.set('serviceConfigNote', this.get('serviceConfigNote'));
+        self.sendRevertCall(serviceConfigVersion);
+        this.hide();
+      },
+      onSecondary: function () {
+        // force <code>serviceVersions</code> recalculating
+        self.propertyDidChange('controller.selectedConfigGroup.name');
+        this._super();
+      },
+      onThird: function () {
+        this.onSecondary();
+      }
+    });
+  },
+
+  /**
+   * send PUT call to revert config to selected version
+   * @param serviceConfigVersion
+   */
+  sendRevertCall: function (serviceConfigVersion) {
+    App.ajax.send({
+      name: 'service.serviceConfigVersion.revert',
+      sender: this,
+      data: {
+        data: {
+          "Clusters": {
+            "desired_service_config_versions": {
+              "service_config_version": serviceConfigVersion.get('version'),
+              "service_name": serviceConfigVersion.get('serviceName'),
+              "service_config_version_note": serviceConfigVersion.get('serviceConfigNote')
+            }
+          }
+        }
+      },
+      success: 'sendRevertCallSuccess'
+    });
+  },
+
+  sendRevertCallSuccess: function (data, opt, params) {
+    // revert to an old version would generate a new version with latest version number,
+    // so, need to loadStep to update
+    App.router.get('updateController').updateComponentConfig(Em.K);
+    this.get('controller').loadStep();
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/2e9c9646/ambari-web/app/views/common/configs/config_versions_dropdown_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/configs/config_versions_dropdown_view.js b/ambari-web/app/views/common/configs/config_versions_dropdown_view.js
new file mode 100644
index 0000000..8e5cb76
--- /dev/null
+++ b/ambari-web/app/views/common/configs/config_versions_dropdown_view.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.
+ */
+
+var App = require('app');
+
+App.ConfigVersionsDropdownView = Em.View.extend({
+  templateName: require('templates/common/configs/config_versions_dropdown'),
+  classNames: ['btn-group'],
+
+  searchLabel: Em.I18n.t('common.search'),
+
+  /**
+   * if true then it's secondary dropdown in Compare Mode
+   * @type {boolean}
+   */
+  isSecondary: false,
+  serviceVersions: [],
+  filterValue: '',
+  isCompareMode: false,
+  displayedServiceVersion: Em.computed.findBy('serviceVersions', 'isDisplayed', true),
+
+  mainClickAction: function (event) {
+    if (this.get('isSecondary')) {
+      this.get('parentView').compare(event);
+    } else {
+      this.get('parentView').switchPrimaryInCompare(event);
+    }
+  },
+
+  filteredServiceVersions: function() {
+    return this.get('serviceVersions').filter((serviceVersion) => {
+      if (!this.get('filterValue').trim()) return true;
+      const searchString = Em.I18n.t('common.version') + ' ' + serviceVersion.get('version') + ' ' + serviceVersion.get('notes');
+      return searchString.indexOf(this.get('filterValue').trim()) !== -1;
+    });
+  }.property('serviceVersions.length', 'filterValue')
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/2e9c9646/ambari-web/app/views/common/configs/service_config_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/configs/service_config_view.js b/ambari-web/app/views/common/configs/service_config_view.js
index fe45c79..50f7418 100644
--- a/ambari-web/app/views/common/configs/service_config_view.js
+++ b/ambari-web/app/views/common/configs/service_config_view.js
@@ -24,6 +24,10 @@ App.ServiceConfigView = Em.View.extend({
 
   isRestartMessageCollapsed: false,
 
+  isDiscardDisabled: Em.computed.or('!controller.versionLoaded', '!controller.isPropertiesChanged'),
+
+  isSaveDisabled: Em.computed.or('controller.isSubmitDisabled', '!controller.versionLoaded', '!controller.isPropertiesChanged'),
+
   /**
    * Bound from parent view in the template
    * @type {string}
@@ -58,6 +62,10 @@ App.ServiceConfigView = Em.View.extend({
     }
   }.property('controller.name', 'controller.selectedService'),
 
+  showSavePanel: function() {
+    return this.get('isOnTheServicePage') && !this.get('controller.isCompareMode') && this.get('controller.displayedVersion.isCurrent');
+  }.property('isOnTheServicePage', 'controller.isCompareMode', 'controller.displayedVersion.isCurrent'),
+
   /**
    * Determines if user is on the service configs page
    * @type {boolean}
@@ -83,6 +91,64 @@ App.ServiceConfigView = Em.View.extend({
   }.observes('controller.selectedService.configs.@each.isHiddenByFilter'),
 
   /**
+   * save configuration
+   * @return {object}
+   */
+  save: function () {
+    var self = this;
+    var passwordWasChanged = this.get('controller.passwordConfigsAreChanged');
+    return App.ModalPopup.show({
+      header: Em.I18n.t('dashboard.configHistory.info-bar.save.popup.title'),
+      serviceConfigNote: '',
+      bodyClass: Em.View.extend({
+        templateName: require('templates/common/configs/save_configuration'),
+        classNames: ['col-md-12'],
+        showPasswordChangeWarning: passwordWasChanged,
+        notesArea: Em.TextArea.extend({
+          classNames: ['full-width'],
+          value: passwordWasChanged ? Em.I18n.t('dashboard.configHistory.info-bar.save.popup.notesForPasswordChange') : '',
+          placeholder: Em.I18n.t('dashboard.configHistory.info-bar.save.popup.placeholder'),
+          didInsertElement: function () {
+            if (this.get('value')) {
+              this.onChangeValue();
+            }
+          },
+          onChangeValue: function() {
+            this.get('parentView.parentView').set('serviceConfigNote', this.get('value'));
+          }.observes('value')
+        })
+      }),
+      footerClass: Em.View.extend({
+        templateName: require('templates/main/service/info/save_popup_footer')
+      }),
+      primary: Em.I18n.t('common.save'),
+      secondary: Em.I18n.t('common.cancel'),
+      onSave: function () {
+        var newVersionToBeCreated = App.ServiceConfigVersion.find().filterProperty('serviceName', self.get('serviceName')).get('length') + 1;
+        self.get('controller').setProperties({
+          saveConfigsFlag: true,
+          serviceConfigVersionNote: this.get('serviceConfigNote'),
+          preSelectedConfigVersion: Em.Object.create({
+            version: newVersionToBeCreated,
+            serviceName: self.get('controller.content.serviceName'),
+            groupName: self.get('controller.selectedConfigGroup.name')
+          })
+        });
+        self.get('controller').saveStepConfigs();
+        this.hide();
+      },
+      onDiscard: function () {
+        this.hide();
+        self.set('controller.preSelectedConfigVersion', null);
+        self.get('controller').loadStep();
+      },
+      onCancel: function () {
+        this.hide();
+      }
+    });
+  },
+
+  /**
    * updates filter counters for advanced tab
    * @method updateFilterCounters
    */


Mime
View raw message