You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ak...@apache.org on 2015/09/23 05:39:03 UTC

[1/2] ignite git commit: IGNITE-843 Reworked unsaved changes detection.

Repository: ignite
Updated Branches:
  refs/heads/ignite-843 a17b30f94 -> 7ab85d541


IGNITE-843 Reworked unsaved changes detection.


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/708a891a
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/708a891a
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/708a891a

Branch: refs/heads/ignite-843
Commit: 708a891ab3af23099a79ff7ca765a02f1d307cf9
Parents: 3f26e32
Author: Alexey Kuznetsov <ak...@apache.org>
Authored: Wed Sep 23 10:38:34 2015 +0700
Committer: Alexey Kuznetsov <ak...@apache.org>
Committed: Wed Sep 23 10:38:34 2015 +0700

----------------------------------------------------------------------
 .../src/main/js/controllers/admin-controller.js |  36 ++--
 .../main/js/controllers/caches-controller.js    | 114 +++++-------
 .../main/js/controllers/clusters-controller.js  | 112 +++++------
 .../src/main/js/controllers/common-module.js    | 185 ++++++++++---------
 .../main/js/controllers/metadata-controller.js  | 125 ++++++-------
 .../main/js/controllers/profile-controller.js   |  10 +-
 .../src/main/js/controllers/sql-controller.js   |  35 ++--
 .../control-center-web/src/main/js/package.json |  14 +-
 .../src/main/js/views/configuration/caches.jade |   2 +-
 .../main/js/views/configuration/clusters.jade   |   2 +-
 .../main/js/views/configuration/metadata.jade   |   2 +-
 .../src/main/js/views/includes/controls.jade    |  14 +-
 .../src/main/js/views/sql/sql.jade              |   9 +-
 .../src/main/js/views/templates/confirm.jade    |   6 +-
 .../src/main/js/views/templates/layout.jade     |   8 +-
 15 files changed, 314 insertions(+), 360 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/708a891a/modules/control-center-web/src/main/js/controllers/admin-controller.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/controllers/admin-controller.js b/modules/control-center-web/src/main/js/controllers/admin-controller.js
index 5e0dc46..76cca9f 100644
--- a/modules/control-center-web/src/main/js/controllers/admin-controller.js
+++ b/modules/control-center-web/src/main/js/controllers/admin-controller.js
@@ -16,7 +16,8 @@
  */
 
 // Controller for Admin screen.
