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 2018/04/02 12:24:45 UTC

[22/24] ignite git commit: IGNITE-5466 Web Console: Configuration reworked to cluster centric model: 1. Reworked data model. 2. Implemented migrations. 3. Reworked UI for all screens. 4. Reworked validation. 5. Many refactorings to improve code base

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/grid-item-selected/controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/grid-item-selected/controller.js b/modules/web-console/frontend/app/components/grid-item-selected/controller.js
index 0e8dadc..3803c96 100644
--- a/modules/web-console/frontend/app/components/grid-item-selected/controller.js
+++ b/modules/web-console/frontend/app/components/grid-item-selected/controller.js
@@ -35,7 +35,7 @@ export default class {
     }
 
     applyValues() {
-        this.selected = this.gridApi.selection.getSelectedRows().length;
+        this.selected = this.gridApi.selection.legacyGetSelectedRows().length;
         this.count = this.gridApi.grid.rows.length;
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/ignite-icon/directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/ignite-icon/directive.js b/modules/web-console/frontend/app/components/ignite-icon/directive.js
index 4ce87a7..b72c4f9 100644
--- a/modules/web-console/frontend/app/components/ignite-icon/directive.js
+++ b/modules/web-console/frontend/app/components/ignite-icon/directive.js
@@ -57,7 +57,7 @@ export default function() {
                 this.wrapper.innerHTML = `<svg><use xlink:href="${url}" href="${url}" /></svg>`;
 
                 Array.from(this.wrapper.childNodes[0].childNodes).forEach((n) => {
-                    this.$element[0].appendChild(n);
+                    this.$element.empty().append(n);
                 });
             }
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/ignite-icon/style.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/ignite-icon/style.scss b/modules/web-console/frontend/app/components/ignite-icon/style.scss
index 60b667f..5bff0fb 100644
--- a/modules/web-console/frontend/app/components/ignite-icon/style.scss
+++ b/modules/web-console/frontend/app/components/ignite-icon/style.scss
@@ -18,4 +18,10 @@
 [ignite-icon] {
     height: 16px;
     width: 16px;
-}
\ No newline at end of file
+}
+
+[ignite-icon='expand'],
+[ignite-icon='collapse'] {
+    width: 13px;
+    height: 13px;
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/component.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/component.js b/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/component.js
new file mode 100644
index 0000000..84ee1e8
--- /dev/null
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/component.js
@@ -0,0 +1,86 @@
+/*
+ * 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 {default as ListEditable} from '../../controller';
+import noItemsTemplate from './no-items-template.pug';
+import hasItemsTemplate from './has-items-template.pug';
+import './style.scss';
+
+/**
+ * Adds "add new item" button to list-editable-no-items slot and after list-editable
+ * @type {ng.IComponentController}
+ */
+export class ListEditableAddItemButton {
+    /** 
+     * Template for button that's inserted after list-editable
+     * @type {string}
+     */
+    static hasItemsTemplate = hasItemsTemplate;
+    /** @type {ListEditable} */
+    _listEditable;
+    /** @type {string} */
+    labelSingle;
+    /** @type {string} */
+    labelMultiple;
+    /** @type {ng.ICompiledExpression} */
+    _addItem;
+
+    static $inject = ['$compile', '$scope'];
+
+    /**
+     * @param {ng.ICompileService} $compile
+     * @param {ng.IScope} $scope
+     */
+    constructor($compile, $scope) {
+        this.$compile = $compile;
+        this.$scope = $scope;
+    }
+
+    $onDestroy() {
+        this._listEditable = this._hasItemsButton = null;
+    }
+
+    $postLink() {
+        this.$compile(ListEditableAddItemButton.hasItemsTemplate)(this.$scope, (hasItemsButton) => {
+            hasItemsButton.insertAfter(this._listEditable.$element);
+        });
+    }
+
+    get hasItems() {
+        return !this._listEditable.ngModel.$isEmpty(this._listEditable.ngModel.$viewValue);
+    }
+
+    addItem() {
+        return this._addItem({
+            $edit: this._listEditable.ngModel.editListItem.bind(this._listEditable),
+            $editLast: (length) => this._listEditable.ngModel.editListIndex(length - 1)
+        });
+    }
+}
+
+export default {
+    controller: ListEditableAddItemButton,
+    require: {
+        _listEditable: '^listEditable'
+    },
+    bindings: {
+        _addItem: '&addItem',
+        labelSingle: '@',
+        labelMultiple: '@'
+    },
+    template: noItemsTemplate
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/component.spec.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/component.spec.js b/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/component.spec.js
new file mode 100644
index 0000000..9e37319
--- /dev/null
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/component.spec.js
@@ -0,0 +1,72 @@
+/*
+ * 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 'mocha';
+import {assert} from 'chai';
+import {spy} from 'sinon';
+import {ListEditableAddItemButton as Ctrl} from './component';
+
+suite('list-editable-add-item-button component', () => {
+    test.skip('has addItem method with correct locals', () => {
+        const i = new Ctrl();
+        i._listEditable = {
+            ngModel: {
+                editListItem: spy()
+            }
+        };
+        i._listEditable.ngModel.editListItem.bind = spy(() => i._listEditable.ngModel.editListItem);
+        i._addItem = spy();
+        i.addItem();
+        assert.isOk(i._addItem.calledOnce);
+        assert.deepEqual(i._addItem.lastCall.args[0], {
+            $edit: i._listEditable.ngModel.editListItem
+        });
+    });
+    test('inserts button after list-editable', () => {
+        Ctrl.hasItemsTemplate = 'tpl';
+        const $scope = {};
+        const clone = {
+            insertAfter: spy()
+        };
+        const $transclude = spy((scope, attach) => attach(clone));
+        const $compile = spy(() => $transclude);
+        const i = new Ctrl($compile, $scope);
+        i._listEditable = {
+            ngModel: {
+                editListItem: spy(),
+                $element: {}
+            }
+        };
+        i.$postLink();
+        assert.isOk($compile.calledOnce);
+        assert.equal($compile.lastCall.args[0], Ctrl.hasItemsTemplate);
+        assert.equal($transclude.lastCall.args[0], $scope);
+        assert.equal(clone.insertAfter.lastCall.args[0], i._listEditable.$element);
+    });
+    test('exposes hasItems getter', () => {
+        const i = new Ctrl();
+        i._listEditable = {
+            ngModel: {
+                $isEmpty: spy((v) => !v.length),
+                $viewValue: [1, 2, 3]
+            }
+        };
+        assert.isOk(i.hasItems);
+        i._listEditable.ngModel.$viewValue = [];
+        assert.isNotOk(i.hasItems);
+    });
+});

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/has-items-template.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/has-items-template.pug b/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/has-items-template.pug
new file mode 100644
index 0000000..272f487
--- /dev/null
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/has-items-template.pug
@@ -0,0 +1,23 @@
+//-
+    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.btn-ignite.btn-ignite--link(
+    list-editable-add-item-button-has-items-button
+    type='button'
+    ng-if='$ctrl.hasItems'
+    ng-click='$ctrl.addItem()'
+)
+    | + Add new {{::$ctrl.labelSingle}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/index.js b/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/index.js
new file mode 100644
index 0000000..f7e33649
--- /dev/null
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/index.js
@@ -0,0 +1,24 @@
+/*
+ * 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 angular from 'angular';
+import component from './component';
+
+export default angular
+.module('list-editable.add-item-button', [])
+.directive('listEditableAddItemButtonHasItemsButton', () => (scope, el) => scope.$on('$destroy', () => el.remove()))
+.component('listEditableAddItemButton', component);

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/no-items-template.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/no-items-template.pug b/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/no-items-template.pug
new file mode 100644
index 0000000..0593795
--- /dev/null
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/no-items-template.pug
@@ -0,0 +1,18 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+| You have no {{::$ctrl.labelMultiple}}. 
+a.link-success(ng-click=`$ctrl.addItem()`) Create one?
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/style.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/style.scss b/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/style.scss
new file mode 100644
index 0000000..73306ca
--- /dev/null
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/style.scss
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+list-editable-add-item-button {
+    font-style: italic;
+    font-family: Roboto;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/cols.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/cols.directive.js b/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/cols.directive.js
index 55544fb..b38cb7a 100644
--- a/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/cols.directive.js
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/cols.directive.js
@@ -15,9 +15,6 @@
  * limitations under the License.
  */
 
-// @ts-check
-/// <reference types="angular" />
-
 import template from './cols.template.pug';
 import './cols.style.scss';
 
@@ -26,7 +23,7 @@ import './cols.style.scss';
  *
  * @typedef {Object} IListEditableColDef
  * @prop {string} [name] - optional name to display at column head
- * @prop {string} cellClass - CSS class to assign to column cells
+ * @prop {string} [cellClass] - CSS class to assign to column cells
  * @prop {string} [tip] - optional tip to display at column head
  */
 export class ListEditableColsController {

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/cols.style.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/cols.style.scss b/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/cols.style.scss
index 30c3235..12c9ba6 100644
--- a/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/cols.style.scss
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/cols.style.scss
@@ -19,13 +19,17 @@
     $index-column-width: 46px;
     $remove-column-width: 36px;
 
-    margin-top: 10px;
+    margin-left: 10px;
     margin-right: $remove-column-width;
-    margin-left: $index-column-width;
+
+    &__multiple-cols {
+        margin-left: $index-column-width;
+    }
 
     .ignite-form-field__label {
-        margin-left: 0;
-        margin-right: 0;
+        padding-left: 0;
+        padding-right: 0;
+        float: none;
     }
 
     [ignite-icon='info'] {
@@ -44,8 +48,4 @@
             display: none;
         }
     }
-
-    .list-editable-cols__header-cell {
-        padding-bottom: 5px;
-    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/cols.template.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/cols.template.pug b/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/cols.template.pug
index f160707..6541c92 100644
--- a/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/cols.template.pug
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/cols.template.pug
@@ -15,7 +15,7 @@
     limitations under the License.
 
 .list-editable-cols__header(
-    ng-class='::$ctrl.rowClass'
+    ng-class='::[$ctrl.rowClass, {"list-editable-cols__header__multiple-cols": $ctrl.colDefs.length > 1}]'
 )
     .list-editable-cols__header-cell(ng-repeat='col in ::$ctrl.colDefs' ng-class='::col.cellClass')
         span.ignite-form-field__label

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/index.js b/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/index.js
index e0d4b61..93df253 100644
--- a/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/index.js
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/index.js
@@ -21,8 +21,7 @@ import cols from './cols.directive.js';
 import row from './row.directive.js';
 
 export default angular
-    .module('list-editable-cols', [
-    ])
+    .module('list-editable-cols', [])
     .directive('listEditableCols', cols)
     .directive('listEditableItemView', row)
     .directive('listEditableItemEdit', row);

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/row.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/row.directive.js b/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/row.directive.js
index 32d75f9..2753263 100644
--- a/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/row.directive.js
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/row.directive.js
@@ -15,11 +15,13 @@
  * limitations under the License.
  */
 
+import {ListEditableColsController} from './cols.directive';
+
 /** @returns {ng.IDirective} */
 export default function() {
     return {
         require: '?^listEditableCols',
-        /** @param {PcListEditableColsController} ctrl */
+        /** @param {ListEditableColsController} ctrl */
         link(scope, el, attr, ctrl) {
             if (!ctrl || !ctrl.colDefs.length)
                 return;

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/list-editable/components/list-editable-one-way/directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-one-way/directive.js b/modules/web-console/frontend/app/components/list-editable/components/list-editable-one-way/directive.js
new file mode 100644
index 0000000..320791b
--- /dev/null
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-one-way/directive.js
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import isMatch from 'lodash/isMatch';
+import {default as ListEditableController} from '../../controller';
+
+/** @type {ng.IDirectiveFactory} */
+export default function listEditableOneWay() {
+    return {
+        require: {
+            list: 'listEditable'
+        },
+        bindToController: {
+            onItemChange: '&?',
+            onItemRemove: '&?'
+        },
+        controller: class Controller {
+            /** @type {ListEditableController} */
+            list;
+            /** @type {ng.ICompiledExpression} onItemChange */
+            onItemChange;
+            /** @type {ng.ICompiledExpression} onItemRemove */
+            onItemRemove;
+
+            static $inject = ['$scope'];
+            /**
+             * @param {ng.IScope} $scope
+             */
+            constructor($scope) {
+                this.$scope = $scope;
+            }
+            $onInit() {
+                this.list.save = (item, index) => {
+                    if (!isMatch(this.list.ngModel.$viewValue[index], item)) this.onItemChange({$event: item});
+                };
+                this.list.remove = (index) => this.onItemRemove({$event: this.list.ngModel.$viewValue[index]});
+            }
+        }
+    };
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/list-editable/components/list-editable-one-way/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-one-way/index.js b/modules/web-console/frontend/app/components/list-editable/components/list-editable-one-way/index.js
new file mode 100644
index 0000000..3c49003
--- /dev/null
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-one-way/index.js
@@ -0,0 +1,24 @@
+/*
+ * 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 angular from 'angular';
+
+import directive from './directive';
+
+export default angular
+    .module('ignite-console.list-editable.one-way', [])
+    .directive(directive.name, directive);

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/list-editable/components/list-editable-save-on-changes/directives.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-save-on-changes/directives.js b/modules/web-console/frontend/app/components/list-editable/components/list-editable-save-on-changes/directives.js
new file mode 100644
index 0000000..4b6e785
--- /dev/null
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-save-on-changes/directives.js
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {default as ListEditableController} from '../../controller';
+
+const CUSTOM_EVENT_TYPE = '$ngModel.change';
+
+/** 
+ * Emits $ngModel.change event on every ngModel.$viewValue change
+ * @type {ng.IDirectiveFactory}
+ */
+export function ngModel() {
+    return {
+        /**
+         * @param {JQLite} el
+         * @param {ng.INgModelController} ngModel
+         */
+        link(scope, el, attr, {ngModel, list}) {
+            if (!list) return;
+            ngModel.$viewChangeListeners.push(() => {
+                el[0].dispatchEvent(new CustomEvent(CUSTOM_EVENT_TYPE, {bubbles: true, cancelable: true}));
+            });
+        },
+        require: {
+            ngModel: 'ngModel',
+            list: '?^listEditable'
+        }
+    };
+}
+/** 
+ * Triggers $ctrl.save when any ngModel emits $ngModel.change event
+ * @type {ng.IDirectiveFactory}
+ */
+export function listEditableTransclude() {
+    return {
+        /**
+         * @param {ng.IScope} scope
+         * @param {JQLite} el
+         * @param {ng.IAttributes} attr
+         * @param {ListEditableController} list
+         */
+        link(scope, el, attr, {list, transclude}) {
+            if (attr.listEditableTransclude !== 'itemEdit') return;
+            if (!list) return;
+            let listener = (e) => {
+                e.stopPropagation();
+                scope.$evalAsync(() => {
+                    if (scope.form.$valid) list.save(scope.item, transclude.$index);
+                });
+            };
+            el[0].addEventListener(CUSTOM_EVENT_TYPE, listener);
+            scope.$on('$destroy', () => {
+                el[0].removeEventListener(CUSTOM_EVENT_TYPE, listener);
+                listener = null;
+            });
+        },
+        require: {
+            list: '?^listEditable',
+            transclude: 'listEditableTransclude'
+        }
+    };
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/list-editable/components/list-editable-save-on-changes/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-save-on-changes/index.js b/modules/web-console/frontend/app/components/list-editable/components/list-editable-save-on-changes/index.js
new file mode 100644
index 0000000..642e84a
--- /dev/null
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-save-on-changes/index.js
@@ -0,0 +1,24 @@
+/*
+ * 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 angular from 'angular';
+import {ngModel, listEditableTransclude} from './directives';
+
+export default angular
+.module('list-editable.save-on-changes', [])
+.directive(ngModel.name, ngModel)
+.directive(listEditableTransclude.name, listEditableTransclude);

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/list-editable/components/list-editable-transclude/directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-transclude/directive.js b/modules/web-console/frontend/app/components/list-editable/components/list-editable-transclude/directive.js
index 4eee50c..6391eb1 100644
--- a/modules/web-console/frontend/app/components/list-editable/components/list-editable-transclude/directive.js
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-transclude/directive.js
@@ -69,6 +69,9 @@ export class ListEditableTransclude {
                     set: (value) => {
                         // There are two items: the original one from collection and an item from
                         // cache that will be saved, so the latter should be the one we set.
+                        if (!this.$scope)
+                            return;
+
                         this.$scope.item = value;
                     },
                     // Allows to delete property later

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/list-editable/controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-editable/controller.js b/modules/web-console/frontend/app/components/list-editable/controller.js
index 8f10166..586743e 100644
--- a/modules/web-console/frontend/app/components/list-editable/controller.js
+++ b/modules/web-console/frontend/app/components/list-editable/controller.js
@@ -17,13 +17,24 @@
 
 import _ from 'lodash';
 
+/** @type {ng.IComponentController} */
 export default class {
-    static $inject = ['$animate', '$element', '$transclude'];
-
-    constructor($animate, $element, $transclude) {
+    /** @type {ng.INgModelController} */
+    ngModel;
+
+    static $inject = ['$animate', '$element', '$transclude', '$timeout'];
+
+    /**
+     * @param {ng.animate.IAnimateService} $animate
+     * @param {JQLite} $element
+     * @param {ng.ITranscludeFunction} $transclude
+     * @param {ng.ITimeoutService} $timeout
+     */
+    constructor($animate, $element, $transclude, $timeout) {
         $animate.enabled($element, false);
         this.$transclude = $transclude;
-
+        this.$element = $element;
+        this.$timeout = $timeout;
         this.hasItemView = $transclude.isSlotFilled('itemView');
 
         this._cache = {};
@@ -36,14 +47,34 @@ export default class {
         return $index;
     }
 
+    $onDestroy() {
+        this.$element = null;
+    }
+
     $onInit() {
         this.ngModel.$isEmpty = (value) => {
             return !Array.isArray(value) || !value.length;
         };
+        this.ngModel.editListItem = (item) => {
+            this.$timeout(() => {
+                this.startEditView(this.ngModel.$viewValue.indexOf(item));
+                // For some reason required validator does not re-run after adding an item,
+                // the $validate call fixes the issue.
+                this.ngModel.$validate();
+            });
+        };
+        this.ngModel.editListIndex = (index) => {
+            this.$timeout(() => {
+                this.startEditView(index);
+                // For some reason required validator does not re-run after adding an item,
+                // the $validate call fixes the issue.
+                this.ngModel.$validate();
+            });
+        };
     }
 
     save(data, idx) {
-        this.ngModel.$setViewValue(this.ngModel.$viewValue.map((v, i) => i === idx ? data : v));
+        this.ngModel.$setViewValue(this.ngModel.$viewValue.map((v, i) => i === idx ? _.cloneDeep(data) : v));
     }
 
     revert(idx) {
@@ -55,7 +86,7 @@ export default class {
     }
 
     isEditView(idx) {
-        return this._cache.hasOwnProperty(idx) || _.isEmpty(this.ngModel.$viewValue[idx]);
+        return this._cache.hasOwnProperty(idx);
     }
 
     getEditView(idx) {
@@ -63,18 +94,18 @@ export default class {
     }
 
     startEditView(idx) {
-        this._cache[idx] = _.clone(this.ngModel.$viewValue[idx]);
+        this._cache[idx] = _.cloneDeep(this.ngModel.$viewValue[idx]);
     }
 
     stopEditView(data, idx, form) {
-        delete this._cache[idx];
+        // By default list-editable saves only valid values, but if you specify {allowInvalid: true}
+        // ng-model-option, then it will always save. Be careful and pay extra attention to validation
+        // when doing so, it's an easy way to miss invalid values this way.
 
-        if (form.$pristine)
-            return;
+        // Dont close if form is invalid and allowInvalid is turned off (which is default value)
+        if (!form.$valid && !this.ngModel.$options.getOption('allowInvalid')) return;
 
-        if (form.$valid)
-            this.save(data, idx);
-        else
-            this.revert(idx);
+        delete this._cache[idx];
+        this.save(data, idx);
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/list-editable/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-editable/index.js b/modules/web-console/frontend/app/components/list-editable/index.js
index ea50020..78493e6 100644
--- a/modules/web-console/frontend/app/components/list-editable/index.js
+++ b/modules/web-console/frontend/app/components/list-editable/index.js
@@ -20,10 +20,16 @@ import angular from 'angular';
 import component from './component';
 import listEditableCols from './components/list-editable-cols';
 import transclude from './components/list-editable-transclude';
+import listEditableOneWay from './components/list-editable-one-way';
+import addItemButton from './components/list-editable-add-item-button';
+import saveOnChanges from './components/list-editable-save-on-changes';
 
 export default angular
     .module('ignite-console.list-editable', [
+        addItemButton.name,
         listEditableCols.name,
-        transclude.name
+        listEditableOneWay.name,
+        transclude.name,
+        saveOnChanges.name
     ])
     .component('listEditable', component);

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/list-editable/style.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-editable/style.scss b/modules/web-console/frontend/app/components/list-editable/style.scss
index 83ce0d4..4d60528 100644
--- a/modules/web-console/frontend/app/components/list-editable/style.scss
+++ b/modules/web-console/frontend/app/components/list-editable/style.scss
@@ -18,9 +18,21 @@
 list-editable {
     $min-height: 47px;
     $index-column-width: 46px;
+    $index-color: #757575;
 
     display: block;
     flex: 1;
+    transition: 0.2s opacity;    
+
+    &[disabled] {
+        opacity: 0.5;
+        cursor: not-allowed;
+        pointer-events: none;
+    }
+
+    [list-editable-transclude='itemView'] {
+        flex: 1;
+    }
 
     &-item-view,
     &-item-edit,
@@ -30,10 +42,11 @@ list-editable {
     }
 
     &-no-items {
+        padding: 8px 20px;
         display: flex;
         align-items: center;
         min-height: $min-height;
-        padding: 5px 20px;
+        padding: 8px 20px;
         margin: -6px 0;
 
         font-style: italic;
@@ -43,22 +56,25 @@ list-editable {
         box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.2);
     }
 
+    .le-row-sort {
+        display: none;
+    }
+
     .le-row {
         display: flex;
         align-items: center;
         justify-content: space-between;
         min-height: $min-height;
         padding: 5px 0;
-
-        cursor: pointer;
+        background-color: var(--le-row-bg-color); // Ilya Borisov: does not work in IE11
         border-top: 1px solid #ddd;
 
         &:nth-child(odd) {
-            background-color: #ffffff;
+            --le-row-bg-color: #ffffff;
         }
 
         &:nth-child(even) {
-            background-color: #f9f9f9;
+            --le-row-bg-color: #f9f9f9;
         }
 
         &-index,
@@ -75,6 +91,7 @@ list-editable {
             flex-grow: 0;
             align-items: center;
             justify-content: center;
+            color: $index-color;
         }
 
         &-sort {
@@ -109,6 +126,10 @@ list-editable {
             align-items: flex-start;
         }
 
+        &--has-item-view {
+            cursor: pointer;
+        }
+
         &:not(.le-row--has-item-view) {
             align-items: flex-start;
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/list-editable/template.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-editable/template.pug b/modules/web-console/frontend/app/components/list-editable/template.pug
index 1cf0e4e..b52bfd2 100644
--- a/modules/web-console/frontend/app/components/list-editable/template.pug
+++ b/modules/web-console/frontend/app/components/list-editable/template.pug
@@ -14,9 +14,8 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 
-.le-body()
+.le-body
     .le-row(
-        ng-if='$ctrl.ngModel.$viewValue.length'
         ng-repeat='item in $ctrl.ngModel.$viewValue track by $ctrl.$index(item, $index)'
         ng-class=`{
             'le-row--editable': $ctrl.isEditView($index),
@@ -38,7 +37,7 @@
                 ignite-on-focus-out='$ctrl.stopEditView(item, $index, form);'
                 ignite-on-focus-out-ignored-classes='bssm-click-overlay bssm-item-text bssm-item-button'
             )
-                .le-row-item-view(ng-show='$ctrl.hasItemView' ng-init='!$ctrl.hasItemView && $ctrl.startEditView($index);item = $ctrl.getEditView($index);')
+                .le-row-item-view(ng-show='$ctrl.hasItemView' ng-init='$ctrl.startEditView($index);item = $ctrl.getEditView($index);')
                     div(list-editable-transclude='itemView')
                 .le-row-item-edit(ng-form name='form')
                     div(list-editable-transclude='itemEdit')
@@ -47,5 +46,5 @@
             button.btn-ignite.btn-ignite--link-dashed-secondary(type='button' ng-click='$ctrl.remove($index)')
                 svg(ignite-icon='cross')
 
-    .le-row(ng-if='!$ctrl.ngModel.$viewValue.length')
-        div(ng-transclude='noItems')
+    .le-row(ng-hide='$ctrl.ngModel.$viewValue.length')
+        .le-row-item(ng-transclude='noItems')

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/list-of-registered-users/column-defs.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-of-registered-users/column-defs.js b/modules/web-console/frontend/app/components/list-of-registered-users/column-defs.js
index e4ec91e..f53de69 100644
--- a/modules/web-console/frontend/app/components/list-of-registered-users/column-defs.js
+++ b/modules/web-console/frontend/app/components/list-of-registered-users/column-defs.js
@@ -71,11 +71,17 @@ export default [
     {name: 'dnld', displayName: 'Dnld', categoryDisplayName: 'Total activities', field: 'activitiesDetail["/agent/download"] || 0', cellTemplate: VALUE_WITH_TITLE, type: 'number', cellClass: 'ui-grid-number-cell', headerTooltip: 'Total count of agent downloads', minWidth: 80, width: 80, enableFiltering: false},
     {name: 'starts', displayName: 'Starts', categoryDisplayName: 'Total activities', field: 'activitiesDetail["/agent/start"] || 0', cellTemplate: VALUE_WITH_TITLE, type: 'number', cellClass: 'ui-grid-number-cell', headerTooltip: 'Total count of agent startup', minWidth: 87, width: 87, enableFiltering: false},
     // Activities Configuration
-    {name: 'clusters', displayName: 'Clusters', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["/configuration/clusters"] || 0', cellTemplate: VALUE_WITH_TITLE, type: 'number', cellClass: 'ui-grid-number-cell', headerTooltip: 'Configuration clusters', minWidth: 100, width: 100, enableFiltering: false, visible: false},
-    {name: 'model', displayName: 'Model', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["/configuration/domains"] || 0', cellTemplate: VALUE_WITH_TITLE, type: 'number', cellClass: 'ui-grid-number-cell', headerTooltip: 'Configuration model', minWidth: 87, width: 87, enableFiltering: false, visible: false},
-    {name: 'caches', displayName: 'Caches', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["/configuration/caches"] || 0', cellTemplate: VALUE_WITH_TITLE, type: 'number', cellClass: 'ui-grid-number-cell', headerTooltip: 'Configuration caches', minWidth: 96, width: 96, enableFiltering: false, visible: false},
-    {name: 'igfs', displayName: 'IGFS', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["/configuration/igfs"] || 0', cellTemplate: VALUE_WITH_TITLE, type: 'number', cellClass: 'ui-grid-number-cell', headerTooltip: 'Configuration IGFS', minWidth: 85, width: 85, enableFiltering: false, visible: false},
-    {name: 'summary', displayName: 'Summary', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["/configuration/summary"] || 0', cellTemplate: VALUE_WITH_TITLE, type: 'number', cellClass: 'ui-grid-number-cell', headerTooltip: 'Configuration summary', minWidth: 111, width: 111, enableFiltering: false, visible: false},
+    {name: 'clusters', displayName: 'Clusters', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["base.configuration.overview"] || 0', cellTemplate: VALUE_WITH_TITLE, type: 'number', cellClass: 'ui-grid-number-cell', headerTooltip: 'Configuration clusters', minWidth: 100, width: 100, enableFiltering: false, visible: false},
+    {name: 'clusterBasic', displayName: 'Basic', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["base.configuration.edit.basic"] || 0', cellTemplate: VALUE_WITH_TITLE, type: 'number', cellClass: 'ui-grid-number-cell', headerTooltip: 'Configuration clusters', minWidth: 100, width: 100, enableFiltering: false, visible: false},
+    {name: 'clusterBasicNew', displayName: 'Basic create', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["/configuration/new/basic"] || 0', cellTemplate: VALUE_WITH_TITLE, type: 'number', cellClass: 'ui-grid-number-cell', headerTooltip: 'Configuration clusters', minWidth: 100, width: 150, enableFiltering: false, visible: false},
+    {name: 'clusterAdvancedNew', displayName: 'Adv. Cluster create', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["/configuration/new/advanced/cluster"] || 0', cellTemplate: VALUE_WITH_TITLE, type: 'number', cellClass: 'ui-grid-number-cell', headerTooltip: 'Configuration clusters', minWidth: 100, width: 170, enableFiltering: false, visible: false},
+    {name: 'clusterAdvancedCluster', displayName: 'Adv. Cluster edit', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["base.configuration.edit.advanced.cluster"] || 0', cellTemplate: VALUE_WITH_TITLE, type: 'number', cellClass: 'ui-grid-number-cell', headerTooltip: 'Configuration clusters', minWidth: 100, width: 150, enableFiltering: false, visible: false},
+    {name: 'clusterAdvancedCaches', displayName: 'Adv. Caches', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["base.configuration.edit.advanced.caches"] || 0', cellTemplate: VALUE_WITH_TITLE, type: 'number', cellClass: 'ui-grid-number-cell', headerTooltip: 'Configuration clusters', minWidth: 100, width: 150, enableFiltering: false, visible: false},
+    {name: 'clusterAdvancedCache', displayName: 'Adv. Cache edit', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["base.configuration.edit.advanced.caches.cache"] || 0', cellTemplate: VALUE_WITH_TITLE, type: 'number', cellClass: 'ui-grid-number-cell', headerTooltip: 'Configuration clusters', minWidth: 100, width: 150, enableFiltering: false, visible: false},
+    {name: 'clusterAdvancedModels', displayName: 'Adv. Models', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["base.configuration.edit.advanced.models"] || 0', cellTemplate: VALUE_WITH_TITLE, type: 'number', cellClass: 'ui-grid-number-cell', headerTooltip: 'Configuration clusters', minWidth: 100, width: 150, enableFiltering: false, visible: false},
+    {name: 'clusterAdvancedModel', displayName: 'Adv. Model edit', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["base.configuration.edit.advanced.models.model"] || 0', cellTemplate: VALUE_WITH_TITLE, type: 'number', cellClass: 'ui-grid-number-cell', headerTooltip: 'Configuration clusters', minWidth: 100, width: 150, enableFiltering: false, visible: false},
+    {name: 'clusterAdvancedIGFSs', displayName: 'Adv. IGFSs', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["base.configuration.edit.advanced.igfs"] || 0', cellTemplate: VALUE_WITH_TITLE, type: 'number', cellClass: 'ui-grid-number-cell', headerTooltip: 'Configuration clusters', minWidth: 100, width: 150, enableFiltering: false, visible: false},
+    {name: 'clusterAdvancedIGFS', displayName: 'Adv. IGFS edit', categoryDisplayName: 'Configuration\'s activities', field: 'activitiesDetail["base.configuration.edit.advanced.igfs.igfs"] || 0', cellTemplate: VALUE_WITH_TITLE, type: 'number', cellClass: 'ui-grid-number-cell', headerTooltip: 'Configuration clusters', minWidth: 100, width: 150, enableFiltering: false, visible: false},
     // Activities Queries
     {name: 'execute', displayName: 'Execute', categoryDisplayName: 'Queries\' activities', field: 'activitiesDetail["/queries/execute"] || 0', cellTemplate: VALUE_WITH_TITLE, type: 'number', cellClass: 'ui-grid-number-cell', headerTooltip: 'Query executions', minWidth: 98, width: 98, enableFiltering: false, visible: false},
     {name: 'explain', displayName: 'Explain', categoryDisplayName: 'Queries\' activities', field: 'activitiesDetail["/queries/explain"] || 0', cellTemplate: VALUE_WITH_TITLE, type: 'number', cellClass: 'ui-grid-number-cell', headerTooltip: 'Query explain executions', minWidth: 95, width: 95, enableFiltering: false, visible: false},

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/list-of-registered-users/controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-of-registered-users/controller.js b/modules/web-console/frontend/app/components/list-of-registered-users/controller.js
index 71d2d61..41ac897 100644
--- a/modules/web-console/frontend/app/components/list-of-registered-users/controller.js
+++ b/modules/web-console/frontend/app/components/list-of-registered-users/controller.js
@@ -55,16 +55,16 @@ export default class IgniteListOfRegisteredUsersCtrl {
         User.read().then((user) => $ctrl.user = user);
 
         const becomeUser = () => {
-            const user = this.gridApi.selection.getSelectedRows()[0];
+            const user = this.gridApi.selection.legacyGetSelectedRows()[0];
 
             AdminData.becomeUser(user._id)
                 .then(() => User.load())
-                .then(() => $state.go('base.configuration.tabs.advanced.clusters'))
+                .then(() => $state.go('base.configuration.overview'))
                 .then(() => NotebookData.load());
         };
 
         const removeUser = () => {
-            const user = this.gridApi.selection.getSelectedRows()[0];
+            const user = this.gridApi.selection.legacyGetSelectedRows()[0];
 
             Confirm.confirm(`Are you sure you want to remove user: "${user.userName}"?`)
                 .then(() => AdminData.removeUser(user))
@@ -83,7 +83,7 @@ export default class IgniteListOfRegisteredUsersCtrl {
         };
 
         const toggleAdmin = () => {
-            const user = this.gridApi.selection.getSelectedRows()[0];
+            const user = this.gridApi.selection.legacyGetSelectedRows()[0];
 
             if (user.adminChanging)
                 return;
@@ -99,7 +99,7 @@ export default class IgniteListOfRegisteredUsersCtrl {
         };
 
         const showActivities = () => {
-            const user = this.gridApi.selection.getSelectedRows()[0];
+            const user = this.gridApi.selection.legacyGetSelectedRows()[0];
 
             return new ActivitiesUserDialog({ user });
         };
@@ -239,10 +239,10 @@ export default class IgniteListOfRegisteredUsersCtrl {
     }
 
     _updateSelected() {
-        const ids = this.gridApi.selection.getSelectedRows().map(({ _id }) => _id).sort();
+        const ids = this.gridApi.selection.legacyGetSelectedRows().map(({ _id }) => _id).sort();
 
         if (ids.length) {
-            const user = this.gridApi.selection.getSelectedRows()[0];
+            const user = this.gridApi.selection.legacyGetSelectedRows()[0];
             const other = this.user._id !== user._id;
 
             this.actionOptions[1].available = other && user.admin;

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/component.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/component.js b/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/component.js
new file mode 100644
index 0000000..44ec11b
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/component.js
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import controller from './controller';
+import templateUrl from './template.tpl.pug';
+import './style.scss';
+
+export default {
+    controller,
+    templateUrl,
+    bindings: {
+        cache: '<',
+        caches: '<',
+        models: '<',
+        igfss: '<',
+        onSave: '&'
+    }
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/controller.js b/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/controller.js
new file mode 100644
index 0000000..14439c1
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/controller.js
@@ -0,0 +1,104 @@
+/*
+ * 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 cloneDeep from 'lodash/cloneDeep';
+import get from 'lodash/get';
+
+export default class CacheEditFormController {
+    /** @type {ig.menu<string>} */
+    modelsMenu;
+    /** @type {ig.menu<string>} */
+    igfssMenu;
+    /**
+     * IGFS IDs to validate against.
+     * @type {Array<string>}
+     */
+    igfsIDs;
+
+    static $inject = ['IgniteConfirm', 'IgniteVersion', '$scope', 'Caches', 'IgniteFormUtils'];
+    constructor(IgniteConfirm, IgniteVersion, $scope, Caches, IgniteFormUtils) {
+        Object.assign(this, {IgniteConfirm, IgniteVersion, $scope, Caches, IgniteFormUtils});
+    }
+    $onInit() {
+        this.available = this.IgniteVersion.available.bind(this.IgniteVersion);
+
+        const rebuildDropdowns = () => {
+            this.$scope.affinityFunction = [
+                {value: 'Rendezvous', label: 'Rendezvous'},
+                {value: 'Custom', label: 'Custom'},
+                {value: null, label: 'Default'}
+            ];
+
+            if (this.available(['1.0.0', '2.0.0']))
+                this.$scope.affinityFunction.splice(1, 0, {value: 'Fair', label: 'Fair'});
+        };
+
+        rebuildDropdowns();
+
+        const filterModel = () => {
+            if (
+                this.clonedCache &&
+                this.available('2.0.0') &&
+                get(this.clonedCache, 'affinity.kind') === 'Fair'
+            )
+                this.clonedCache.affinity.kind = null;
+
+        };
+
+        this.subscription = this.IgniteVersion.currentSbj
+            .do(rebuildDropdowns)
+            .do(filterModel)
+            .subscribe();
+
+        this.$scope.ui = this.IgniteFormUtils.formUI();
+        this.$scope.ui.activePanels = [0];
+        this.$scope.ui.topPanels = [0, 1, 2, 3];
+    }
+    $onDestroy() {
+        this.subscription.unsubscribe();
+    }
+    $onChanges(changes) {
+        if (
+            'cache' in changes && get(this.clonedCache, '_id') !== get(this.cache, '_id')
+        ) {
+            this.clonedCache = cloneDeep(changes.cache.currentValue);
+            if (this.$scope.ui && this.$scope.ui.inputForm) {
+                this.$scope.ui.inputForm.$setPristine();
+                this.$scope.ui.inputForm.$setUntouched();
+            }
+        }
+        if ('models' in changes)
+            this.modelsMenu = (changes.models.currentValue || []).map((m) => ({value: m._id, label: m.valueType}));
+        if ('igfss' in changes) {
+            this.igfssMenu = (changes.igfss.currentValue || []).map((i) => ({value: i._id, label: i.name}));
+            this.igfsIDs = (changes.igfss.currentValue || []).map((i) => i._id);
+        }
+    }
+    getValuesToCompare() {
+        return [this.cache, this.clonedCache].map(this.Caches.normalize);
+    }
+    save() {
+        if (this.$scope.ui.inputForm.$invalid)
+            return this.IgniteFormUtils.triggerValidation(this.$scope.ui.inputForm, this.$scope);
+        this.onSave({$event: cloneDeep(this.clonedCache)});
+    }
+    reset = (forReal) => forReal ? this.clonedCache = cloneDeep(this.cache) : void 0;
+    confirmAndReset() {
+        return this.IgniteConfirm.confirm('Are you sure you want to undo all changes for current cache?')
+        .then(this.reset);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/index.js b/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/index.js
new file mode 100644
index 0000000..900efcd
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/index.js
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import angular from 'angular';
+import component from './component';
+export default angular.module('configuration.cache-edit-form', [])
+.component('cacheEditForm', component);

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/style.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/style.scss b/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/style.scss
new file mode 100644
index 0000000..d656f3d
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/style.scss
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cache-edit-form {
+    display: block;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/template.tpl.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/template.tpl.pug b/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/template.tpl.pug
new file mode 100644
index 0000000..20cde2e
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/template.tpl.pug
@@ -0,0 +1,48 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+form(
+    name='ui.inputForm'
+    id='cache'
+    novalidate
+    bs-collapse=''
+    data-allow-multiple='true'
+    ng-submit='$ctrl.save($ctrl.clonedCache)'
+)
+    include /app/modules/states/configuration/caches/general
+    include /app/modules/states/configuration/caches/memory
+    include /app/modules/states/configuration/caches/query
+    include /app/modules/states/configuration/caches/store
+
+    include /app/modules/states/configuration/caches/affinity
+    include /app/modules/states/configuration/caches/concurrency
+    include /app/modules/states/configuration/caches/near-cache-client
+    include /app/modules/states/configuration/caches/near-cache-server
+    include /app/modules/states/configuration/caches/node-filter
+    include /app/modules/states/configuration/caches/rebalance
+    include /app/modules/states/configuration/caches/statistics
+
+.pc-form-actions-panel
+    .pc-form-actions-panel__right-after
+    button.btn-ignite.btn-ignite--link-success(
+        type='button'
+        ng-click='$ctrl.confirmAndReset()'
+    )
+        | Cancel
+    button.btn-ignite.btn-ignite--success(
+        form='cache'
+        type='submit'
+    ) Save

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/component.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/component.js b/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/component.js
new file mode 100644
index 0000000..6df5337
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/component.js
@@ -0,0 +1,31 @@
+/*
+ * 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 controller from './controller';
+import templateUrl from './template.tpl.pug';
+import './style.scss';
+
+export default {
+    controller,
+    templateUrl,
+    bindings: {
+        isNew: '<',
+        cluster: '<',
+        caches: '<',
+        onSave: '&'
+    }
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/controller.js b/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/controller.js
new file mode 100644
index 0000000..dc76bd5
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/controller.js
@@ -0,0 +1,118 @@
+/*
+ * 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 cloneDeep from 'lodash/cloneDeep';
+import get from 'lodash/get';
+import _ from 'lodash';
+
+export default class ClusterEditFormController {
+    /** @type {Array<ig.config.cache.ShortCache>} */
+    caches;
+    /** @type {ig.menu<string>} */
+    cachesMenu;
+
+    static $inject = ['IgniteLegacyUtils', 'IgniteEventGroups', 'IgniteConfirm', 'IgniteVersion', '$scope', 'Clusters', 'IgniteFormUtils'];
+    constructor(IgniteLegacyUtils, IgniteEventGroups, IgniteConfirm, IgniteVersion, $scope, Clusters, IgniteFormUtils) {
+        Object.assign(this, {IgniteLegacyUtils, IgniteEventGroups, IgniteConfirm, IgniteVersion, $scope, Clusters, IgniteFormUtils});
+    }
+    $onDestroy() {
+        this.subscription.unsubscribe();
+    }
+    $onInit() {
+        this.available = this.IgniteVersion.available.bind(this.IgniteVersion);
+
+        let __original_value;
+
+        const rebuildDropdowns = () => {
+            this.eventStorage = [
+                {value: 'Memory', label: 'Memory'},
+                {value: 'Custom', label: 'Custom'}
+            ];
+
+            this.marshallerVariant = [
+                {value: 'JdkMarshaller', label: 'JdkMarshaller'},
+                {value: null, label: 'Default'}
+            ];
+
+            if (this.available('2.0.0')) {
+                this.eventStorage.push({value: null, label: 'Disabled'});
+
+                this.eventGroups = _.filter(this.IgniteEventGroups, ({value}) => value !== 'EVTS_SWAPSPACE');
+            }
+            else {
+                this.eventGroups = this.IgniteEventGroups;
+
+                this.marshallerVariant.splice(0, 0, {value: 'OptimizedMarshaller', label: 'OptimizedMarshaller'});
+            }
+        };
+
+        rebuildDropdowns();
+
+        const filterModel = (cluster) => {
+            if (cluster) {
+                if (this.available('2.0.0')) {
+                    const evtGrps = _.map(this.eventGroups, 'value');
+
+                    _.remove(cluster.includeEventTypes, (evtGrp) => !_.includes(evtGrps, evtGrp));
+
+                    if (_.get(cluster, 'marshaller.kind') === 'OptimizedMarshaller')
+                        cluster.marshaller.kind = null;
+                }
+                else if (cluster && !_.get(cluster, 'eventStorage.kind'))
+                    _.set(cluster, 'eventStorage.kind', 'Memory');
+            }
+        };
+
+        this.subscription = this.IgniteVersion.currentSbj
+            .do(rebuildDropdowns)
+            .do(() => filterModel(this.clonedCluster))
+            .subscribe();
+
+        this.supportedJdbcTypes = this.IgniteLegacyUtils.mkOptions(this.IgniteLegacyUtils.SUPPORTED_JDBC_TYPES);
+
+        this.$scope.ui = this.IgniteFormUtils.formUI();
+        this.$scope.ui.loadedPanels = ['checkpoint', 'serviceConfiguration', 'odbcConfiguration'];
+        this.$scope.ui.activePanels = [0];
+        this.$scope.ui.topPanels = [0];
+    }
+    $onChanges(changes) {
+        if (
+            'cluster' in changes && get(this.clonedCluster, '_id') !== get(this.cluster, '_id')
+        ) {
+            this.clonedCluster = cloneDeep(changes.cluster.currentValue);
+            if (this.$scope.ui && this.$scope.ui.inputForm) {
+                this.$scope.ui.inputForm.$setPristine();
+                this.$scope.ui.inputForm.$setUntouched();
+            }
+        }
+        if ('caches' in changes)
+            this.cachesMenu = (changes.caches.currentValue || []).map((c) => ({label: c.name, value: c._id}));
+    }
+    getValuesToCompare() {
+        return [this.cluster, this.clonedCluster].map(this.Clusters.normalize);
+    }
+    save() {
+        if (this.$scope.ui.inputForm.$invalid)
+            return this.IgniteFormUtils.triggerValidation(this.$scope.ui.inputForm, this.$scope);
+        this.onSave({$event: cloneDeep(this.clonedCluster)});
+    }
+    reset = () => this.clonedCluster = cloneDeep(this.cluster);
+    confirmAndReset() {
+        return this.IgniteConfirm.confirm('Are you sure you want to undo all changes for current cluster?')
+        .then(this.reset);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/index.js b/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/index.js
new file mode 100644
index 0000000..c9b5b01
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/index.js
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import angular from 'angular';
+import component from './component';
+export default angular.module('configuration.cluster-edit-form', [])
+.component('clusterEditForm', component);

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/style.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/style.scss b/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/style.scss
new file mode 100644
index 0000000..d656f3d
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/style.scss
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cache-edit-form {
+    display: block;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/template.tpl.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/template.tpl.pug b/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/template.tpl.pug
new file mode 100644
index 0000000..5bd52ac
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/template.tpl.pug
@@ -0,0 +1,88 @@
+//-
+    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.
+
+include /app/helpers/jade/mixins
+
+div(bs-collapse='' data-allow-multiple='true' ng-model='ui.activePanels')
+    form(id='cluster' name='ui.inputForm' novalidate ng-submit='$ctrl.save()')
+        .panel-group
+            include /app/modules/states/configuration/clusters/general
+
+            include /app/modules/states/configuration/clusters/atomic
+            include /app/modules/states/configuration/clusters/binary
+            include /app/modules/states/configuration/clusters/cache-key-cfg
+            include /app/modules/states/configuration/clusters/checkpoint
+
+            //- Since ignite 2.3
+            include /app/modules/states/configuration/clusters/client-connector
+
+            include /app/modules/states/configuration/clusters/collision
+            include /app/modules/states/configuration/clusters/communication
+            include /app/modules/states/configuration/clusters/connector
+            include /app/modules/states/configuration/clusters/deployment
+
+            //- Since ignite 2.3
+            include /app/modules/states/configuration/clusters/data-storage
+
+            include /app/modules/states/configuration/clusters/discovery
+            include /app/modules/states/configuration/clusters/events
+            include /app/modules/states/configuration/clusters/failover
+            include /app/modules/states/configuration/clusters/hadoop
+            include /app/modules/states/configuration/clusters/load-balancing
+            include /app/modules/states/configuration/clusters/logger
+            include /app/modules/states/configuration/clusters/marshaller
+
+            //- Since ignite 2.0, deprecated in ignite 2.3
+            include /app/modules/states/configuration/clusters/memory
+
+            include /app/modules/states/configuration/clusters/misc
+            include /app/modules/states/configuration/clusters/metrics
+
+            //- Deprecated in ignite 2.1
+            include /app/modules/states/configuration/clusters/odbc
+
+            //- Since ignite 2.1, deprecated in ignite 2.3
+            include /app/modules/states/configuration/clusters/persistence
+
+            //- Deprecated in ignite 2.3
+            include /app/modules/states/configuration/clusters/sql-connector
+
+            include /app/modules/states/configuration/clusters/service
+            include /app/modules/states/configuration/clusters/ssl
+
+            //- Removed in ignite 2.0
+            include /app/modules/states/configuration/clusters/swap
+
+            include /app/modules/states/configuration/clusters/thread
+            include /app/modules/states/configuration/clusters/time
+            include /app/modules/states/configuration/clusters/transactions
+            include /app/modules/states/configuration/clusters/attributes
+
+.pc-form-actions-panel(n_g-show='$ctrl.$scope.selectedItem')
+    button-preview-project(cluster='$ctrl.cluster' ng-hide='$ctrl.isNew')
+    button-download-project(cluster='$ctrl.cluster' ng-hide='$ctrl.isNew')
+
+    .pc-form-actions-panel__right-after
+
+    button.btn-ignite.btn-ignite--link-success(
+        type='button'
+        ng-click='$ctrl.confirmAndReset()'
+    )
+        | Cancel
+    button.btn-ignite.btn-ignite--success(
+        form='cluster'
+        type='submit'
+    ) Save
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/component.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/component.js b/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/component.js
new file mode 100644
index 0000000..225a482
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/component.js
@@ -0,0 +1,30 @@
+/*
+ * 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 controller from './controller';
+import templateUrl from './template.tpl.pug';
+import './style.scss';
+
+export default {
+    controller,
+    templateUrl,
+    bindings: {
+        igfs: '<',
+        igfss: '<',
+        onSave: '&'
+    }
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/controller.js b/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/controller.js
new file mode 100644
index 0000000..aa150d3
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/controller.js
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import cloneDeep from 'lodash/cloneDeep';
+import get from 'lodash/get';
+
+export default class IgfsEditFormController {
+    static $inject = ['IgniteConfirm', 'IgniteVersion', '$scope', 'IGFSs', 'IgniteFormUtils'];
+    constructor( IgniteConfirm, IgniteVersion, $scope, IGFSs, IgniteFormUtils) {
+        Object.assign(this, { IgniteConfirm, IgniteVersion, $scope, IGFSs, IgniteFormUtils});
+    }
+    $onInit() {
+        this.available = this.IgniteVersion.available.bind(this.IgniteVersion);
+
+        this.$scope.ui = this.IgniteFormUtils.formUI();
+        this.$scope.ui.activePanels = [0];
+        this.$scope.ui.topPanels = [0];
+        this.$scope.ui.expanded = true;
+        this.$scope.ui.loadedPanels = ['general', 'secondaryFileSystem', 'misc'];
+    }
+
+    $onChanges(changes) {
+        if (
+            'igfs' in changes && get(this.$scope.backupItem, '_id') !== get(this.igfs, '_id')
+        ) {
+            this.$scope.backupItem = cloneDeep(changes.igfs.currentValue);
+            if (this.$scope.ui && this.$scope.ui.inputForm) {
+                this.$scope.ui.inputForm.$setPristine();
+                this.$scope.ui.inputForm.$setUntouched();
+            }
+        }
+    }
+    getValuesToCompare() {
+        return [this.igfs, this.$scope.backupItem].map(this.IGFSs.normalize);
+    }
+    save() {
+        if (this.$scope.ui.inputForm.$invalid)
+            return this.IgniteFormUtils.triggerValidation(this.$scope.ui.inputForm, this.$scope);
+        this.onSave({$event: cloneDeep(this.$scope.backupItem)});
+    }
+    reset = (forReal) => forReal ? this.$scope.backupItem = cloneDeep(this.igfs) : void 0;
+    confirmAndReset() {
+        return this.IgniteConfirm.confirm('Are you sure you want to undo all changes for current IGFS?')
+        .then(this.reset);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/index.js b/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/index.js
new file mode 100644
index 0000000..e187cc2
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/index.js
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import angular from 'angular';
+import component from './component';
+export default angular.module('configuration.igfs-edit-form', [])
+.component('igfsEditForm', component);

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/style.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/style.scss b/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/style.scss
new file mode 100644
index 0000000..881268e
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/style.scss
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+igfs-edit-form {
+    display: block;
+}
\ No newline at end of file