You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sb...@apache.org on 2017/10/25 09:59:15 UTC

[23/50] [abbrv] ignite git commit: IGNITE-5909 Added list editable component.

IGNITE-5909 Added list editable component.


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

Branch: refs/heads/ignite-5937
Commit: 01daee6b35f4dca63021ba34db1f9934c87e3233
Parents: 026254c
Author: Dmitriy Shabalin <ds...@gridgain.com>
Authored: Mon Oct 23 16:09:47 2017 +0700
Committer: Andrey Novikov <an...@gridgain.com>
Committed: Mon Oct 23 16:09:47 2017 +0700

----------------------------------------------------------------------
 modules/web-console/frontend/.eslintrc          |   2 +-
 modules/web-console/frontend/app/app.js         |   3 +
 .../app/components/list-editable/component.js   |  36 +++++
 .../list-editable-cols/cols.directive.js        |  79 +++++++++++
 .../list-editable-cols/cols.style.scss          |  51 +++++++
 .../list-editable-cols/cols.template.pug        |  29 ++++
 .../components/list-editable-cols/index.js      |  28 ++++
 .../list-editable-cols/row.directive.js         |  40 ++++++
 .../app/components/list-editable/controller.js  |  79 +++++++++++
 .../app/components/list-editable/index.js       |  27 ++++
 .../app/components/list-editable/style.scss     | 132 +++++++++++++++++++
 .../app/components/list-editable/template.pug   |  49 +++++++
 .../helpers/jade/form/form-field-dropdown.pug   |   2 +-
 .../app/primitives/form-field/index.scss        |  15 +++
 .../frontend/app/primitives/ui-grid/index.scss  |   4 +
 modules/web-console/frontend/package.json       |   2 +-
 .../frontend/public/images/icons/index.js       |   2 +
 .../frontend/public/images/icons/info.svg       |   3 +
 .../frontend/public/images/icons/sort.svg       |   1 +
 modules/web-console/frontend/tsconfig.json      |  12 ++
 20 files changed, 593 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/01daee6b/modules/web-console/frontend/.eslintrc
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/.eslintrc b/modules/web-console/frontend/.eslintrc
index 4e24d0b..3c26fa7 100644
--- a/modules/web-console/frontend/.eslintrc
+++ b/modules/web-console/frontend/.eslintrc
@@ -186,7 +186,7 @@ rules:
     space-in-parens: 0
     space-infix-ops: 2
     space-unary-ops: [2, { "words": true, "nonwords": false }]
-    spaced-comment: [1, "always"]
+    spaced-comment: [1, "always", {"markers": ["/"]}]
     use-isnan: 2
     valid-jsdoc: 0
     valid-typeof: 2

http://git-wip-us.apache.org/repos/asf/ignite/blob/01daee6b/modules/web-console/frontend/app/app.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/app.js b/modules/web-console/frontend/app/app.js
index f2ee8ef..44454f6 100644
--- a/modules/web-console/frontend/app/app.js
+++ b/modules/web-console/frontend/app/app.js
@@ -128,6 +128,8 @@ import gridItemSelected from './components/grid-item-selected';
 import bsSelectMenu from './components/bs-select-menu';
 import protectFromBsSelectRender from './components/protect-from-bs-select-render';
 import uiGridHovering from './components/ui-grid-hovering';
+import listEditable from './components/list-editable';
+
 import igniteServices from './services';
 
 // Inject external modules.
@@ -202,6 +204,7 @@ angular.module('ignite-console', [
     protectFromBsSelectRender.name,
     AngularStrapTooltip.name,
     AngularStrapSelect.name,
+    listEditable.name,
     // Ignite modules.
     IgniteModules.name
 ])