-controlCenterModule.controller('adminController', ['$scope', '$window', '$http', '$common', '$confirm',
+controlCenterModule.controller('adminController',
+    ['$scope', '$window', '$http', '$common', '$confirm',
     function ($scope, $window, $http, $common, $confirm) {
     $scope.users = null;
 
@@ -37,24 +38,25 @@ controlCenterModule.controller('adminController', ['$scope', '$window', '$http',
     };
 
     $scope.removeUser = function (user) {
-        $confirm.confirm('Are you sure you want to remove user: "' + user.username + '"?').then(function () {
-            $http.post('admin/remove', {userId: user._id}).success(
-                function () {
-                    var i = _.findIndex($scope.users, function (u) {
-                        return u._id == user._id;
-                    });
+        $confirm.confirm('Are you sure you want to remove user: "' + user.username + '"?')
+            .then(function () {
+                $http.post('admin/remove', {userId: user._id}).success(
+                    function () {
+                        var i = _.findIndex($scope.users, function (u) {
+                            return u._id == user._id;
+                        });
 
-                    if (i >= 0)
-                        $scope.users.splice(i, 1);
+                        if (i >= 0)
+                            $scope.users.splice(i, 1);
 
-                    $common.showInfo('User has been removed: "' + user.username + '"');
-                }).error(function (errMsg, status) {
-                    if (status == 503)
-                        $common.showInfo(errMsg);
-                    else
-                        $common.showError('Failed to remove user: "' + $common.errorMessage(errMsg) + '"');
-                });
-        });
+                        $common.showInfo('User has been removed: "' + user.username + '"');
+                    }).error(function (errMsg, status) {
+                        if (status == 503)
+                            $common.showInfo(errMsg);
+                        else
+                            $common.showError('Failed to remove user: "' + $common.errorMessage(errMsg) + '"');
+                    });
+            });
     };
 
     $scope.toggleAdmin = function (user) {

http://git-wip-us.apache.org/repos/asf/ignite/blob/708a891a/modules/control-center-web/src/main/js/controllers/caches-controller.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/controllers/caches-controller.js b/modules/control-center-web/src/main/js/controllers/caches-controller.js
index 1f22e37..06b01f6 100644
--- a/modules/control-center-web/src/main/js/controllers/caches-controller.js
+++ b/modules/control-center-web/src/main/js/controllers/caches-controller.js
@@ -17,12 +17,14 @@
 
 // Controller for Caches screen.
 controlCenterModule.controller('cachesController', [
-        '$scope', '$controller', '$http', '$timeout', '$common', '$focus', '$confirm', '$copy', '$table', '$preview', '$loading',
-        function ($scope, $controller, $http, $timeout, $common, $focus, $confirm, $copy, $table, $preview, $loading) {
+        '$scope', '$controller', '$http', '$timeout', '$common', '$focus', '$confirm', '$clone', '$table', '$preview', '$loading', '$unsavedChangesGuard',
+        function ($scope, $controller, $http, $timeout, $common, $focus, $confirm, $clone, $table, $preview, $loading, $unsavedChangesGuard) {
+            $unsavedChangesGuard.install($scope);
+
             // Initialize the super class and extend it.
             angular.extend(this, $controller('save-remove', {$scope: $scope}));
 
-            $scope.ui = $common.formUI(2);
+            $scope.ui = $common.formUI();
 
             $scope.joinTip = $common.joinTip;
             $scope.getModel = $common.getModel;
@@ -37,8 +39,6 @@ controlCenterModule.controller('cachesController', [
             $scope.tableStartEdit = $table.tableStartEdit;
             $scope.tableRemove = function (item, field, index) {
                 $table.tableRemove(item, field, index);
-
-                $scope.ui.markDirty();
             };
 
             $scope.tableSimpleSave = $table.tableSimpleSave;
@@ -245,6 +245,8 @@ controlCenterModule.controller('cachesController', [
                             $scope.general = data.general;
                             $scope.advanced = data.advanced;
 
+                            $scope.ui.addGroups(data.general, data.advanced);
+
                             if ($common.getQueryVariable('new'))
                                 $scope.createItem();
                             else {
@@ -268,12 +270,12 @@ controlCenterModule.controller('cachesController', [
                                     selectFirstItem();
                             }
 
-                            $timeout(function() {
-                                $scope.ui.markPristineHard();
-                            });
-
                             $scope.$watch('backupItem', function (val) {
                                 if (val) {
+                                    var srcItem = $scope.selectedItem ? $scope.selectedItem : prepareNewItem();
+
+                                    $scope.ui.checkDirty(val, srcItem);
+
                                     var metas = cacheMetadatas(val);
                                     var varName = $commonUtils.toJavaName('cache', val.name);
 
@@ -308,8 +310,6 @@ controlCenterModule.controller('cachesController', [
                                     $scope.preview.statistics.xml = $generatorXml.cacheStatistics(val).asString();
                                     $scope.preview.statistics.java = $generatorJava.cacheStatistics(val, varName).asString();
                                     $scope.preview.statistics.allDefaults = $common.isEmptyString($scope.preview.statistics.xml);
-
-                                    $scope.ui.markDirty();
                                 }
                             }, true);
 
@@ -369,8 +369,6 @@ controlCenterModule.controller('cachesController', [
                         $scope.backupItem = angular.copy(item);
                     else
                         $scope.backupItem = undefined;
-
-                    $scope.ui.markPristine(2);
                 }
 
                 $common.confirmUnsavedChanges($scope.ui.isDirty(), selectItem);
@@ -388,7 +386,7 @@ controlCenterModule.controller('cachesController', [
                     copyOnRead: true,
                     clusters: [],
                     metadatas: []
-                };
+                }
             }
 
             // Add new cache.
@@ -466,7 +464,7 @@ controlCenterModule.controller('cachesController', [
             function save(item) {
                 $http.post('caches/save', item)
                     .success(function (_id) {
-                        $scope.ui.markPristine(0);
+                        $scope.ui.markPristine();
 
                         var idx = _.findIndex($scope.caches, function (cache) {
                             return cache._id == _id;
@@ -479,7 +477,6 @@ controlCenterModule.controller('cachesController', [
 
                             $scope.caches.push(item);
                             $scope.selectItem(item);
-                            $scope.ui.markPristine(1);
                         }
 
                         $common.showInfo('Cache "' + item.name + '" saved.');
@@ -504,7 +501,7 @@ controlCenterModule.controller('cachesController', [
                 $table.tableReset();
 
                 if (validate($scope.backupItem))
-                    $copy.confirm($scope.backupItem.name).then(function (newName) {
+                    $clone.confirm($scope.backupItem.name).then(function (newName) {
                         var item = angular.copy($scope.backupItem);
 
                         item._id = undefined;
@@ -520,68 +517,53 @@ controlCenterModule.controller('cachesController', [
 
                 var selectedItem = $scope.selectedItem;
 
-                $confirm.confirm('Are you sure you want to remove cache: "' + selectedItem.name + '"?').then(
-                    function () {
-                        $scope.ui.markPristine(0);
-
-                        var _id = selectedItem._id;
+                $confirm.confirm('Are you sure you want to remove cache: "' + selectedItem.name + '"?')
+                    .then(function () {
+                            var _id = selectedItem._id;
 
-                        $http.post('caches/remove', {_id: _id})
-                            .success(function () {
-                                $common.showInfo('Cache has been removed: ' + selectedItem.name);
+                            $http.post('caches/remove', {_id: _id})
+                                .success(function () {
+                                    $common.showInfo('Cache has been removed: ' + selectedItem.name);
 
-                                var caches = $scope.caches;
+                                    var caches = $scope.caches;
 
-                                var idx = _.findIndex(caches, function (cache) {
-                                    return cache._id == _id;
-                                });
+                                    var idx = _.findIndex(caches, function (cache) {
+                                        return cache._id == _id;
+                                    });
 
-                                if (idx >= 0) {
-                                    caches.splice(idx, 1);
+                                    if (idx >= 0) {
+                                        caches.splice(idx, 1);
 
-                                    if (caches.length > 0)
-                                        $scope.selectItem(caches[0]);
-                                    else
-                                        $scope.selectItem(undefined, undefined);
-                                }
-                            })
-                            .error(function (errMsg) {
-                                $common.showError(errMsg);
-                            });
-                    }
-                );
+                                        if (caches.length > 0)
+                                            $scope.selectItem(caches[0]);
+                                        else
+                                            $scope.selectItem(undefined, undefined);
+                                    }
+                                })
+                                .error(function (errMsg) {
+                                    $common.showError(errMsg);
+                                });
+                    });
             };
 
             // Remove all caches from db.
             $scope.removeAllItems = function () {
                 $table.tableReset();
 
-                $confirm.confirm('Are you sure you want to remove all caches?').then(
-                    function () {
-                        $scope.ui.markPristine(0);
-
-                        $http.post('caches/remove/all')
-                            .success(function () {
-                                $common.showInfo('All caches have been removed');
+                $confirm.confirm('Are you sure you want to remove all caches?')
+                    .then(function () {
+                            $http.post('caches/remove/all')
+                                .success(function () {
+                                    $common.showInfo('All caches have been removed');
 
-                                $scope.caches = [];
-
-                                $scope.selectItem(undefined, undefined);
-                            })
-                            .error(function (errMsg) {
-                                $common.showError(errMsg);
-                            });
-                    }
-                );
-            };
+                                    $scope.caches = [];
 
-            $scope.resetItemVisible = function (group) {
-                var resetTo = $scope.selectedItem;
-
-                if (!$common.isDefined(resetTo))
-                    resetTo = prepareNewItem();
-
-                return $common.resetItemVisible(group, $scope.backupItem, resetTo);
+                                    $scope.selectItem(undefined, undefined);
+                                })
+                                .error(function (errMsg) {
+                                    $common.showError(errMsg);
+                                });
+                    });
             };
 
             $scope.resetItem = function (group) {

http://git-wip-us.apache.org/repos/asf/ignite/blob/708a891a/modules/control-center-web/src/main/js/controllers/clusters-controller.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/controllers/clusters-controller.js b/modules/control-center-web/src/main/js/controllers/clusters-controller.js
index 217fdf8..3ae80f6 100644
--- a/modules/control-center-web/src/main/js/controllers/clusters-controller.js
+++ b/modules/control-center-web/src/main/js/controllers/clusters-controller.js
@@ -16,12 +16,15 @@
  */
 
 // Controller for Clusters screen.
-controlCenterModule.controller('clustersController', ['$scope', '$controller', '$http', '$timeout', '$common', '$focus', '$confirm', '$copy', '$table', '$preview', '$loading',
-    function ($scope, $controller, $http, $timeout, $common, $focus, $confirm, $copy, $table, $preview, $loading) {
+controlCenterModule.controller('clustersController', [
+    '$scope', '$controller', '$http', '$timeout', '$common', '$focus', '$confirm', '$clone', '$table', '$preview', '$loading', '$unsavedChangesGuard',
+    function ($scope, $controller, $http, $timeout, $common, $focus, $confirm, $clone, $table, $preview, $loading, $unsavedChangesGuard) {
+        $unsavedChangesGuard.install($scope);
+
         // Initialize the super class and extend it.
         angular.extend(this, $controller('save-remove', {$scope: $scope}));
 
-        $scope.ui = $common.formUI(2);
+        $scope.ui = $common.formUI();
 
         $scope.joinTip = $common.joinTip;
         $scope.getModel = $common.getModel;
@@ -35,8 +38,6 @@ controlCenterModule.controller('clustersController', ['$scope', '$controller', '
         $scope.tableStartEdit = $table.tableStartEdit;
         $scope.tableRemove = function (item, field, index) {
             $table.tableRemove(item, field, index);
-
-            $scope.ui.markDirty();
         };
 
         $scope.tableSimpleSave = $table.tableSimpleSave;
@@ -170,6 +171,7 @@ controlCenterModule.controller('clustersController', ['$scope', '$controller', '
                         $scope.general = data.general;
                         $scope.advanced = data.advanced;
 
+                        $scope.ui.addGroups(data.general, data.advanced);
 
                         if ($common.getQueryVariable('new'))
                             $scope.createItem();
@@ -193,10 +195,6 @@ controlCenterModule.controller('clustersController', ['$scope', '$controller', '
                                 selectFirstItem();
                         }
 
-                        $timeout(function() {
-                            $scope.ui.markPristineHard();
-                        });
-
                         $scope.$watch('backupItem', function (val) {
                             if (val) {
                                 var clusterCaches = _.reduce($scope.caches, function(caches, cache){
@@ -207,6 +205,10 @@ controlCenterModule.controller('clustersController', ['$scope', '$controller', '
                                     return caches;
                                 }, []);
 
+                                var srcItem = $scope.selectedItem ? $scope.selectedItem : prepareNewItem();
+
+                                $scope.ui.checkDirty(val, srcItem);
+
                                 $scope.preview.general.xml = $generatorXml.clusterCaches(clusterCaches, $generatorXml.clusterGeneral(val)).asString();
                                 $scope.preview.general.java = $generatorJava.clusterCaches(clusterCaches, $generatorJava.clusterGeneral(val)).asString();
                                 $scope.preview.general.allDefaults = $common.isEmptyString($scope.preview.general.xml);
@@ -254,8 +256,6 @@ controlCenterModule.controller('clustersController', ['$scope', '$controller', '
                                 $scope.preview.transactions.xml = $generatorXml.clusterTransactions(val).asString();
                                 $scope.preview.transactions.java = $generatorJava.clusterTransactions(val).asString();
                                 $scope.preview.transactions.allDefaults = $common.isEmptyString($scope.preview.transactions.xml);
-
-                                $scope.ui.markDirty();
                             }
                         }, true);
                     })
@@ -292,8 +292,6 @@ controlCenterModule.controller('clustersController', ['$scope', '$controller', '
                     $scope.backupItem = angular.copy(item);
                 else
                     $scope.backupItem = undefined;
-
-                $scope.ui.markPristine(2);
             }
 
             $common.confirmUnsavedChanges($scope.ui.isDirty(), selectItem);
@@ -388,7 +386,7 @@ controlCenterModule.controller('clustersController', ['$scope', '$controller', '
         function save(item) {
             $http.post('clusters/save', item)
                 .success(function (_id) {
-                    $scope.ui.markPristine(0);
+                    $scope.ui.markPristine();
 
                     var idx = _.findIndex($scope.clusters, function (cluster) {
                         return cluster._id == _id;
@@ -401,7 +399,6 @@ controlCenterModule.controller('clustersController', ['$scope', '$controller', '
 
                         $scope.clusters.push(item);
                         $scope.selectItem(item);
-                        $scope.ui.markPristine(1);
                     }
 
                     $common.showInfo('Cluster "' + item.name + '" saved.');
@@ -426,7 +423,7 @@ controlCenterModule.controller('clustersController', ['$scope', '$controller', '
             $table.tableReset();
 
             if (validate($scope.backupItem))
-                $copy.confirm($scope.backupItem.name).then(function (newName) {
+                $clone.confirm($scope.backupItem.name).then(function (newName) {
                     var item = angular.copy($scope.backupItem);
 
                     item._id = undefined;
@@ -442,68 +439,53 @@ controlCenterModule.controller('clustersController', ['$scope', '$controller', '
 
             var selectedItem = $scope.selectedItem;
 
-            $confirm.confirm('Are you sure you want to remove cluster: "' + selectedItem.name + '"?').then(
-                function () {
-                    $scope.ui.markPristine(0);
+            $confirm.confirm('Are you sure you want to remove cluster: "' + selectedItem.name + '"?')
+                .then(function () {
+                        var _id = selectedItem._id;
 
-                    var _id = selectedItem._id;
+                        $http.post('clusters/remove', {_id: _id})
+                            .success(function () {
+                                $common.showInfo('Cluster has been removed: ' + selectedItem.name);
 
-                    $http.post('clusters/remove', {_id: _id})
-                        .success(function () {
-                            $common.showInfo('Cluster has been removed: ' + selectedItem.name);
+                                var clusters = $scope.clusters;
 
-                            var clusters = $scope.clusters;
-
-                            var idx = _.findIndex(clusters, function (cluster) {
-                                return cluster._id == _id;
-                            });
+                                var idx = _.findIndex(clusters, function (cluster) {
+                                    return cluster._id == _id;
+                                });
 
-                            if (idx >= 0) {
-                                clusters.splice(idx, 1);
+                                if (idx >= 0) {
+                                    clusters.splice(idx, 1);
 
-                                if (clusters.length > 0)
-                                    $scope.selectItem(clusters[0]);
-                                else
-                                    $scope.selectItem(undefined, undefined);
-                            }
-                        })
-                        .error(function (errMsg) {
-                            $common.showError(errMsg);
-                        });
-                }
-            );
+                                    if (clusters.length > 0)
+                                        $scope.selectItem(clusters[0]);
+                                    else
+                                        $scope.selectItem(undefined, undefined);
+                                }
+                            })
+                            .error(function (errMsg) {
+                                $common.showError(errMsg);
+                            });
+                });
         };
 
         // Remove all clusters from db.
         $scope.removeAllItems = function () {
             $table.tableReset();
 
-            $confirm.confirm('Are you sure you want to remove all clusters?').then(
-                function () {
-                    $scope.ui.markPristine(0);
+            $confirm.confirm('Are you sure you want to remove all clusters?')
+                .then(function () {
+                        $http.post('clusters/remove/all')
+                            .success(function () {
+                                $common.showInfo('All clusters have been removed');
 
-                    $http.post('clusters/remove/all')
-                        .success(function () {
-                            $common.showInfo('All clusters have been removed');
+                                $scope.clusters = [];
 
-                            $scope.clusters = [];
-
-                            $scope.selectItem(undefined, undefined);
-                        })
-                        .error(function (errMsg) {
-                            $common.showError(errMsg);
-                        });
-                }
-            );
-        };
-
-        $scope.resetItemVisible = function (group) {
-            var resetTo = $scope.selectedItem;
-
-            if (!$common.isDefined(resetTo))
-                resetTo = prepareNewItem();
-
-            return $common.resetItemVisible(group, $scope.backupItem, resetTo);
+                                $scope.selectItem(undefined, undefined);
+                            })
+                            .error(function (errMsg) {
+                                $common.showError(errMsg);
+                            });
+                });
         };
 
         $scope.resetItem = function (group) {

http://git-wip-us.apache.org/repos/asf/ignite/blob/708a891a/modules/control-center-web/src/main/js/controllers/common-module.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/controllers/common-module.js b/modules/control-center-web/src/main/js/controllers/common-module.js
index d90bb9b..709488b 100644
--- a/modules/control-center-web/src/main/js/controllers/common-module.js
+++ b/modules/control-center-web/src/main/js/controllers/common-module.js
@@ -15,7 +15,8 @@
  * limitations under the License.
  */
 
-var controlCenterModule = angular.module('ignite-web-control-center', ['ngAnimate', 'smart-table', 'mgcrea.ngStrap', 'ui.ace', 'ngSanitize', 'treeControl', 'unsavedChanges', 'darthwade.loading']);
+var controlCenterModule = angular.module('ignite-web-control-center',
+    ['ngAnimate', 'smart-table', 'mgcrea.ngStrap', 'ui.ace', 'ngSanitize', 'treeControl', 'darthwade.loading']);
 
 // Modal popup configuration.
 controlCenterModule.config(function ($modalProvider) {
@@ -75,12 +76,6 @@ controlCenterModule.config(function($modalProvider) {
     });
 });
 
-// Unsaved changes configuration.
-controlCenterModule.config(['unsavedWarningsConfigProvider', function(unsavedWarningsConfigProvider) {
-    unsavedWarningsConfigProvider.navigateMessage = 'Unsaved changes will be discarded.';
-    unsavedWarningsConfigProvider.reloadMessage = 'Unsaved changes will be discarded.';
-}]);
-
 // Common functions to be used in controllers.
 controlCenterModule.service('$common', [
     '$alert', '$popover', '$timeout', '$focus', '$window', function ($alert, $popover, $timeout, $focus, $window) {
@@ -517,16 +512,6 @@ controlCenterModule.service('$common', [
             return false;
         }
 
-        function markDirty (form) {
-            if (isDefined(form))
-                form.$setDirty();
-        }
-
-        function markPristine (form) {
-            if (isDefined(form))
-                form.$setPristine();
-        }
-
         function getModel(obj, field) {
             var path = field.path;
 
@@ -551,6 +536,47 @@ controlCenterModule.service('$common', [
             return root;
         }
 
+        function checkGroupDirty(group, curItem, srcItem) {
+            function _compareField(field) {
+                var curModel = getModel(curItem, field);
+                var srcModel = getModel(srcItem, field);
+
+                if (field.model == 'kind' && isDefined(curModel.kind)) {
+                    if (curModel.kind != srcModel.kind)
+                        return true;
+
+                    if (_compareFields(field.details[curModel.kind].fields))
+                        return true;
+                }
+
+                var curValue = curModel[field.model];
+                var srcValue = srcModel[field.model];
+
+                var isCur = isDefined(curValue);
+                var isSrc = isDefined(srcValue);
+
+                if ((isCur && !isSrc) || (!isCur && isSrc) || (isCur && isSrc && !angular.equals(curValue, srcValue)))
+                    return true;
+
+                return false;
+            }
+
+            function _compareFields(fields) {
+                for (var fldIx = 0; fldIx < fields.length; fldIx++) {
+                    var field = fields[fldIx];
+
+                    if (_compareField(field))
+                        return true;
+                }
+
+                return false;
+            }
+
+            group.dirty = _compareFields(group.fields);
+
+            return group.dirty;
+        }
+
         return {
             getModel: getModel,
             joinTip: function (arr) {
@@ -725,44 +751,6 @@ controlCenterModule.service('$common', [
 
                 document.body.removeChild(file);
             },
-            resetItemVisible: function (group, curItem, srcItem) {
-                function _compareField(field) {
-                    var curModel = getModel(curItem, field);
-                    var srcModel = getModel(srcItem, field);
-
-                    if (field.model == 'kind' && isDefined(curModel.kind)) {
-                        if (curModel.kind != srcModel.kind)
-                            return true;
-
-                        if (_compareFields(field.details[curModel.kind].fields))
-                            return true;
-                    }
-
-                    var curValue = curModel[field.model];
-                    var srcValue = srcModel[field.model];
-
-                    var isCur = isDefined(curValue);
-                    var isSrc = isDefined(srcValue);
-
-                    if ((isCur && !isSrc) || (!isCur && isSrc) || (isCur && isSrc && !_.isEqual(curValue, srcValue)))
-                        return true;
-
-                    return false;
-                }
-
-                function _compareFields(fields) {
-                    for (var fldIx = 0; fldIx < fields.length; fldIx++) {
-                        var field = fields[fldIx];
-
-                        if (_compareField(field))
-                            return true;
-                    }
-
-                    return false;
-                }
-
-                return _compareFields(group.fields);
-            },
             resetItem: function (backupItem, selectedItem, groups, group) {
                 function restoreFields(fields) {
                     // Reset fields by one.
@@ -814,39 +802,33 @@ controlCenterModule.service('$common', [
                     }
                 }
             },
-            formUI: function (initialDirtyCnt) {
+            formUI: function () {
                 return {
                     ready: false,
                     expanded: false,
-                    dirty: initialDirtyCnt,
-                    isDirty: function () {
-                        return this.dirty < 0;
-                    },
-                    markDirty: function () {
-                        this.dirty--;
+                    groups: [],
+                    addGroups: function (general, advanced) {
+                        if (general)
+                            $.merge(this.groups, general);
 
-                        if (isDefined(this.inputForm)) {
-                            if (this.dirty < 0)
-                                markDirty(this.inputForm);
-                            else
-                                markPristine(this.inputForm);
-                        }
+                        if (advanced)
+                            $.merge(this.groups, advanced);
                     },
-                    markPristineHard: function() {
-                        if (isDefined(this.inputForm))
-                            markPristine(this.inputForm);
+                    isDirty: function () {
+                        return _.findIndex(this.groups, function (group) {
+                            return group.dirty;
+                        }) >= 0;
                     },
-                    markPristine: function (dirtyCnt) {
-                        this.dirty = dirtyCnt;
-
-                        if (isDefined(this.inputForm))
-                            markPristine(this.inputForm);
+                    markPristine: function () {
+                        this.groups.forEach(function (group) {
+                            group.dirty = false;
+                        })
                     },
-                    noSubmit: function() {
-                        if (this.dirty < 0)
-                            markDirty(this.inputForm);
-                        else
-                            markPristine(this.inputForm);
+                    checkDirty: function(curItem, srcItem) {
+                        this.groups.forEach(function(group) {
+                            if (checkGroupDirty(group, curItem, srcItem))
+                                dirty = true;
+                        });
                     }
                 };
             },
@@ -874,19 +856,28 @@ controlCenterModule.service('$confirm', function ($modal, $rootScope, $q) {
 
     var deferred;
 
-    // Configure title of cancel button.
-    scope.cancelTitle = 'Cancel';
+    var confirmModal = $modal({templateUrl: '/confirm', scope: scope, placement: 'center', show: false});
 
-    scope.ok = function () {
-        deferred.resolve();
+    scope.confirmOk = function () {
+        deferred.reject('cancelled');
 
         confirmModal.hide();
     };
 
-    var confirmModal = $modal({templateUrl: '/confirm', scope: scope, placement: 'center', show: false});
+    scope.confirmOk = function () {
+        deferred.resolve(true);
+
+        confirmModal.hide();
+    };
+
+    scope.confirmCancel = function () {
+        deferred.resolve(false);
+
+        confirmModal.hide();
+    };
 
     confirmModal.confirm = function (content) {
-        scope.content = content || 'Confirm deletion?';
+        scope.content = content || 'Confirm?';
 
         deferred = $q.defer();
 
@@ -898,6 +889,24 @@ controlCenterModule.service('$confirm', function ($modal, $rootScope, $q) {
     return confirmModal;
 });
 
+// Confirm change location.
+controlCenterModule.service('$unsavedChangesGuard', function () {
+    return {
+        install: function ($scope) {
+            $scope.$on("$destroy", function() {
+                window.onbeforeunload = null;
+            });
+
+            window.onbeforeunload = function(){
+                return $scope.ui && $scope.ui.isDirty()
+                    ? 'You have unsaved changes.\n\nAre you sure you want to discard them?'
+                    : undefined;
+            };
+        }
+    }
+});
+
+
 // Service for confirm or skip several steps.
 controlCenterModule.service('$confirmBatch', function ($rootScope, $modal,  $q) {
     var scope = $rootScope.$new();
@@ -984,7 +993,7 @@ controlCenterModule.service('$confirmBatch', function ($rootScope, $modal,  $q)
 });
 
 // 'Clone' popup service.
-controlCenterModule.service('$copy', function ($modal, $rootScope, $q) {
+controlCenterModule.service('$clone', function ($modal, $rootScope, $q) {
     var scope = $rootScope.$new();
 
     var deferred;

http://git-wip-us.apache.org/repos/asf/ignite/blob/708a891a/modules/control-center-web/src/main/js/controllers/metadata-controller.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/controllers/metadata-controller.js b/modules/control-center-web/src/main/js/controllers/metadata-controller.js
index 6821e57..4c6d3e1 100644
--- a/modules/control-center-web/src/main/js/controllers/metadata-controller.js
+++ b/modules/control-center-web/src/main/js/controllers/metadata-controller.js
@@ -17,15 +17,17 @@
 
 // Controller for Metadata screen.
 controlCenterModule.controller('metadataController', [
-        '$scope', '$controller', '$http', '$modal', '$common', '$timeout', '$focus', '$confirm', '$confirmBatch', '$copy', '$table', '$preview', '$loading',
-        function ($scope, $controller, $http, $modal, $common, $timeout, $focus, $confirm, $confirmBatch, $copy, $table, $preview, $loading) {
+        '$scope', '$controller', '$http', '$modal', '$common', '$timeout', '$focus', '$confirm', '$confirmBatch', '$clone', '$table', '$preview', '$loading', '$unsavedChangesGuard',
+        function ($scope, $controller, $http, $modal, $common, $timeout, $focus, $confirm, $confirmBatch, $clone, $table, $preview, $loading, $unsavedChangesGuard) {
+            $unsavedChangesGuard.install($scope);
+
             // Initialize the super class and extend it.
             angular.extend(this, $controller('save-remove', {$scope: $scope}));
 
             // Initialize the super class and extend it.
             angular.extend(this, $controller('agent-download', {$scope: $scope}));
 
-            $scope.ui = $common.formUI(1);
+            $scope.ui = $common.formUI();
 
             $scope.agentGoal = 'load metadata from database schema';
             $scope.agentTestDriveOption = '--test-drive-metadata';
@@ -43,8 +45,6 @@ controlCenterModule.controller('metadataController', [
             $scope.tableStartEdit = $table.tableStartEdit;
             $scope.tableRemove = function (item, field, index) {
                 $table.tableRemove(item, field, index);
-
-                $scope.ui.markDirty();
             };
 
             $scope.tableSimpleSave = $table.tableSimpleSave;
@@ -371,7 +371,6 @@ controlCenterModule.controller('metadataController', [
                                 lastItem = $scope.metadatas[0];
 
                             $scope.selectItem(lastItem);
-                            $scope.ui.markPristine(1);
 
                             $common.showInfo('Cache type metadata loaded from database.');
                         })
@@ -536,11 +535,12 @@ controlCenterModule.controller('metadataController', [
                 var itemsToConfirm = _.filter(batch, function (item) { return item.confirm; });
 
                 if (itemsToConfirm.length > 0)
-                    $confirmBatch.confirm(overwriteMessage, itemsToConfirm).then(function () {
-                        _saveBatch(_.filter(batch, function (item) {return !item.skip}));
-                    }, function () {
-                        $common.showError('Cache type metadata loading interrupted by user.');
-                    });
+                    $confirmBatch.confirm(overwriteMessage, itemsToConfirm)
+                        .then(function () {
+                            _saveBatch(_.filter(batch, function (item) {return !item.skip}));
+                        }, function () {
+                            $common.showError('Cache type metadata loading interrupted by user.');
+                        });
                 else
                     _saveBatch(batch);
             }
@@ -598,6 +598,8 @@ controlCenterModule.controller('metadataController', [
                             $scope.metadata = data.metadata;
                             $scope.metadataDb = data.metadataDb;
 
+                            $scope.ui.groups = data.metadata;
+
                             if ($common.getQueryVariable('new'))
                                 $scope.createItem();
                             else {
@@ -622,12 +624,14 @@ controlCenterModule.controller('metadataController', [
 
                             $timeout(function () {
                                 $scope.$apply();
-
-                                $scope.ui.markPristineHard();
                             });
 
                             $scope.$watch('backupItem', function (val) {
                                 if (val) {
+                                    var srcItem = $scope.selectedItem ? $scope.selectedItem : prepareNewItem();
+
+                                    $scope.ui.checkDirty(val, srcItem);
+
                                     $scope.preview.general.xml = $generatorXml.metadataGeneral(val).asString();
                                     $scope.preview.general.java = $generatorJava.metadataGeneral(val).asString();
                                     $scope.preview.general.allDefaults = $common.isEmptyString($scope.preview.general.xml);
@@ -639,8 +643,6 @@ controlCenterModule.controller('metadataController', [
                                     $scope.preview.store.xml = $generatorXml.metadataStore(val).asString();
                                     $scope.preview.store.java = $generatorJava.metadataStore(val).asString();
                                     $scope.preview.store.allDefaults = $common.isEmptyString($scope.preview.store.xml);
-
-                                    $scope.ui.markDirty();
                                 }
                             }, true);
                         })
@@ -694,8 +696,6 @@ controlCenterModule.controller('metadataController', [
                         $scope.backupItem = angular.copy(item);
                     else
                         $scope.backupItem = undefined;
-
-                    $scope.ui.markPristine(1);
                 }
 
                 $common.confirmUnsavedChanges($scope.ui.isDirty(), selectItem);
@@ -705,9 +705,9 @@ controlCenterModule.controller('metadataController', [
                     : 'New metadata';
             };
 
-            function prepareNewItem() {
+            $scope.prepareNewItem = function () {
                 return {space: $scope.spaces[0]._id, caches: []};
-            }
+            };
 
             // Add new metadata.
             $scope.createItem = function () {
@@ -789,7 +789,7 @@ controlCenterModule.controller('metadataController', [
 
                 $http.post('metadata/save', item)
                     .success(function (res) {
-                        $scope.ui.markPristine(0);
+                        $scope.ui.markPristine();
 
                         var savedMeta = res[0];
 
@@ -803,7 +803,6 @@ controlCenterModule.controller('metadataController', [
                             $scope.metadatas.push(savedMeta);
 
                         $scope.selectItem(savedMeta);
-                        $scope.ui.markPristine(1);
 
                         $common.showInfo('Cache type metadata"' + item.valueType + '" saved.');
                     })
@@ -827,7 +826,7 @@ controlCenterModule.controller('metadataController', [
                 $table.tableReset();
 
                 if (validate($scope.backupItem))
-                    $copy.confirm($scope.backupItem.valueType).then(function (newName) {
+                    $clone.confirm($scope.backupItem.valueType).then(function (newName) {
                         var item = angular.copy($scope.backupItem);
 
                         item._id = undefined;
@@ -843,34 +842,32 @@ controlCenterModule.controller('metadataController', [
 
                 var selectedItem = $scope.selectedItem;
 
-                $confirm.confirm('Are you sure you want to remove cache type metadata: "' + selectedItem.valueType + '"?').then(
-                    function () {
-                        var _id = selectedItem._id;
+                $confirm.confirm('Are you sure you want to remove cache type metadata: "' + selectedItem.valueType + '"?')
+                    .then(function () {
+                            var _id = selectedItem._id;
 
-                        $http.post('metadata/remove', {_id: _id})
-                            .success(function () {
-                                $scope.ui.markPristine(0);
+                            $http.post('metadata/remove', {_id: _id})
+                                .success(function () {
+                                    $common.showInfo('Cache type metadata has been removed: ' + selectedItem.valueType);
 
-                                $common.showInfo('Cache type metadata has been removed: ' + selectedItem.valueType);
+                                    var metadatas = $scope.metadatas;
 
-                                var metadatas = $scope.metadatas;
-
-                                var idx = _.findIndex(metadatas, function (metadata) {
-                                    return metadata._id == _id;
-                                });
+                                    var idx = _.findIndex(metadatas, function (metadata) {
+                                        return metadata._id == _id;
+                                    });
 
-                                if (idx >= 0) {
-                                    metadatas.splice(idx, 1);
+                                    if (idx >= 0) {
+                                        metadatas.splice(idx, 1);
 
-                                    if (metadatas.length > 0)
-                                        $scope.selectItem(metadatas[0]);
-                                    else
-                                        $scope.selectItem(undefined, undefined);
-                                }
-                            })
-                            .error(function (errMsg) {
-                                $common.showError(errMsg);
-                            });
+                                        if (metadatas.length > 0)
+                                            $scope.selectItem(metadatas[0]);
+                                        else
+                                            $scope.selectItem(undefined, undefined);
+                                    }
+                                })
+                                .error(function (errMsg) {
+                                    $common.showError(errMsg);
+                                });
                     });
             };
 
@@ -878,23 +875,20 @@ controlCenterModule.controller('metadataController', [
             $scope.removeAllItems = function () {
                 $table.tableReset();
 
-                $confirm.confirm('Are you sure you want to remove all metadata?').then(
-                    function () {
-                        $scope.ui.markPristine(0);
-
-                        $http.post('metadata/remove/all')
-                            .success(function () {
-                                $common.showInfo('All metadata have been removed');
+                $confirm.confirm('Are you sure you want to remove all metadata?')
+                    .then(function () {
+                            $http.post('metadata/remove/all')
+                                .success(function () {
+                                    $common.showInfo('All metadata have been removed');
 
-                                $scope.metadatas = [];
+                                    $scope.metadatas = [];
 
-                                $scope.selectItem(undefined, undefined);
-                            })
-                            .error(function (errMsg) {
-                                $common.showError(errMsg);
-                            });
-                    }
-                );
+                                    $scope.selectItem(undefined, undefined);
+                                })
+                                .error(function (errMsg) {
+                                    $common.showError(errMsg);
+                                });
+                    });
             };
 
             $scope.tableSimpleValid = function (item, field, name, index) {
@@ -1178,17 +1172,6 @@ controlCenterModule.controller('metadataController', [
                 $table.tableReset();
 
                 group.fields.splice(index, 1);
-
-                $scope.ui.markDirty();
-            };
-
-            $scope.resetItemVisible = function (group) {
-                var resetTo = $scope.selectedItem;
-
-                if (!$common.isDefined(resetTo))
-                    resetTo = prepareNewItem();
-
-                return $common.resetItemVisible(group, $scope.backupItem, resetTo);
             };
 
             $scope.resetItem = function (group) {

http://git-wip-us.apache.org/repos/asf/ignite/blob/708a891a/modules/control-center-web/src/main/js/controllers/profile-controller.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/controllers/profile-controller.js b/modules/control-center-web/src/main/js/controllers/profile-controller.js
index 15f1d55..52e123f 100644
--- a/modules/control-center-web/src/main/js/controllers/profile-controller.js
+++ b/modules/control-center-web/src/main/js/controllers/profile-controller.js
@@ -16,16 +16,18 @@
  */
 
 // Controller for Profile screen.
-controlCenterModule.controller('profileController', ['$scope', '$http', '$common', '$focus', '$confirm', function ($scope, $http, $common, $focus, $confirm) {
+controlCenterModule.controller('profileController',
+    ['$scope', '$http', '$common', '$focus', '$confirm', function ($scope, $http, $common, $focus, $confirm) {
     $scope.profileUser = angular.copy($scope.user);
 
     if ($scope.profileUser && !$scope.profileUser.token)
         $scope.profileUser.token = 'No security token. Regenerate please.';
 
     $scope.generateToken = function () {
-        $confirm.confirm('Are you sure you want to change security token?').then(function () {
-            $scope.profileUser.token = $commonUtils.randomString(20);
-        })
+        $confirm.confirm('Are you sure you want to change security token?')
+            .then(function () {
+                $scope.profileUser.token = $commonUtils.randomString(20);
+            })
     };
 
     $scope.profileChanged = function () {

http://git-wip-us.apache.org/repos/asf/ignite/blob/708a891a/modules/control-center-web/src/main/js/controllers/sql-controller.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/controllers/sql-controller.js b/modules/control-center-web/src/main/js/controllers/sql-controller.js
index 384a3e9..75b054d 100644
--- a/modules/control-center-web/src/main/js/controllers/sql-controller.js
+++ b/modules/control-center-web/src/main/js/controllers/sql-controller.js
@@ -16,7 +16,8 @@
  */
 
 // Controller for SQL notebook screen.
-controlCenterModule.controller('sqlController', ['$scope', '$window','$controller', '$http', '$timeout', '$common', '$confirm', '$interval', '$popover', '$loading',
+controlCenterModule.controller('sqlController',
+    ['$scope', '$window','$controller', '$http', '$timeout', '$common', '$confirm', '$interval', '$popover', '$loading',
     function ($scope, $window, $controller, $http, $timeout, $common, $confirm, $interval, $popover, $loading) {
     // Initialize the super class and extend it.
     angular.extend(this, $controller('agent-download', {$scope: $scope}));
@@ -152,8 +153,8 @@ controlCenterModule.controller('sqlController', ['$scope', '$window','$controlle
     };
 
     $scope.removeNotebook = function () {
-        $confirm.confirm('Are you sure you want to remove notebook: "' + $scope.notebook.name + '"?').then(
-            function () {
+        $confirm.confirm('Are you sure you want to remove notebook: "' + $scope.notebook.name + '"?')
+            .then(function () {
                 $http.post('/notebooks/remove', {_id: $scope.notebook._id})
                     .success(function () {
                         var idx = _.findIndex($scope.$root.notebooks, function (item) {
@@ -173,8 +174,7 @@ controlCenterModule.controller('sqlController', ['$scope', '$window','$controlle
                     .error(function (errMsg) {
                         $common.showError(errMsg);
                     });
-            }
-        );
+            });
     };
 
     $scope.renameParagraph = function (paragraph, newName) {
@@ -234,22 +234,21 @@ controlCenterModule.controller('sqlController', ['$scope', '$window','$controlle
     };
 
     $scope.removeParagraph = function(paragraph) {
-        $confirm.confirm('Are you sure you want to remove paragraph: "' + paragraph.name + '"?').then(
-            function () {
-                var paragraph_idx = _.findIndex($scope.notebook.paragraphs, function (item) {
-                    return paragraph == item;
-                });
+        $confirm.confirm('Are you sure you want to remove paragraph: "' + paragraph.name + '"?')
+            .then(function () {
+                    var paragraph_idx = _.findIndex($scope.notebook.paragraphs, function (item) {
+                        return paragraph == item;
+                    });
 
-                var panel_idx = _.findIndex($scope.notebook.expandedParagraphs, function (item) {
-                    return paragraph_idx == item;
-                });
+                    var panel_idx = _.findIndex($scope.notebook.expandedParagraphs, function (item) {
+                        return paragraph_idx == item;
+                    });
 
-                if (panel_idx >= 0)
-                    $scope.notebook.expandedParagraphs.splice(panel_idx, 1);
+                    if (panel_idx >= 0)
+                        $scope.notebook.expandedParagraphs.splice(panel_idx, 1);
 
-                $scope.notebook.paragraphs.splice(paragraph_idx, 1);
-            }
-        );
+                    $scope.notebook.paragraphs.splice(paragraph_idx, 1);
+            });
     };
 
     $http.post('/agent/topology')

http://git-wip-us.apache.org/repos/asf/ignite/blob/708a891a/modules/control-center-web/src/main/js/package.json
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/package.json b/modules/control-center-web/src/main/js/package.json
index 7dd73e5..eed30d8 100644
--- a/modules/control-center-web/src/main/js/package.json
+++ b/modules/control-center-web/src/main/js/package.json
@@ -22,32 +22,32 @@
   "dependencies": {
     "archiver": "^0.15.1",
     "async": "1.4.2",
-    "body-parser": "~1.13.3",
+    "body-parser": "~1.14.0",
     "bootstrap-sass": "^3.3.5",
     "compression": "1.5.2",
     "connect-mongo": "^0.8.1",
-    "cookie-parser": "~1.3.4",
+    "cookie-parser": "~1.4.0",
     "debug": "~2.2.0",
     "express": "~4.13.3",
     "express-force-ssl": "^0.3.0",
     "express-session": "^1.11.1",
     "jade": "~1.11.0",
     "lodash": "3.10.1",
-    "mongoose": "^4.1.7",
+    "mongoose": "^4.1.8",
     "mongoose-deep-populate": "2.0.1",
-    "nconf": "^0.7.2",
-    "node-sass-middleware": "0.9.0",
+    "nconf": "^0.8.0",
+    "node-sass-middleware": "0.9.6",
     "nodemailer": "1.4.0",
     "passport": "^0.3.0",
     "passport-local": "^1.0.0",
-    "passport-local-mongoose": "2.0.0",
+    "passport-local-mongoose": "3.0.0",
     "serve-favicon": "~2.3.0",
     "ws": "~0.8.0"
   },
   "devDependencies": {
     "morgan": "~1.6.1",
     "supertest": "^1.1.0",
-    "mocha": "~2.3.2",
+    "mocha": "~2.3.3",
     "should": "~7.1.0"
   }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/708a891a/modules/control-center-web/src/main/js/views/configuration/caches.jade
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/views/configuration/caches.jade b/modules/control-center-web/src/main/js/views/configuration/caches.jade
index db1ff60..1f3687d 100644
--- a/modules/control-center-web/src/main/js/views/configuration/caches.jade
+++ b/modules/control-center-web/src/main/js/views/configuration/caches.jade
@@ -36,7 +36,7 @@ block content
                     +save-remove-buttons('cache')
                     br
                     hr
-                form.form-horizontal(name='ui.inputForm' ng-if='backupItem' ng-submit='ui.noSubmit()' novalidate unsaved-warning-form)
+                form.form-horizontal(name='ui.inputForm' ng-if='backupItem' novalidate unsaved-warning-form)
                     .panel-group(bs-collapse ng-model='panels.activePanels' data-allow-multiple='true')
                         +groups('general', 'backupItem')
                         div(ng-show='ui.expanded')

http://git-wip-us.apache.org/repos/asf/ignite/blob/708a891a/modules/control-center-web/src/main/js/views/configuration/clusters.jade
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/views/configuration/clusters.jade b/modules/control-center-web/src/main/js/views/configuration/clusters.jade
index 8c37396..d10c20e 100644
--- a/modules/control-center-web/src/main/js/views/configuration/clusters.jade
+++ b/modules/control-center-web/src/main/js/views/configuration/clusters.jade
@@ -36,7 +36,7 @@ block content
                     +save-remove-buttons('cluster')
                     br
                     hr
-                form.form-horizontal(name='ui.inputForm' ng-if='backupItem' ng-submit='ui.noSubmit()' novalidate unsaved-warning-form)
+                form.form-horizontal(name='ui.inputForm' ng-if='backupItem' novalidate unsaved-warning-form)
                     .panel-group(bs-collapse ng-model='panels.activePanels' data-allow-multiple='true' ng-click='triggerDigest = true')
                         +groups('general', 'backupItem')
                         div(ng-show='ui.expanded')

http://git-wip-us.apache.org/repos/asf/ignite/blob/708a891a/modules/control-center-web/src/main/js/views/configuration/metadata.jade
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/views/configuration/metadata.jade b/modules/control-center-web/src/main/js/views/configuration/metadata.jade
index aa85476..aac5cf0 100644
--- a/modules/control-center-web/src/main/js/views/configuration/metadata.jade
+++ b/modules/control-center-web/src/main/js/views/configuration/metadata.jade
@@ -38,7 +38,7 @@ block content
                     +save-remove-buttons('metadata')
                     br
                     hr
-                form.form-horizontal(name='ui.inputForm' ng-if='backupItem' ng-submit='ui.noSubmit()' novalidate unsaved-warning-form)
+                form.form-horizontal(name='ui.inputForm' ng-if='backupItem' novalidate unsaved-warning-form)
                     .panel-group(bs-collapse ng-model='panels.activePanels' data-allow-multiple='true')
                         +groups('metadata', 'backupItem')
                     .section

http://git-wip-us.apache.org/repos/asf/ignite/blob/708a891a/modules/control-center-web/src/main/js/views/includes/controls.jade
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/views/includes/controls.jade b/modules/control-center-web/src/main/js/views/includes/controls.jade
index 6a2995b..ad694ff 100644
--- a/modules/control-center-web/src/main/js/views/includes/controls.jade
+++ b/modules/control-center-web/src/main/js/views/includes/controls.jade
@@ -458,7 +458,7 @@ mixin groups(groups, dataSource)
             label(id='{{::group.group + "-title"}}')
             i.tipLabel.fa.fa-question-circle(ng-if='group.tip' bs-tooltip='joinTip(group.tip)' type='button')
             i.tipLabel.fa.fa-question-circle.blank(ng-if='!group.tip')
-            i.pull-right.fa.fa-undo(ng-show='resetItemVisible(group)' ng-click='resetItem(group.group);$event.stopPropagation()' bs-tooltip data-title='Undo unsaved changes')
+            i.pull-right.fa.fa-undo(ng-show='group.dirty' ng-click='resetItem(group.group); $event.stopPropagation()' bs-tooltip data-title='Undo unsaved changes')
         .panel-collapse(role='tabpanel' bs-collapse-target id='{{::group.group}}' number='{{::group.number}}')
             .panel-body
                 .col-sm-6(id='{{::group.group + "-left"}}')
@@ -479,18 +479,18 @@ mixin advanced-options-bottom
         a(ng-click='toggleExpanded()') {{ui.expanded ? 'Hide advanced settings...' : 'Show advanced settings...'}}
 
 mixin preview-content(preview, state, mode)
-    -var previewState = preview + 'State'
+    -var previewMode = 'group.preview'
 
-    .preview-content(ng-if='!preview[#{preview}].allDefaults && #{previewState} == #{state}' id='#{id}'
+    .preview-content(ng-if='!preview[#{preview}].allDefaults && #{previewMode} == #{state}' id='#{id}'
         ui-ace='{onLoad: previewInit, onChange: previewChanged, mode: "#{mode}", rendererOptions: {minLines: group.previewMinLines || 3}}' ng-model='preview[#{preview}].#{mode}')
 
 mixin preview(preview, id)
-    -var previewState = preview + 'State'
+    -var previewMode = 'group.preview'
 
-    .preview-panel(ng-init='#{previewState} = false')
+    .preview-panel(ng-init='#{previewMode} = false')
         .preview-legend
-            a(ng-class='{active: !#{previewState}, inactive: #{previewState}}' ng-click='#{previewState} = false') XML&nbsp;
-            a(ng-class='{active: #{previewState}, inactive: !#{previewState}}' ng-click='#{previewState} = true') Java
+            a(ng-class='{active: !#{previewMode}, inactive: #{previewMode}}' ng-click='#{previewMode} = false') XML&nbsp;
+            a(ng-class='{active: #{previewMode}, inactive: !#{previewMode}}' ng-click='#{previewMode} = true') Java
         +preview-content(preview, false, 'xml')
         +preview-content(preview, true, 'java')
         .preview-content-empty(ng-if='preview[#{preview}].allDefaults' id='#{id}')

http://git-wip-us.apache.org/repos/asf/ignite/blob/708a891a/modules/control-center-web/src/main/js/views/sql/sql.jade
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/views/sql/sql.jade b/modules/control-center-web/src/main/js/views/sql/sql.jade
index 74c4dd5..5a5f8f2 100644
--- a/modules/control-center-web/src/main/js/views/sql/sql.jade
+++ b/modules/control-center-web/src/main/js/views/sql/sql.jade
@@ -126,13 +126,10 @@ block container
                                                     button.btn.btn-primary(id='export-item-dropdown' data-toggle='dropdown' data-container='body' bs-dropdown='exportDropdown' data-placement='bottom-right')
                                                         span.caret
                                         .sql-table-wrapper
-                                            table.table.table-condensed(st-table='displayedResult' st-safe-src='paragraph.rows' float-thead='floatTheadOptions')
-                                                thead
-                                                    tr
-                                                        th(ng-repeat='col in paragraph.meta track by $index' ng-if='paragraph.columnFilter(col)' bs-tooltip='columnToolTip(col)' data-placement='bottom') {{col.fieldName}}
+                                            table.table.table-condensed
                                                 tbody
-                                                    tr(ng-repeat='row in displayedResult track by $index')
-                                                        td(ng-repeat='val in row track by $index' ng-if='paragraph.columnFilter(paragraph.meta[$index])') {{ val }}
+                                                    tr(ng-repeat='row in paragraph.rows')
+                                                        td(ng-repeat='val in row') {{::val}}
                                     div(ng-show='paragraph.chart() && paragraph.nonEmpty()')
                                         .chart-settings-link
                                             i.fa.fa-chevron-circle-down

http://git-wip-us.apache.org/repos/asf/ignite/blob/708a891a/modules/control-center-web/src/main/js/views/templates/confirm.jade
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/views/templates/confirm.jade b/modules/control-center-web/src/main/js/views/templates/confirm.jade
index 21e125b..bb68a04 100644
--- a/modules/control-center-web/src/main/js/views/templates/confirm.jade
+++ b/modules/control-center-web/src/main/js/views/templates/confirm.jade
@@ -18,10 +18,10 @@
     .modal-dialog
         .modal-content
             .modal-header
-                button.close(type='button' ng-click='$hide()' aria-hidden='true') &times;
+                button.close(type='button' ng-click='confirmCancel()' aria-hidden='true') &times;
                 h4.modal-title Confirmation
             .modal-body(ng-show='content')
                 p(ng-bind-html='content' style='text-align: center;')
             .modal-footer
-                button.btn.btn-default(id='confirm-btn-cancel' type='button' ng-click='$hide()') Cancel
-                button.btn.btn-primary(id='confirm-btn-confirm' type='button' ng-click='ok()') Confirm
+                button.btn.btn-default(id='confirm-btn-cancel' type='button' ng-click='confirmCancel()') Cancel
+                button.btn.btn-primary(id='confirm-btn-confirm' type='button' ng-click='confirmOk()') Confirm

http://git-wip-us.apache.org/repos/asf/ignite/blob/708a891a/modules/control-center-web/src/main/js/views/templates/layout.jade
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/views/templates/layout.jade b/modules/control-center-web/src/main/js/views/templates/layout.jade
index 18c6d3d..359f275 100644
--- a/modules/control-center-web/src/main/js/views/templates/layout.jade
+++ b/modules/control-center-web/src/main/js/views/templates/layout.jade
@@ -38,9 +38,9 @@ html(ng-app='ignite-web-control-center' ng-init='user = #{JSON.stringify(user)};
 
             script(src='//cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js')
 
-            script(src='//ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js')
-            script(src='//cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.5/angular-sanitize.min.js')
-            script(src='//cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.5/angular-animate.min.js')
+            script(src='//ajax.googleapis.com/ajax/libs/angularjs/1.4.6/angular.min.js')
+            script(src='//cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular-sanitize.min.js')
+            script(src='//cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular-animate.min.js')
 
             // script(src='//cdnjs.cloudflare.com/ajax/libs/angular-strap/2.3.2/angular-strap.js')
             // script(src='/js/angular-strap-2.3.2.js')
@@ -56,8 +56,6 @@ html(ng-app='ignite-web-control-center' ng-init='user = #{JSON.stringify(user)};
             script(src='//cdnjs.cloudflare.com/ajax/libs/floatthead/1.2.13/jquery.floatThead.min.js')
             script(src='//cdn.rawgit.com/wix/angular-tree-control/master/angular-tree-control.js')
 
-            script(src='//cdn.rawgit.com/facultymatt/angular-unsavedChanges/develop/dist/unsavedChanges.min.js')
-
             script(src='//cdnjs.cloudflare.com/ajax/libs/spin.js/2.3.2/spin.min.js')
             script(src='//rawgithub.com/darthwade/angular-loading/master/angular-loading.min.js')
 


[2/2] ignite git commit: Merge remote-tracking branch 'origin/ignite-843' into ignite-843

Posted by ak...@apache.org.
Merge remote-tracking branch 'origin/ignite-843' into ignite-843


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

Branch: refs/heads/ignite-843
Commit: 7ab85d5411743c668dfd54fe32b10bd2051757b1
Parents: 708a891 a17b30f
Author: Alexey Kuznetsov <ak...@apache.org>
Authored: Wed Sep 23 10:39:04 2015 +0700
Committer: Alexey Kuznetsov <ak...@apache.org>
Committed: Wed Sep 23 10:39:04 2015 +0700

----------------------------------------------------------------------
 .../src/main/js/controllers/sql-controller.js                | 5 ++++-
 .../src/main/js/public/stylesheets/style.scss                | 8 ++++++++
 2 files changed, 12 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/7ab85d54/modules/control-center-web/src/main/js/controllers/sql-controller.js
----------------------------------------------------------------------