http://git-wip-us.apache.org/repos/asf/ignite/blob/01daee6b/modules/web-console/frontend/app/components/list-editable/component.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-editable/component.js b/modules/web-console/frontend/app/components/list-editable/component.js
new file mode 100644
index 0000000..8cdc083
--- /dev/null
+++ b/modules/web-console/frontend/app/components/list-editable/component.js
@@ -0,0 +1,36 @@
+/*
+ * 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 template from './template.pug';
+import controller from './controller';
+
+import './style.scss';
+
+export default {
+    controller,
+    template,
+    require: {
+        ngModel: '^ngModel'
+    },
+    bindings: {
+    },
+    transclude: {
+        noItems: '?listEditableNoItems',
+        itemView: '?listEditableItemView',
+        itemEdit: '?listEditableItemEdit'
+    }
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/01daee6b/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
new file mode 100644
index 0000000..55544fb
--- /dev/null
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/cols.directive.js
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// @ts-check
+/// <reference types="angular" />
+
+import template from './cols.template.pug';
+import './cols.style.scss';
+
+/**
+ * A column definition.
+ *
+ * @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} [tip] - optional tip to display at column head
+ */
+export class ListEditableColsController {
+    /** @type {Array<IListEditableColDef>} - column definitions */
+    colDefs;
+    /** @type {string} - optional class to assign to rows */
+    rowClass;
+    /** @type {ng.INgModelController} */
+    ngModel;
+
+    static $inject = ['$compile', '$element', '$scope'];
+
+    /**
+     * @param {ng.ICompileService} $compile
+     * @param {JQLite} $element
+     * @param {ng.IScope} $scope
+     */
+    constructor($compile, $element, $scope) {
+        this.$compile = $compile;
+        this.$element = $element;
+        this.$scope = $scope;
+    }
+
+    $postLink() {
+        this.$compile(template)(this.$scope.$new(true), (clone, scope) => {
+            scope.$ctrl = this;
+
+            this.$element[0].parentElement.insertBefore(clone[0], this.$element[0]);
+        });
+    }
+
+    $onDestroy() {
+        this.$element = null;
+    }
+}
+
+/** @returns {ng.IDirective} */
+export default function listEditableCols() {
+    return {
+        controller: ListEditableColsController,
+        controllerAs: '$colsCtrl',
+        require: {
+            ngModel: 'ngModel'
+        },
+        bindToController: {
+            colDefs: '<listEditableCols',
+            rowClass: '@?listEditableColsRowClass'
+        }
+    };
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/01daee6b/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
new file mode 100644
index 0000000..30c3235
--- /dev/null
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/cols.style.scss
@@ -0,0 +1,51 @@
+/*
+ * 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-cols__header {
+    $index-column-width: 46px;
+    $remove-column-width: 36px;
+
+    margin-top: 10px;
+    margin-right: $remove-column-width;
+    margin-left: $index-column-width;
+
+    .ignite-form-field__label {
+        margin-left: 0;
+        margin-right: 0;
+    }
+
+    [ignite-icon='info'] {
+        @import 'public/stylesheets/variables';
+
+        margin-left: 5px;
+        color: $ignite-brand-success;
+    }
+
+    &+list-editable {
+        .ignite-form-field__label {
+            display: none;
+        }
+        
+        .le-row-item-view:nth-last-child(2) {
+            display: none;
+        }
+    }
+
+    .list-editable-cols__header-cell {
+        padding-bottom: 5px;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/01daee6b/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
new file mode 100644
index 0000000..2331173
--- /dev/null
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/cols.template.pug
@@ -0,0 +1,29 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+.list-editable-cols__header(
+    ng-show='$ctrl.ngModel.$viewValue.length'
+    ng-class='::$ctrl.rowClass'
+)
+    .list-editable-cols__header-cell(ng-repeat='col in ::$ctrl.colDefs' ng-class='::col.cellClass')
+        span.ignite-form-field__label
+            | {{ ::col.name }}
+            svg(
+                ng-if='::col.tip'
+                ignite-icon='info'
+                bs-tooltip=''
+                data-title='{{::col.tip}}'
+            )

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

http://git-wip-us.apache.org/repos/asf/ignite/blob/01daee6b/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
new file mode 100644
index 0000000..e427ab5
--- /dev/null
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-cols/row.directive.js
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** @returns {ng.IDirective} */
+export default function() {
+    return {
+        require: '?^listEditableCols',
+        /** @param {PcListEditableColsController} ctrl */
+        link(scope, el, attr, ctrl) {
+            if (!ctrl || !ctrl.colDefs.length)
+                return;
+
+            const children = el.children();
+
+            if (children.length !== ctrl.colDefs.length)
+                return;
+
+            if (ctrl.rowClass)
+                el.addClass(ctrl.rowClass);
+
+            ctrl.colDefs.forEach(({ cellClass }, index) => {
+                children[index].classList.add(...(Array.isArray(cellClass) ? cellClass : [cellClass]));
+            });
+        }
+    };
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/01daee6b/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
new file mode 100644
index 0000000..bc864ce
--- /dev/null
+++ b/modules/web-console/frontend/app/components/list-editable/controller.js
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import _ from 'lodash';
+
+export default class {
+    static $inject = ['$animate', '$element', '$transclude'];
+
+    constructor($animate, $element, $transclude) {
+        $animate.enabled(false, $element);
+
+        this.hasItemView = $transclude.isSlotFilled('itemView');
+
+        this._cache = {};
+    }
+
+    $index(item, $index) {
+        if (item._id)
+            return item._id;
+
+        return $index;
+    }
+
+    $onInit() {
+        this.ngModel.$isEmpty = (value) => {
+            return !Array.isArray(value) || !value.length;
+        };
+    }
+
+    save(data, idx) {
+        this.ngModel.$setViewValue(this.ngModel.$viewValue.map((v, i) => i === idx ? data : v));
+    }
+
+    revert(idx) {
+        delete this._cache[idx];
+    }
+
+    remove(idx) {
+        this.ngModel.$setViewValue(this.ngModel.$viewValue.filter((v, i) => i !== idx));
+    }
+
+    isEditView(idx) {
+        return this._cache.hasOwnProperty(idx) || _.isEmpty(this.ngModel.$viewValue[idx]);
+    }
+
+    getEditView(idx) {
+        return this._cache[idx];
+    }
+
+    startEditView(idx) {
+        this._cache[idx] = _.clone(this.ngModel.$viewValue[idx]);
+    }
+
+    stopEditView(data, idx, form) {
+        delete this._cache[idx];
+
+        if (form.$pristine)
+            return;
+
+        if (form.$valid)
+            this.save(data, idx);
+        else
+            this.revert(idx);
+    }
+}

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

http://git-wip-us.apache.org/repos/asf/ignite/blob/01daee6b/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
new file mode 100644
index 0000000..0f3f8ae
--- /dev/null
+++ b/modules/web-console/frontend/app/components/list-editable/style.scss
@@ -0,0 +1,132 @@
+/*
+ * 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 {
+    $min-height: 47px;
+    $index-column-width: 46px;
+
+    display: block;
+    flex: 1;
+
+    &-item-view,
+    &-item-edit,
+    &-no-items {
+        flex: 1;
+        display: block;
+    }
+
+    &-no-items {
+        display: flex;
+        align-items: center;
+        min-height: $min-height;
+        padding: 5px 10px;
+
+        font-style: italic;
+    }
+
+    .le-body {
+        box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.2);
+    }
+
+    .le-row {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        min-height: $min-height;
+        padding: 5px 0;
+
+        cursor: pointer;
+        border-top: 1px solid #ddd;
+
+        &:nth-child(odd) {
+            background-color: #ffffff;
+        }
+
+        &:nth-child(even) {
+            background-color: #f9f9f9;
+        }
+
+        &-index,
+        &-cross {
+            display: flex;
+            height: 36px;
+        }
+
+        &-index {
+            width: $index-column-width;
+            flex-basis: $index-column-width;
+            padding-left: 10px;
+            flex-shrink: 0;
+            flex-grow: 0;
+            align-items: center;
+            justify-content: center;
+        }
+
+        &-cross {
+            [ignite-icon] {
+                width: 12px;
+                height: 12px;
+            }
+        }
+
+        &-item {
+            width: 100%;
+
+            &-view {
+                display: flex;
+                min-height: 36px;
+                align-items: center;
+            }
+
+            &-edit {
+                margin-left: -11px;
+            }
+        }
+
+        &--editable {
+            position: relative;
+            z-index: 1;
+
+            align-items: flex-start;
+        }
+
+        &:not(.le-row--has-item-view) {
+            & > .le-row-index,
+            & > .le-row-cross {
+                margin-top: 18px;
+            }
+
+            align-items: flex-start;
+        }
+    }
+
+    [divider]:after {
+        content: attr(divider);
+
+        display: inline-flex;
+        justify-content: center;
+        align-self: flex-start;
+
+        width: 20px;
+        height: 36px;
+
+        margin-top: 18px;
+        margin-right: -20px;
+        
+        line-height: 36px;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/01daee6b/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
new file mode 100644
index 0000000..a713188
--- /dev/null
+++ b/modules/web-console/frontend/app/components/list-editable/template.pug
@@ -0,0 +1,49 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+.le-body(ng-if='$ctrl.ngModel.$viewValue.length')
+    .le-row(
+        ng-repeat='item in $ctrl.ngModel.$viewValue track by $ctrl.$index(item, $index)'
+        ng-class=`{
+            'le-row--editable': $ctrl.isEditView($index),
+            'le-row--has-item-view': $ctrl.hasItemView
+        }`)
+
+        .le-row-sort
+            button.btn-ignite.btn-ignite--link-dashed-secondary
+                svg(ignite-icon='sort')
+
+        .le-row-index
+            span {{ $index+1 }}
+
+        .le-row-item
+            .le-row-item-view(ng-if='$ctrl.hasItemView && !$ctrl.isEditView($index)' ng-click='$ctrl.startEditView($index);')
+                div(ng-transclude='itemView')
+            div(
+                ng-if='!$ctrl.hasItemView || $ctrl.isEditView($index)'
+                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);')
+                    div(ng-transclude='itemView')
+                .le-row-item-edit(ng-form name='form')
+                    div(ng-transclude='itemEdit')
+
+        .le-row-cross
+            button.btn-ignite.btn-ignite--link-dashed-secondary(type='button' ng-click='$ctrl.remove($index)')
+                svg(ignite-icon='cross')
+
+div(ng-transclude='noItems' ng-if='!$ctrl.ngModel.$viewValue.length')

http://git-wip-us.apache.org/repos/asf/ignite/blob/01daee6b/modules/web-console/frontend/app/helpers/jade/form/form-field-dropdown.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/helpers/jade/form/form-field-dropdown.pug b/modules/web-console/frontend/app/helpers/jade/form/form-field-dropdown.pug
index 117568d..cf7d50a 100644
--- a/modules/web-console/frontend/app/helpers/jade/form/form-field-dropdown.pug
+++ b/modules/web-console/frontend/app/helpers/jade/form/form-field-dropdown.pug
@@ -23,7 +23,7 @@ mixin ignite-form-field-dropdown(label, model, name, disabled, required, multipl
             data-placeholder=placeholderEmpty ? `{{ ${options}.length > 0 ? '${placeholder}' : '${placeholderEmpty}' }}` : placeholder
             
             data-ng-model=model
-
+            data-ng-disabled=disabled && `${disabled}`
             data-ng-required=required && `${required}`
 
             bs-select

http://git-wip-us.apache.org/repos/asf/ignite/blob/01daee6b/modules/web-console/frontend/app/primitives/form-field/index.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/primitives/form-field/index.scss b/modules/web-console/frontend/app/primitives/form-field/index.scss
index 4bc4252..f6d8496 100644
--- a/modules/web-console/frontend/app/primitives/form-field/index.scss
+++ b/modules/web-console/frontend/app/primitives/form-field/index.scss
@@ -61,6 +61,21 @@
 
                     color: $text-color;
                     line-height: 36px;
+
+                    &.ng-invalid:not(.ng-pristine),
+                    &.ng-invalid.ng-touched {
+                        border-color: $ignite-brand-primary;
+                        box-shadow: inset 0 1px 3px 0 rgba($ignite-brand-primary, .5);
+                    }
+
+                    &:focus {
+                        border-color: $ignite-brand-success;
+                        box-shadow: inset 0 1px 3px 0 rgba($ignite-brand-success, .5);
+                    }
+
+                    &:disabled {
+                        opacity: .5;
+                    }
                 }
 
                 & > input[type='number'] {

http://git-wip-us.apache.org/repos/asf/ignite/blob/01daee6b/modules/web-console/frontend/app/primitives/ui-grid/index.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/primitives/ui-grid/index.scss b/modules/web-console/frontend/app/primitives/ui-grid/index.scss
index 88bff69..e86eec7 100644
--- a/modules/web-console/frontend/app/primitives/ui-grid/index.scss
+++ b/modules/web-console/frontend/app/primitives/ui-grid/index.scss
@@ -501,6 +501,10 @@
             content: '';
         }
     }
+
+    .ui-grid-selection-row-header-buttons::before {
+        opacity: 1;
+    }
 }
 
 .ui-grid--ignite.ui-grid-disabled-group-selection {

http://git-wip-us.apache.org/repos/asf/ignite/blob/01daee6b/modules/web-console/frontend/package.json
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/package.json b/modules/web-console/frontend/package.json
index 82c3eea..95b4a2b 100644
--- a/modules/web-console/frontend/package.json
+++ b/modules/web-console/frontend/package.json
@@ -32,6 +32,7 @@
     "win32"
   ],
   "dependencies": {
+    "@uirouter/angularjs": "1.0.5",
     "angular": "1.5.11",
     "angular-acl": "0.1.8",
     "angular-animate": "1.5.11",
@@ -50,7 +51,6 @@
     "angular-translate": "2.15.2",
     "angular-tree-control": "0.2.28",
     "angular-ui-grid": "4.0.7",
-    "@uirouter/angularjs": "1.0.5",
     "babel-core": "6.25.0",
     "babel-eslint": "7.2.3",
     "babel-loader": "7.1.1",

http://git-wip-us.apache.org/repos/asf/ignite/blob/01daee6b/modules/web-console/frontend/public/images/icons/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/images/icons/index.js b/modules/web-console/frontend/public/images/icons/index.js
index 5d8ac53..d802805 100644
--- a/modules/web-console/frontend/public/images/icons/index.js
+++ b/modules/web-console/frontend/public/images/icons/index.js
@@ -24,3 +24,5 @@ export download from './download.svg';
 export filter from './filter.svg';
 export search from './search.svg';
 export refresh from './refresh.svg';
+export sort from './sort.svg';
+export info from './info.svg';

http://git-wip-us.apache.org/repos/asf/ignite/blob/01daee6b/modules/web-console/frontend/public/images/icons/info.svg
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/images/icons/info.svg b/modules/web-console/frontend/public/images/icons/info.svg
new file mode 100644
index 0000000..de92136
--- /dev/null
+++ b/modules/web-console/frontend/public/images/icons/info.svg
@@ -0,0 +1,3 @@
+<svg version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+ <path fill="currentColor" d="m8 0c-4.4 0-8 3.6-8 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm0 0.80078c4 0 7.1992 3.1992 7.1992 7.1992s-3.1992 7.1992-7.1992 7.1992-7.1992-3.1992-7.1992-7.1992 3.1992-7.1992 7.1992-7.1992zm0 2.7988c-1.3 0-2.4004 1.1004-2.4004 2.4004 0 0.2 0.20039 0.40039 0.40039 0.40039s0.40039-0.20039 0.40039-0.40039c0-0.9 0.69961-1.5996 1.5996-1.5996s1.5996 0.69961 1.5996 1.5996-0.69961 1.5996-1.5996 1.5996c-0.2 0-0.40039 0.20039-0.40039 0.40039v1.6992c0 0.2 0.20039 0.40039 0.40039 0.40039s0.40039-0.098828 0.40039-0.29883v-1.4004c1.1-0.2 2-1.2004 2-2.4004 0-1.3-1.1004-2.4004-2.4004-2.4004zm0 7.5c-0.2 0-0.40039 0.20039-0.40039 0.40039v1.0996c0 0.2 0.20039 0.40039 0.40039 0.40039s0.40039-0.20039 0.40039-0.40039v-1.0996c0-0.2-0.20039-0.40039-0.40039-0.40039z"/>
+</svg>

http://git-wip-us.apache.org/repos/asf/ignite/blob/01daee6b/modules/web-console/frontend/public/images/icons/sort.svg
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/images/icons/sort.svg b/modules/web-console/frontend/public/images/icons/sort.svg
new file mode 100644
index 0000000..7e4bb52
--- /dev/null
+++ b/modules/web-console/frontend/public/images/icons/sort.svg
@@ -0,0 +1 @@
+<svg id="drag-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="currentColor" d="M 4,6.9 H 6.3 V 4.6 H 4 Z m 4.6,0 h 2.3 V 4.6 H 8.6 Z M 4,11.4 H 6.3 V 9.1 H 4 Z m 4.6,0 h 2.3 V 9.1 H 8.6 Z M 4,16 H 6.3 V 13.7 H 4 Z m 4.6,0 h 2.3 V 13.7 H 8.6 Z M 4,2.3 H 6.3 V 0 H 4 Z m 4.6,0 h 2.3 V 0 H 8.6 Z"/></svg>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/01daee6b/modules/web-console/frontend/tsconfig.json
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/tsconfig.json b/modules/web-console/frontend/tsconfig.json
new file mode 100644
index 0000000..a70845d
--- /dev/null
+++ b/modules/web-console/frontend/tsconfig.json
@@ -0,0 +1,12 @@
+{
+    "compilerOptions": {
+        "allowSyntheticDefaultImports": true,
+        "target": "ES2017",
+        "allowJs": true,
+        "checkJs": true,
+        "baseUrl": ".",
+        "paths": {
+            "*": ["*", "node_modules/*"]
+        }
+    }
+}
\ No newline at end of file