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 2016/09/09 03:26:52 UTC

[24/52] ignite git commit: Web Console beta-3.

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/stylesheets/_font-awesome-custom.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/stylesheets/_font-awesome-custom.scss b/modules/web-console/frontend/public/stylesheets/_font-awesome-custom.scss
new file mode 100644
index 0000000..1c8f325
--- /dev/null
+++ b/modules/web-console/frontend/public/stylesheets/_font-awesome-custom.scss
@@ -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 '~font-awesome/scss/variables';
+
+$fa-font-path: '~font-awesome/fonts';
+
+@import '~font-awesome/scss/mixins';
+@import '~font-awesome/scss/path';
+@import '~font-awesome/scss/core';
+@import '~font-awesome/scss/larger';
+@import '~font-awesome/scss/fixed-width';
+@import '~font-awesome/scss/list';
+@import '~font-awesome/scss/bordered-pulled';
+@import '~font-awesome/scss/animated';
+@import '~font-awesome/scss/rotated-flipped';
+@import '~font-awesome/scss/stacked';
+@import '~font-awesome/scss/icons';

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/stylesheets/blocks/error.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/stylesheets/blocks/error.scss b/modules/web-console/frontend/public/stylesheets/blocks/error.scss
new file mode 100644
index 0000000..4e16989
--- /dev/null
+++ b/modules/web-console/frontend/public/stylesheets/blocks/error.scss
@@ -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.
+ */
+
+.error-page {
+    text-align: center;
+    min-height: 300px;
+
+    &__title {
+        margin-top: 150px;
+        font-weight: 200;
+    }
+
+    &__description {
+        margin-top: 30px;
+        font-weight: 500;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/stylesheets/style.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/stylesheets/style.scss b/modules/web-console/frontend/public/stylesheets/style.scss
new file mode 100644
index 0000000..4db7127
--- /dev/null
+++ b/modules/web-console/frontend/public/stylesheets/style.scss
@@ -0,0 +1,2171 @@
+/*
+ * 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 "./font-awesome-custom";
+@import "./bootstrap-custom";
+@import "./variables";
+@import "~roboto-font/css/fonts.css";
+@import "./../../app/directives/information/information.scss";
+@import "./blocks/error";
+
+hr {
+    margin: 20px 0;
+}
+
+.theme-line a.active {
+    font-weight: bold;
+    font-size: 1.1em;
+}
+
+.theme-line a:focus {
+    text-decoration: underline;
+    outline: none;
+}
+
+.navbar-default .navbar-brand, .navbar-default .navbar-brand:hover {
+    position: absolute;
+    left: 0;
+    text-align: center;
+}
+
+.navbar-brand {
+    padding: 5px 0;
+    margin: 10px 0;
+}
+
+.modal.center .modal-dialog {
+    position: fixed;
+    top: 50%;
+    left: 50%;
+    -webkit-transform: translateX(-50%) translateY(-50%);
+    transform: translateX(-50%) translateY(-50%);
+}
+
+.border-left {
+    box-shadow: 1px 0 0 0 $gray-lighter inset;
+}
+
+.border-right {
+    box-shadow: 1px 0 0 0 $gray-lighter;
+}
+
+.theme-line header {
+    background-color: $ignite-background-color;
+}
+
+.theme-line .docs-header h1 {
+    color: $ignite-header-color;
+    margin-top: 0;
+    font-size: 22px;
+}
+
+.theme-line .footer {
+    text-align: center;
+}
+
+.table.table-vertical-middle tbody > tr > td {
+  vertical-align: middle;
+}
+
+ul.navbar-nav, .sidebar-nav {
+    li.active > a {
+        color: $link-color;
+    }
+
+    li.active > a:not(.dropdown-toggle) {
+        cursor: default;
+        pointer-events: none;
+    }
+}
+
+.theme-line .sidebar-nav {
+    padding-bottom: 30px;
+
+    ul {
+        padding: 0;
+        list-style: none;
+        margin: 3px 0 0;
+
+        li {
+            line-height: $input-height;
+
+            a {
+                font-size: 18px;
+                color: $ignite-header-color;
+                position: relative;
+                white-space: nowrap;
+                overflow: hidden;
+                -o-text-overflow: ellipsis;
+                text-overflow: ellipsis;
+
+                span.fa-stack {
+                    margin-right: 5px;
+                    font-size: 12px;
+                    height: 26px;
+                }
+            }
+
+            a:hover { color: $link-hover-color; }
+
+            a.active {
+                color: $link-color;
+            }
+        }
+    }
+}
+
+.theme-line .sidebar-nav ul li a:hover {
+    text-decoration: none;
+}
+
+.theme-line .select {
+    li a.active {
+        color: $dropdown-link-active-color;
+    }
+
+    li a:hover {
+        color: $dropdown-link-hover-color;
+    }
+}
+
+.theme-line .select,
+.theme-line .typeahead {
+    .active {
+        font-size: 1em;
+        background-color: $gray-lighter;
+    }
+}
+
+.theme-line button.form-control.placeholder {
+    color: $input-color-placeholder;
+}
+
+.theme-line .summary-pojo-list > ul.dropdown-menu {
+    width: 100%;
+    max-width: none;
+}
+
+.tooltip {
+  word-wrap: break-word;
+}
+
+.theme-line ul.dropdown-menu {
+    min-width: 120px;
+    max-width: 280px;
+    max-height: 20em;
+    overflow: auto;
+    overflow-x: hidden;
+    outline-style: none;
+    margin-top: 0;
+
+    li > a {
+        display: block;
+
+        padding: 3px 10px;
+
+        overflow: hidden;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+
+        i {
+            float: right;
+            color: $brand-primary;
+            background-color: transparent;
+            line-height: $line-height-base;
+            margin-left: 5px;
+            margin-right: 0;
+        }
+    }
+
+    li > div {
+        display: block;
+        overflow: hidden;
+
+        i {
+            float: right;
+            color: $text-color;
+            background-color: transparent;
+            line-height: $line-height-base;
+            margin: 0 10px 0 0;
+            padding: 6px 0;
+        }
+
+        div {
+            overflow: hidden;
+            text-overflow: ellipsis;
+        }
+    }
+
+    // Hover/Focus state
+    li > div a {
+        float: left;
+        display: block;
+        width: 100%;
+        padding: 3px 10px;
+        color: $dropdown-link-color;
+
+        overflow: hidden;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+        
+        &:hover,
+        &:focus {
+            text-decoration: none;
+            color: $dropdown-link-hover-color;
+            background-color: $dropdown-link-hover-bg;
+        }
+    }
+
+    // Active state
+    .active > div a {
+        cursor: default;
+        pointer-events: none;
+
+        &,
+        &:hover,
+        &:focus {
+            color: $dropdown-link-active-color;
+            text-decoration: none;
+            outline: 0;
+            background-color: $dropdown-link-active-bg;
+        }
+    }
+
+    li.divider {
+        margin: 3px 0;
+    }
+}
+
+.theme-line .border-left .sidebar-nav {
+    padding-left: 15px;
+}
+
+.theme-line .suggest {
+    padding: 5px;
+    display: inline-block;
+    font-size: 12px;
+}
+
+.theme-line header {
+    border-bottom: 8px solid $ignite-border-bottom-color;
+
+    p {
+        color: $ignite-header-color;
+    }
+}
+
+.header .nav.navbar-nav.pull-right > li > a {
+    padding-right: 0;
+}
+
+.header .title {
+    margin: 20px 0 5px 0;
+    padding: 0 15px;
+
+    font-size: 1.4em;
+}
+
+.header .nav.navbar-nav .not-link {
+    padding: 15px;
+    display: inline-block;
+}
+
+.nav > li {
+    > a {
+        color: $navbar-default-link-color
+    }
+    > a:hover {
+        color: $link-hover-color
+    }
+    > a.active {
+        color: $link-color
+    }
+}
+
+.theme-line header .navbar-nav a {
+    line-height: 25px;
+    font-size: 18px;
+}
+
+.theme-line .section-right {
+    padding-left: 30px;
+}
+
+.body-overlap .main-content {
+    margin-top: 30px;
+}
+
+.body-box .main-content,
+.body-overlap .main-content {
+    padding: 30px;
+    box-shadow: 0 0 0 1px $ignite-border-color;
+    background-color: $ignite-background-color;
+}
+
+body {
+    font-weight: 400;
+}
+
+h1, h2, h3, h4, h5, h6 {
+    font-weight: 700;
+    margin-bottom: 10px;
+}
+
+.container-footer {
+    margin-top: 20px;
+    margin-bottom: 20px;
+
+    p {
+        font-size: 12px;
+        margin-bottom: 0;
+    }
+}
+
+/* Modal */
+.modal {
+    display: block;
+    overflow: hidden;
+}
+
+.modal .close {
+    position: absolute;
+    top: 10px;
+    right: 10px;
+    float: none;
+}
+
+.modal-header {
+    border-top-left-radius: 6px;
+    border-top-right-radius: 6px;
+}
+
+// Close icon
+.modal-header .close {
+    margin-right: -2px;
+}
+
+.modal .modal-dialog {
+    width: 650px;
+}
+
+.modal .modal-content {
+    background-color: $gray-lighter;
+
+    .input-tip {
+        padding-top: 1px;
+    }
+}
+
+.modal .modal-content .modal-header {
+    background-color: $ignite-background-color;
+    text-align: center;
+    color: $ignite-header-color;
+    padding: 15px 25px 15px 15px;
+}
+
+.modal .modal-content .modal-header h4 {
+    font-size: 22px;
+}
+
+.modal .modal-content .modal-footer {
+    margin-top: 0;
+}
+
+.modal-footer {
+    label {
+        float: left;
+        margin: 0;
+    }
+
+    .btn:last-child {
+        margin-right: 0;
+    }
+
+    .checkbox {
+        margin: 0;
+    }
+}
+
+.login-header {
+    margin-top: 0;
+    margin-bottom: 20px;
+    font-size: 2em;
+}
+
+.login-footer {
+    @extend .modal-footer;
+
+    padding-left: 0;
+    padding-right: 0;
+
+    .btn {
+        margin-right: 0;
+    }
+}
+
+.modal-body {
+    margin-left: 20px;
+    margin-right: 20px;
+}
+
+.modal-body-with-scroll {
+    max-height: 420px;
+    overflow-y: auto;
+    margin: 0;
+}
+
+.greedy {
+    min-height: 100%;
+    height: #{"calc(100vh - 270px)"};
+}
+
+.signin-greedy {
+    height: #{"calc(100vh - 300px)"};
+}
+
+@media (min-width: 768px) {
+    .navbar-nav > li > a {
+        padding: 0 15px;
+    }
+}
+
+.details-row {
+    padding: 0 5px;
+}
+
+.details-row, .settings-row {
+    display: block;
+    margin: 10px 0;
+
+    [class*="col-"] {
+        display: inline-block;
+        vertical-align: middle;
+        float: none;
+    }
+
+    input[type="checkbox"] {
+        line-height: 20px;
+        margin-right: 5px;
+    }
+
+    .checkbox label {
+        line-height: 20px !important;
+        vertical-align: middle;
+    }
+}
+
+.group-section {
+    margin-top: 20px;
+}
+
+.details-row:first-child {
+    margin-top: 0;
+
+    .group-section {
+        margin-top: 10px;
+    }
+}
+
+.details-row:last-child {
+    margin-bottom: 0;
+}
+
+.settings-row:first-child {
+    margin-top: 0;
+
+    .group-section {
+        margin-top: 0;
+    }
+}
+
+.settings-row:last-child {
+    margin-bottom: 0;
+}
+
+button, .btn {
+    margin-right: 5px;
+}
+
+i.btn {
+    margin-right: 0;
+}
+
+.btn {
+    padding: 3px 6px;
+
+    :focus {
+        //outline: none;
+        //border: 1px solid $btn-default-border;
+    }
+}
+
+.btn-group.pull-right {
+    margin-right: 0;
+}
+
+.btn-group {
+    margin-right: 5px;
+
+    > button, a.btn {
+        margin-right: 0;
+    }
+
+    button.btn + .btn {
+        margin-left: 0;
+    }
+
+    > .btn + .dropdown-toggle {
+        margin-right: 0;
+        padding: 3px 6px;
+        border-left-width: 0;
+    }
+}
+
+h1,
+h2,
+h3 {
+    user-select: none;
+    font-weight: normal;
+    /* Makes the vertical size of the text the same for all fonts. */
+    line-height: 1;
+}
+
+h3 {
+    font-size: 1.2em;
+    margin-top: 0;
+    margin-bottom: 1.5em;
+}
+
+.base-control {
+    text-align: left;
+    padding: 3px 3px;
+    height: $input-height;
+}
+
+.sql-name-input {
+    @extend .form-control;
+
+    width: auto;
+}
+
+.form-control {
+    @extend .base-control;
+
+    display: inline-block;
+
+    button {
+        text-align: left;
+    }
+}
+
+button.form-control {
+    display: block;
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+}
+
+.theme-line .notebook-header {
+    border-color: $gray-lighter;
+
+    h1 {
+        padding: 0;
+        margin: 0;
+
+        height: 40px;
+
+        label {
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+            margin-top: 5px;
+        }
+
+        .btn-group {
+            margin-top: -5px;
+            margin-left: 5px;
+        }
+
+        > i.btn {
+            float: right;
+            line-height: 30px;
+        }
+
+        input {
+            font-size: 22px;
+            height: 35px;
+        }
+
+        a.dropdown-toggle {
+            font-size: $font-size-base;
+            margin-right: 5px;
+        }
+    }
+}
+
+.theme-line .paragraphs {
+    .panel-group .panel + .panel {
+        margin-top: 30px;
+    }
+
+    .btn-group {
+        margin-right: 0;
+    }
+
+    .sql-editor {
+        padding: 5px 0;
+
+        .ace_cursor {
+            opacity: 1;
+        }
+
+        .ace_hidden-cursors {
+            opacity: 1;
+        }
+
+        .ace_gutter-cell, .ace_folding-enabled > .ace_gutter-cell {
+            padding-right: 5px;
+        }
+    }
+
+    table thead {
+        background-color: white;
+    }
+
+    .wrong-caches-filter {
+        text-align: center;
+        color: $ignite-placeholder-color;
+        height: 65px;
+        line-height: 65px;
+    }
+
+    .empty-caches {
+        text-align: center;
+        color: $ignite-placeholder-color;
+        height: 55px;
+        line-height: 55px;
+    }
+
+    .sql-controls {
+        border-top: 1px solid $ignite-border-color;
+
+        padding: 10px 10px;
+    }
+
+    .sql-result {
+        border-top: 1px solid $ignite-border-color;
+
+        .error {
+            padding: 10px 10px;
+
+            text-align: center;
+            color: $brand-primary;
+        }
+
+        .empty {
+            padding: 10px 10px;
+
+            text-align: center;
+            color: $ignite-placeholder-color;
+        }
+
+        .total {
+            padding: 10px 10px;
+        }
+
+        .table {
+            margin: 0
+        }
+
+        .chart {
+            margin: 0
+        }
+
+        .footer {
+            border-top: 1px solid $ignite-border-color;
+
+            padding: 5px 10px;
+        }
+    }
+}
+
+.theme-line .panel-heading {
+    padding: 5px 10px;
+    margin: 0;
+    cursor: pointer;
+    font-size: $font-size-large;
+    line-height: 24px;
+
+    label {
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+        max-width: calc(100% - 85px);
+        cursor: pointer;
+    }
+
+    .btn-group {
+        vertical-align:top;
+        margin-left: 10px;
+
+        i { line-height: 18px; }
+    }
+
+    > i {
+        vertical-align: top;
+        line-height: 26px;
+        height: 26px;
+    }
+
+    .fa {
+        line-height: 26px;
+    }
+
+    .fa-floppy-o {
+        float: right;
+    }
+
+    .fa-chevron-circle-right, .fa-chevron-circle-down {
+        font-size: $font-size-base;
+        color: inherit;
+        float: left;
+    }
+
+    .fa-undo {
+        padding: 1px 6px;
+
+        font-size: 16px;
+    }
+
+    .fa-undo:hover {
+        padding: 0 5px;
+
+        border-radius: 5px;
+        border: thin dotted $ignite-darck-border-color;
+    }
+}
+
+.theme-line .panel-heading:hover {
+    text-decoration: underline;
+}
+
+.theme-line .panel-body {
+    padding: 20px;
+}
+
+.theme-line .main-content a.customize {
+    margin-left: 5px;
+}
+
+.theme-line .panel-collapse {
+    margin: 0;
+}
+
+.theme-line table.links {
+    table-layout: fixed;
+    border-collapse: collapse;
+
+    width: 100%;
+
+    label.placeholder {
+        text-align: center;
+        color: $ignite-placeholder-color;
+        width: 100%;
+    }
+
+    input[type="text"] {
+        font-weight: normal;
+    }
+
+    input[type="radio"] {
+        margin-left: 1px;
+        margin-right: 5px;
+    }
+
+    tbody {
+        border-left: 10px solid transparent;
+    }
+
+    tbody td:first-child {
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+    }
+
+    tfoot > tr > td {
+        padding: 0;
+
+        .pagination {
+            margin: 10px 0;
+
+            > .active > a {
+                border-color: $table-border-color;
+                background-color: $gray-lighter;
+            }
+        }
+    }
+}
+
+.theme-line table.links-edit {
+    @extend table.links;
+
+    margin-top: 0;
+    margin-bottom: 5px;
+
+    label {
+        line-height: $input-height;
+    }
+
+    td {
+        padding-left: 0;
+    }
+}
+
+.theme-line table.links-edit-sub {
+    @extend table.links-edit;
+
+    margin-top: 0;
+    margin-bottom: 0;
+}
+
+.theme-line table.links-edit-details {
+    @extend table.links;
+
+    margin-bottom: 10px;
+
+    label {
+        line-height: $input-height;
+        color: $ignite-header-color;
+    }
+
+    td {
+        padding: 0;
+
+        .input-tip {
+            padding: 0;
+        }
+    }
+}
+
+.theme-line table.admin {
+    tr:hover {
+        cursor: default;
+    }
+
+    thead {
+        .pagination {
+            margin: 0;
+        }
+    }
+
+    thead > tr th.header {
+        padding: 0 0 10px;
+
+        div {
+            padding: 0;
+        }
+
+        input[type="text"] {
+            font-weight: normal;
+        }
+    }
+
+    margin-bottom: 10px;
+
+    label {
+        line-height: $input-height;
+        color: $ignite-header-color;
+    }
+
+    thead > tr th, td {
+        padding: 10px 10px;
+
+        .input-tip {
+            padding: 0;
+        }
+    }
+
+    tfoot > tr > td {
+        padding: 0;
+    }
+
+    .pagination {
+        margin: 10px 0;
+        font-weight: normal;
+
+        > .active > a {
+            border-color: $table-border-color;
+            background-color: $gray-lighter;
+        }
+    }
+}
+
+.admin-summary {
+    padding-bottom: 10px;
+}
+
+.import-domain-model-wizard-page {
+    margin: 15px;
+}
+
+.scrollable-y {
+    overflow-x: hidden;
+    overflow-y: auto;
+}
+
+.theme-line table.metadata {
+    margin-bottom: 10px;
+
+    tr:hover {
+        cursor: default;
+    }
+
+    thead > tr {
+        label {
+            font-weight: bold;
+        }
+
+        input[type="checkbox"] {
+            cursor: pointer;
+        }
+    }
+
+    thead > tr th.header {
+        padding: 0 0 10px;
+
+        .pull-right {
+            padding: 0;
+        }
+
+        input[type="checkbox"] {
+            cursor: pointer;
+        }
+
+        input[type="text"] {
+            font-weight: normal;
+        }
+    }
+
+    > thead > tr > th {
+        padding: 5px 0 5px 5px !important;
+    }
+
+    tbody > tr > td {
+        padding: 0;
+    }
+}
+
+.td-ellipsis {
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+}
+
+.table-modal-striped {
+    width: 100%;
+
+    > tbody > tr {
+        border-bottom: 2px solid $ignite-border-color;
+
+        input[type="checkbox"] {
+            cursor: pointer;
+        }
+    }
+
+    > tbody > tr > td {
+        padding: 5px 0 5px 5px !important;
+    }
+}
+
+.theme-line table.sql-results {
+    margin: 0;
+
+    td {
+        padding: 3px 6px;
+    }
+
+    > thead > tr > td {
+        padding: 3px 0;
+    }
+
+    thead > tr > th {
+        padding: 3px 6px;
+
+        line-height: $input-height;
+    }
+
+    tfoot > tr > td {
+        padding: 0;
+
+        .pagination {
+            margin: 10px 0 0 0;
+
+            > .active > a {
+                border-color: $table-border-color;
+                background-color: $gray-lighter;
+            }
+        }
+    }
+}
+
+.affix {
+    z-index: 910;
+    background-color: white;
+
+    hr {
+        margin: 0;
+    }
+}
+
+.affix.padding-top-dflt {
+    hr {
+        margin-top: 10px;
+    }
+}
+
+.affix + .bs-affix-fix {
+    height: 78px;
+}
+
+.panel-details {
+    margin-top: 5px;
+    padding: 10px 5px;
+
+    border-radius: 5px;
+    border: thin dotted $ignite-border-color;
+}
+
+.panel-details-noborder {
+    margin-top: 5px;
+    padding: 10px 5px;
+}
+
+.group {
+    border-radius: 5px;
+    border: thin dotted $ignite-border-color;
+
+    text-align: left;
+
+    hr {
+        margin: 7px 0;
+    }
+}
+
+.group-legend {
+    margin: -10px 5px 0 10px;
+    overflow: visible;
+    position: relative;
+
+    label {
+        padding: 0 5px;
+        background: white;
+    }
+}
+
+.group-legend-btn {
+    background: white;
+    float: right;
+    line-height: 20px;
+    padding: 0 5px 0 5px;
+}
+
+.group-content {
+    margin: 10px;
+
+    table {
+        width: 100%;
+    }
+}
+
+.group-content-empty {
+    color: $input-color-placeholder;
+
+    padding: 10px 0;
+    position: relative;
+
+    text-align: center;
+}
+
+.content-not-available {
+    min-height: 28px;
+
+    margin-right: 20px;
+
+    border-radius: 5px;
+    border: thin dotted $ignite-border-color;
+
+    padding: 0;
+
+    color: $input-color-placeholder;
+    display: table;
+    width: 100%;
+    height: 26px;
+
+    label {
+        display: table-cell;
+        text-align: center;
+        vertical-align: middle;
+    }
+}
+
+.tooltip > .tooltip-inner {
+    text-align: left;
+    border: solid 1px #ccc;
+}
+
+.popover-footer {
+    margin: 0; // reset heading margin
+    padding: 8px 14px;
+    font-size: $font-size-base;
+    color: $input-color-placeholder;
+    background-color: $popover-title-bg;
+    border-top: 1px solid darken($popover-title-bg, 5%);
+    border-radius: 0 0 ($border-radius-large - 1) ($border-radius-large - 1);
+}
+
+.popover-content {
+    padding: 5px;
+}
+
+.popover:focus {
+    outline: none;
+    border: 1px solid $btn-default-border;
+}
+
+.theme-line .popover.settings {
+    .close {
+        position: absolute;
+        top: 5px;
+        right: 5px;
+    }
+}
+
+.theme-line .popover.cache-metadata {
+    @extend .popover.settings;
+
+    position: absolute;
+    z-index: 1030;
+    min-width: 305px;
+    max-width: 450px;
+
+    .popover-title {
+        color: black;
+
+        line-height: 27px;
+
+        padding: 3px 5px 3px 10px;
+
+        white-space: nowrap;
+        overflow: hidden;
+        -o-text-overflow: ellipsis;
+        text-overflow: ellipsis;
+
+        .close {
+            float: right;
+            top: 0;
+            right: 0;
+            position: relative;
+            margin-left: 10px;
+            line-height: 27px;
+        }
+    }
+
+    > .popover-content {
+        overflow: auto;
+
+        white-space: nowrap;
+
+        min-height: 400px;
+        max-height: 400px;
+
+        .content-empty {
+            display: block;
+            text-align: center;
+            line-height: 380px;
+
+            color: $input-color-placeholder;
+        }
+    }
+
+    .clickable { cursor: pointer; }
+}
+
+.theme-line .popover.summary-project-structure {
+    @extend .popover.settings;
+
+    z-index: 1030;
+    min-width: 305px;
+
+    .popover-title {
+        color: black;
+
+        line-height: 27px;
+
+        padding: 3px 5px 3px 10px;
+
+        white-space: nowrap;
+        overflow: hidden;
+        -o-text-overflow: ellipsis;
+        text-overflow: ellipsis;
+
+        .close {
+            float: right;
+            top: 0;
+            right: 0;
+            position: relative;
+            margin-left: 10px;
+            line-height: 27px;
+        }
+    }
+
+    > .popover-content {
+        overflow: auto;
+
+        white-space: nowrap;
+
+        min-height: 300px;
+        max-height: 300px;
+    }
+}
+
+.theme-line .popover.validation-error {
+    max-width: 400px;
+    color: $brand-primary;
+    background: white;
+    border: 1px solid $brand-primary;
+
+    &.right > .arrow {
+        border-right-color: $brand-primary;
+    }
+
+    .close {
+        vertical-align: middle;
+    }
+}
+
+label {
+    font-weight: normal;
+    margin-bottom: 0;
+}
+
+.form-horizontal .checkbox {
+    padding-top: 0;
+    min-height: 0;
+}
+
+.input-tip {
+    display: block;
+    overflow: hidden;
+    position: relative;
+}
+
+.labelHeader {
+    font-weight: bold;
+    text-transform: capitalize;
+}
+
+.labelField {
+    float: left;
+    margin-right: 5px;
+}
+
+.labelFormField {
+    float: left;
+    line-height: $input-height;
+}
+
+.labelLogin {
+    margin-right: 10px;
+}
+
+.form-horizontal .form-group {
+    margin: 0;
+}
+
+.form-horizontal .has-feedback .form-control-feedback {
+    right: 0;
+}
+
+.tipField {
+    float: right;
+    line-height: $input-height;
+    margin-left: 5px;
+}
+
+.tipLabel {
+    font-size: $font-size-base;
+    margin-left: 5px;
+}
+
+.fieldSep {
+    float: right;
+    line-height: $input-height;
+    margin: 0 5px;
+}
+
+.fieldButton {
+    float: right;
+    margin-left: 5px;
+    margin-right: 0;
+}
+
+.fa {
+    cursor: pointer;
+}
+
+.fa-cursor-default {
+    cursor: default !important;
+}
+
+.fa-remove {
+    color: $brand-primary;
+}
+
+.fa-chevron-circle-down {
+    color: $brand-primary;
+    margin-right: 5px;
+}
+
+.fa-chevron-circle-right {
+    color: $brand-primary;
+    margin-right: 5px;
+}
+
+.fa-question-circle {
+    cursor: default;
+}
+
+label.required:after {
+    color: $brand-primary;
+    content: ' *';
+    display: inline;
+}
+
+.blank {
+    visibility: hidden;
+}
+
+.alert {
+    outline: 0;
+    padding: 10px;
+    position: fixed;
+    z-index: 1050;
+    margin: 20px;
+    max-width: 700px;
+
+    &.top-right {
+        top: 60px;
+        right: 0;
+
+        .close {
+            padding-left: 10px;
+        }
+    }
+
+    .alert-icon {
+        padding-right: 10px;
+        font-size: 16px;
+    }
+
+    .alert-title {
+        color: $text-color;
+    }
+
+    .close {
+        margin-right: 0;
+        line-height: 19px;
+    }
+}
+
+.summary-tabs {
+    margin-top: 0.65em;
+}
+
+.summary-tab {
+    img {
+        margin-right: 5px;
+        height: 16px;
+        width: 16px;
+        float: left;
+    }
+}
+
+input[type="number"]::-webkit-outer-spin-button,
+input[type="number"]::-webkit-inner-spin-button {
+    -webkit-appearance: none;
+    margin: 0;
+}
+
+input[type="number"] {
+    -moz-appearance: textfield;
+}
+
+input.ng-dirty.ng-invalid, button.ng-dirty.ng-invalid {
+    border-color: $ignite-invalid-color;
+
+    :focus {
+        border-color: $ignite-invalid-color;
+    }
+}
+
+.form-control-feedback {
+    display: inline-block;
+    color: $brand-primary;
+    line-height: $input-height;
+    pointer-events: initial;
+}
+
+.theme-line .nav-tabs > li > a {
+    padding: 5px 5px;
+    color: $ignite-header-color;
+}
+
+.viewedUser {
+    text-align: center;
+    background-color: $brand-warning;
+}
+
+a {
+    cursor: pointer;
+}
+
+.st-sort-ascent:after {
+    content: '\25B2';
+}
+
+.st-sort-descent:after {
+    content: '\25BC';
+}
+
+th[st-sort] {
+    cursor: pointer;
+}
+
+.panel {
+    margin-bottom: 0;
+}
+
+.panel-group {
+    margin-bottom: 0;
+}
+
+.panel-group .panel + .panel {
+    margin-top: 20px;
+}
+
+.section {
+    margin-top: 20px;
+}
+
+.section-top {
+    width: 100%;
+    margin-top: 10px;
+    margin-bottom: 20px;
+}
+
+.advanced-options {
+    @extend .section;
+    margin-bottom: 20px;
+
+    i {
+        font-size: 16px;
+    }
+}
+
+.modal-advanced-options {
+    @extend .advanced-options;
+    margin-top: 10px;
+    margin-bottom: 10px;
+}
+
+.margin-left-dflt {
+    margin-left: 10px;
+}
+
+.margin-top-dflt {
+    margin-top: 10px;
+}
+
+.margin-top-dflt-2x {
+    margin-top: 20px;
+}
+
+.margin-bottom-dflt {
+    margin-bottom: 10px;
+}
+
+.margin-dflt {
+    margin-top: 10px;
+    margin-bottom: 10px;
+}
+
+.padding-top-dflt {
+    padding-top: 10px;
+}
+
+.padding-left-dflt {
+    padding-left: 10px;
+}
+
+.padding-bottom-dflt {
+    padding-bottom: 10px;
+}
+
+.padding-dflt {
+    padding-top: 10px;
+    padding-bottom: 10px;
+}
+
+.agent-download {
+    padding: 10px 10px 10px 20px;
+}
+
+.ace_content {
+    padding-left: 5px;
+}
+
+.ace_hidden-cursors {
+    opacity: 0;
+}
+
+.ace_cursor {
+    opacity: 0;
+}
+
+.ace_editor {
+    margin: 10px 5px 10px 0;
+
+    .ace_gutter {
+        background: transparent !important;
+        border: 1px $ignite-border-color;
+        border-right-style: solid;
+    }
+
+    .ace_gutter-cell, .ace_folding-enabled > .ace_gutter-cell {
+        padding-left: 0.65em;
+    }
+}
+
+.preview-highlight-1 {
+    position: absolute;
+    background-color: #f7faff;
+    z-index: 20;
+}
+
+.preview-highlight-2 {
+    position: absolute;
+    background-color: #f0f6ff;
+    z-index: 21;
+}
+
+.preview-highlight-3 {
+    position: absolute;
+    background-color: #e8f2ff;
+    z-index: 22;
+}
+
+.preview-highlight-4 {
+    position: absolute;
+    background-color: #e1eeff;
+    z-index: 23;
+}
+
+.preview-highlight-5 {
+    position: absolute;
+    background-color: #DAEAFF;
+    z-index: 24;
+}
+
+.preview-highlight-6 {
+    position: absolute;
+    background-color: #D2E5FF;
+    z-index: 25;
+}
+
+.preview-highlight-7 {
+    position: absolute;
+    background-color: #CBE1FF;
+    z-index: 26;
+}
+
+.preview-highlight-8 {
+    position: absolute;
+    background-color: #C3DDFF;
+    z-index: 27;
+}
+
+.preview-highlight-9 {
+    position: absolute;
+    background-color: #BCD9FF;
+    z-index: 28;
+}
+
+.preview-highlight-10 {
+    position: absolute;
+    background-color: #B5D5FF;
+    z-index: 29;
+}
+
+.preview-panel {
+    min-height: 28px;
+
+    margin-left: 20px;
+
+    border-radius: 5px;
+    border: thin dotted $ignite-border-color;
+
+    padding: 0;
+}
+
+.preview-legend {
+    top: -10px;
+    right: 20px;
+    position: absolute;
+    z-index: 900;
+
+    a {
+        background-color: white;
+        margin-left: 5px;
+        font-size: 0.9em;
+    }
+
+    .inactive {
+        color: $input-color-placeholder;
+    }
+}
+
+.preview-content-empty {
+    color: $input-color-placeholder;
+    display: table;
+    width: 100%;
+    height: 26px;
+
+    label {
+        display: table-cell;
+        text-align: center;
+        vertical-align: middle;
+    }
+}
+
+.chart-settings-link {
+    padding-left: 10px;
+    line-height: $input-height;
+
+    label, button {
+        margin-left: 5px;
+        margin-right: 0;
+    }
+
+    button.select-manual-caret {
+        padding-right: 3px;
+
+        .caret { margin-left: 3px; }
+    }
+
+    a, i {
+        font-size: $font-size-base;
+        color: $link-color !important;
+        margin-right: 5px;
+    }
+
+    div {
+        margin-left: 20px;
+        display: inline-block;
+    }
+}
+
+.chart-settings {
+    margin: 10px 5px 5px 5px !important;
+}
+
+.chart-settings-columns-list {
+    border: 1px solid $ignite-border-color;
+    list-style: none;
+    margin-bottom: 10px;
+    min-height: 30px;
+    max-height: 200px;
+    padding: 5px;
+
+    overflow: auto;
+
+    & > li {
+        float: left;
+    }
+
+    li:nth-child(even) {
+        margin-right: 0;
+    }
+
+    .fa-close {
+        margin-left: 10px;
+    }
+}
+
+.btn-chart-column {
+    border-radius: 3px;
+    font-size: 12px;
+    margin: 3px 3px;
+    padding: 1px 5px;
+    line-height: 1.5;
+    cursor: default;
+}
+
+.btn-chart-column-movable {
+    @extend .btn-chart-column;
+    cursor: move;
+}
+
+.btn-chart-column-agg-fx {
+    border: 0;
+    margin: 0 0 0 10px;
+}
+
+.dw-loading {
+    min-height: 100px;
+}
+
+.dw-loading > .dw-loading-body > .dw-loading-text {
+    left: -50%;
+}
+
+.dw-loading.dw-loading-overlay {
+    z-index: 1030;
+}
+
+.modal {
+    .dw-loading.dw-loading-overlay {
+        z-index: 9999;
+    }
+
+    .dw-loading-body {
+        left: 10%;
+    }
+}
+
+.panel-tip-container {
+    display: inline-block;
+}
+
+button.dropdown-toggle {
+    margin-right: 5px;
+}
+
+button.select-toggle {
+    position: relative;
+    padding-right: 15px;
+}
+
+button.select-toggle::after {
+    content: "";
+    border-top: 0.3em solid;
+    border-right: 0.3em solid transparent;
+    border-left: 0.3em solid transparent;
+    position: absolute;
+    right: 5px;
+    top: 50%;
+    vertical-align: middle;
+}
+
+// Prevent scroll bars from being hidden for OS X.
+::-webkit-scrollbar {
+    -webkit-appearance: none;
+}
+
+::-webkit-scrollbar:vertical {
+    width: 10px;
+}
+
+::-webkit-scrollbar:horizontal {
+    height: 10px;
+}
+
+::-webkit-scrollbar-thumb {
+    border-radius: 8px;
+    border: 2px solid white; /* should match background, can't be transparent */
+    background-color: rgba(0, 0, 0, .5);
+}
+
+::-webkit-scrollbar-track {
+    background-color: white;
+    border-radius: 8px;
+}
+
+treecontrol.tree-classic {
+    > ul > li {
+        padding: 0;
+    }
+
+    li {
+        padding-left: 15px;
+    }
+
+    li.tree-expanded i.tree-branch-head.fa, li.tree-collapsed i.tree-branch-head.fa, li.tree-leaf i.tree-branch-head.fa, .tree-label i.fa {
+        background: none no-repeat;
+        padding: 1px 5px 1px 1px;
+    }
+
+    li.tree-leaf i.tree-leaf-head {
+        background: none no-repeat !important;
+        padding: 0 !important;
+    }
+
+    li .tree-selected {
+        background-color: white;
+        font-weight: normal;
+    }
+
+    span {
+        margin-right: 10px;
+    }
+}
+
+.docs-content {
+    .affix {
+        border-bottom: 1px solid $gray-lighter;
+    }
+
+    min-height: 100px;
+}
+
+.carousel-caption {
+    position: relative;
+    left: auto;
+    right: auto;
+
+    margin-top: 10px;
+
+    h3 {
+        margin-bottom: 10px;
+    }
+}
+
+.carousel-control {
+    font-size: 20px;
+    z-index: 16;
+
+    // Toggles
+    .fa-chevron-left,.fa-chevron-right {
+        position: absolute;
+        bottom: 28px;
+        margin-top: -10px;
+        z-index: 16;
+        display: inline-block;
+        margin-left: -10px;
+    }
+
+    .fa-chevron-left {
+        left: 90%;
+        margin-left: -10px;
+    }
+
+    .fa-chevron-right {
+        right: 90%;
+        margin-right: -10px;
+    }
+}
+
+.carousel-control.left {
+    background-image: none;
+}
+
+.carousel-control.right {
+    background-image: none;
+}
+
+.getting-started-puzzle {
+    margin-left: 20px;
+}
+
+.getting-started {
+    margin: 15px 15px 300px;
+}
+
+.getting-started-demo {
+    color: $brand-info;
+}
+
+.home-panel {
+    border-radius: 5px;
+    border: thin dotted $panel-default-border;
+    background-color: $panel-default-heading-bg;
+
+    margin-top: 20px;
+    padding: 10px;
+}
+
+.home {
+    min-height: 880px;
+    padding: 20px;
+
+    @media(min-width: 992px) {
+        min-height: 450px;
+    }
+}
+
+.additional-filter {
+    input[type="checkbox"] {
+        position: absolute;
+        margin-top: 8px;
+    }
+
+    a {
+        font-weight: normal;
+        padding-left: 20px;
+        float: none;
+    }
+}
+
+.grid {
+    .ui-grid-header-cell .ui-grid-cell-contents {
+        text-align: center;
+
+        > span:not(.ui-grid-header-cell-label) {
+            position: absolute;
+            right: -3px;
+        }
+    }
+
+    .ui-grid-cell .ui-grid-cell-contents {
+        text-align: center;
+        white-space: pre;
+
+        > i.fa {
+            cursor: default;
+        }
+    }
+
+    .ui-grid-column-menu-button {
+        right: -3px;
+    }
+
+    .ui-grid-menu-button {
+        margin-top: -1px;
+    }
+
+    .ui-grid-column-menu-button-last-col {
+        margin-right: 0
+    }
+
+    .no-rows {
+        .center-container {
+            background: white;
+
+            .centered > div {
+                display: inline-block;
+                padding: 10px;
+
+                opacity: 1;
+
+                background-color: #f5f5f5;
+                border-radius: 6px;
+                border: 1px solid $ignite-darck-border-color;
+            }
+        }
+    }
+}
+
+.cell-right .ui-grid-cell-contents {
+    text-align: right !important;
+}
+
+.cell-left .ui-grid-cell-contents {
+    text-align: left !important;
+}
+
+.grid.ui-grid {
+    border-left-width: 0;
+    border-right-width: 0;
+    border-bottom-width: 0;
+}
+
+.summary-tabs {
+    .nav-tabs > li:first-child,
+    .nav-tabs > li:first-child.active {
+        & > a,
+        & > a:focus,
+        & > a:hover {
+            border-left: none;
+            border-top-left-radius: 0;
+        }
+    }
+}
+
+.ribbon-wrapper {
+    width: 150px;
+    height: 150px;
+    position: absolute;
+    overflow: hidden;
+    top: 0;
+    z-index: 1001;
+    pointer-events: none;
+}
+
+.ribbon-wrapper.right {
+    right: 0;
+}
+
+.ribbon {
+    position: absolute;
+    top: 42px;
+    width: 200px;
+    padding: 1px 0;
+    color: $btn-primary-color;
+    background: $btn-primary-border;
+
+    -moz-box-shadow: 0 0 10px rgba(0,0,0,0.5);
+    -webkit-box-shadow: 0 0 10px rgba(0,0,0,0.5);
+    box-shadow: 0 0 10px rgba(0,0,0,0.5);
+
+    right: -42px;
+    -moz-transform: rotate(45deg);
+    -webkit-transform: rotate(45deg);
+    -o-transform: rotate(45deg);
+    -ms-transform: rotate(45deg);
+    transform: rotate(45deg);
+
+    > label {
+        display: block;
+        padding: 1px 0;
+        height: 24px;
+        line-height: 18px;
+
+        text-align: center;
+        text-decoration: none;
+        font-family: $font-family-sans-serif;
+        font-size: 20px;
+        font-weight: 500;
+
+        border: 1px solid rgba(255,255,255,0.3);
+
+        -moz-text-shadow: 0 0 10px rgba(0,0,0,0.31);
+        -webkit-text-shadow: 0 0 10px rgba(0,0,0,0.31);
+        text-shadow: 0 0 10px rgba(0,0,0,0.31);
+    }
+}
+
+html,body,.splash-screen {
+    width: 100%;
+    height: 100%;
+}
+
+.splash {
+    position: fixed;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    top: 0;
+    opacity: 1;
+    background-color: white;
+    z-index: 99999;
+
+    .splash-wrapper {
+        display: inline-block;
+        vertical-align: middle;
+        position: relative;
+        width: 100%;
+    }
+
+    .splash-wellcome {
+        font-size: 18px;
+        margin: 20px 0;
+        text-align: center;
+    }
+}
+
+.splash:before {
+  content: '';
+  display: inline-block;
+  height: 100%;
+  vertical-align: middle;
+}
+
+.spinner {
+    margin: 0 auto;
+    width: 100px;
+    text-align: center;
+
+    > div {
+        width: 18px;
+        height: 18px;
+        margin: 0 5px;
+        border-radius: 100%;
+        display: inline-block;
+        -webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both;
+        animation: sk-bouncedelay 1.4s infinite ease-in-out both;
+        background-color: $brand-primary;
+    }
+
+    .bounce1 {
+        -webkit-animation-delay: -0.32s;
+        animation-delay: -0.32s;
+    }
+
+    .bounce2 {
+        -webkit-animation-delay: -0.16s;
+        animation-delay: -0.16s;
+    }
+}
+
+@-webkit-keyframes sk-bouncedelay {
+    0%, 80%, 100% {
+        -webkit-transform: scale(0)
+    }
+    40% {
+        -webkit-transform: scale(1.0)
+    }
+}
+
+@keyframes sk-bouncedelay {
+    0%, 80%, 100% {
+        -webkit-transform: scale(0);
+        transform: scale(0);
+    }
+    40% {
+        -webkit-transform: scale(1.0);
+        transform: scale(1.0);
+    }
+}
+
+[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
+    display: none !important;
+}
+
+.nvd3 .nv-axis .nv-axisMaxMin text {
+    font-weight: normal; /* Here the text can be modified*/
+}
+
+[ng-hide].ng-hide-add.ng-hide-animate {
+    display: none;
+}
+
+[ng-show].ng-hide-add.ng-hide-animate {
+    display: none;
+}
+
+@media only screen and (max-width: 767px) {
+    .container{
+        padding: 0 $padding-small-horizontal;
+    }
+}
+
+.domains-import-dialog {
+    .modal-body {
+        height: 325px;
+        margin: 0;
+        padding: 0;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/stylesheets/variables.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/stylesheets/variables.scss b/modules/web-console/frontend/public/stylesheets/variables.scss
new file mode 100644
index 0000000..8500eac
--- /dev/null
+++ b/modules/web-console/frontend/public/stylesheets/variables.scss
@@ -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 "bootstrap-variables";
+
+$logo-path: "/images/logo.png";
+$input-height: 28px;
+$ignite-placeholder-color: #999999;
+$ignite-border-color: #ddd;
+$ignite-darck-border-color: #aaa;
+$ignite-border-bottom-color: $brand-primary;
+$ignite-background-color: #fff;
+$ignite-header-color: #555;
+$ignite-invalid-color: $brand-primary;

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/test/e2e/exampe.test.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/test/e2e/exampe.test.js b/modules/web-console/frontend/test/e2e/exampe.test.js
new file mode 100644
index 0000000..c778c79
--- /dev/null
+++ b/modules/web-console/frontend/test/e2e/exampe.test.js
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+suite('ExampleTestSuite', () => {
+    setup(() => {
+        // browser.get('http://localhost:9000/');
+    });
+
+    test('initially has a greeting', (done) => {
+        done();
+
+        // element(by.model('ui.email')).sendKeys('jhon@doe.com');
+    });
+
+    test('initially has a greeting', (done) => {
+        done();
+
+        // element(by.model('ui.email')).sendKeys('jhon@doe.com');
+    });
+
+    test('initially has a greeting', (done) => {
+        done();
+
+        // element(by.model('ui.email')).sendKeys('jhon@doe.com');
+    });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/test/karma.conf.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/test/karma.conf.js b/modules/web-console/frontend/test/karma.conf.js
new file mode 100644
index 0000000..e13ba00
--- /dev/null
+++ b/modules/web-console/frontend/test/karma.conf.js
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const path = require('path');
+const webpack = require('webpack');
+
+const basePath = path.resolve('./');
+
+module.exports = function(config) {
+    config.set({
+        // Base path that will be used to resolve all patterns (eg. files, exclude).
+        basePath: basePath,
+
+        // Frameworks to use available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+        frameworks: ['mocha'],
+
+        // List of files / patterns to load in the browser.
+        files: [
+            'test/**/*.test.js'
+        ],
+
+        plugins: [
+            require('karma-phantomjs-launcher'),
+            require('karma-teamcity-reporter'),
+            require('karma-webpack'),
+            require('karma-mocha')
+        ],
+
+        // Preprocess matching files before serving them to the browser
+        // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor.
+        preprocessors: {
+            'test/**/*.js': ['webpack']
+        },
+
+        webpack: {
+            module: {
+                loaders: [
+                    {
+                        test: /\.json$/,
+                        loader: 'json'
+                    },
+                    {
+                        test: /\.js$/,
+                        loader: 'babel',
+                        exclude: /node_modules/
+                    }
+                ]
+            },
+            resolve: {
+                extensions: ["", ".js"]
+            },
+            plugins: [
+                new webpack.ProvidePlugin({
+                    _: 'lodash'
+                })
+            ]
+        },
+
+        webpackMiddleware: {
+            noInfo: true
+        },
+
+        // Test results reporter to use
+        // possible values: 'dots', 'progress'
+        // available reporters: https://npmjs.org/browse/keyword/karma-reporter.
+        reporters: ['teamcity'],
+
+        // web server port
+        port: 9876,
+
+        // enable / disable colors in the output (reporters and logs)
+        colors: true,
+
+        // level of logging
+        // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+        logLevel: config.LOG_INFO,
+
+        // enable / disable watching file and executing tests whenever any file changes
+        autoWatch: true,
+
+        // start these browsers
+        // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+        browsers: ['PhantomJS'],
+
+        // Continuous Integration mode
+        // if true, Karma captures browsers, runs the tests and exits
+        singleRun: true,
+
+        // Concurrency level
+        // how many browser should be started simultaneous
+        concurrency: Infinity,
+
+        client: {
+            mocha: {
+                ui: 'tdd'
+            }
+        }
+    });
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/test/protractor.conf.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/test/protractor.conf.js b/modules/web-console/frontend/test/protractor.conf.js
new file mode 100644
index 0000000..3386e66
--- /dev/null
+++ b/modules/web-console/frontend/test/protractor.conf.js
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+// exports.config = {
+//   specs: ['test/e2e/*.js'],
+//   capabilities: {
+
+//   }
+// };
+
+exports.config = {
+  seleniumAddress: 'http://localhost:4444/wd/hub',
+
+  capabilities: {
+    'browserName': 'chrome'
+    // 'browserName': 'phantomjs',
+
+    // /*
+    //  * Can be used to specify the phantomjs binary path.
+    //  * This can generally be ommitted if you installed phantomjs globally.
+    //  */
+    // 'phantomjs.binary.path': require('phantomjs').path,
+
+    // /*
+    //  * Command line args to pass to ghostdriver, phantomjs's browser driver.
+    //  * See https://github.com/detro/ghostdriver#faq
+    //  */
+    // 'phantomjs.ghostdriver.cli.args': ['--loglevel=DEBUG']
+  },
+
+  specs: ['test/e2e/*.js'],
+
+  jasmineNodeOpts: {
+    showColors: true
+  }
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/test/unit/JavaTypes.test.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/test/unit/JavaTypes.test.js b/modules/web-console/frontend/test/unit/JavaTypes.test.js
new file mode 100644
index 0000000..25c0f67
--- /dev/null
+++ b/modules/web-console/frontend/test/unit/JavaTypes.test.js
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import JavaTypes from '../../app/services/JavaTypes.service.js';
+
+import { assert } from 'chai';
+
+const { nonBuiltInClass, fullClassName, validIdentifier, validPackage, packageSpecified, isKeywords, isJavaPrimitive} = JavaTypes[1]();
+
+suite('JavaTypesTestsSuite', () => {
+    test('nonBuiltInClass', () => {
+        assert.equal(nonBuiltInClass('BigDecimal'), false);
+        assert.equal(nonBuiltInClass('java.math.BigDecimal'), false);
+
+        assert.equal(nonBuiltInClass('String'), false);
+        assert.equal(nonBuiltInClass('java.lang.String'), false);
+
+        assert.equal(nonBuiltInClass('Timestamp'), false);
+        assert.equal(nonBuiltInClass('java.sql.Timestamp'), false);
+
+        assert.equal(nonBuiltInClass('Date'), false);
+        assert.equal(nonBuiltInClass('java.sql.Date'), false);
+
+        assert.equal(nonBuiltInClass('Date'), false);
+        assert.equal(nonBuiltInClass('java.util.Date'), false);
+
+        assert.equal(nonBuiltInClass('CustomClass'), true);
+        assert.equal(nonBuiltInClass('java.util.CustomClass'), true);
+        assert.equal(nonBuiltInClass('my.package.CustomClass'), true);
+    });
+
+    test('fullClassName', () => {
+        assert.equal(fullClassName('BigDecimal'), 'java.math.BigDecimal');
+    });
+
+    test('validIdentifier', () => {
+        assert.equal(validIdentifier('java.math.BigDecimal'), true);
+    });
+
+    test('validPackage', () => {
+        assert.equal(validPackage('java.math.BigDecimal'), true);
+    });
+
+    test('packageSpecified', () => {
+        assert.equal(packageSpecified('java.math.BigDecimal'), true);
+    });
+
+    test('isKeywords', () => {
+        assert.equal(isKeywords('abstract'), true);
+    });
+
+    test('isJavaPrimitive', () => {
+        assert.equal(isJavaPrimitive('boolean'), true);
+    });
+});

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/test/unit/UserAuth.test.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/test/unit/UserAuth.test.js b/modules/web-console/frontend/test/unit/UserAuth.test.js
new file mode 100644
index 0000000..dbba1f6
--- /dev/null
+++ b/modules/web-console/frontend/test/unit/UserAuth.test.js
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import AuthService from '../../app/modules/user/Auth.service';
+
+suite('AuthServiceTestsSuite', () => {
+    test('SignIn', (done) => {
+        // TODO IGNITE-3262 Add test.
+        done();
+    });
+
+    test('SignUp', (done) => {
+        // TODO IGNITE-3262 Add test.
+        done();
+    });
+
+    test('Logout', (done) => {
+        // TODO IGNITE-3262 Add test.
+        done();
+    });
+});

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/403.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/403.jade b/modules/web-console/frontend/views/403.jade
new file mode 100644
index 0000000..38d8bb5
--- /dev/null
+++ b/modules/web-console/frontend/views/403.jade
@@ -0,0 +1,22 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+include includes/header
+
+.error-page
+    .container
+        h1.error-page__title 403
+        h2.error-page__description You are not authorized

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/404.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/404.jade b/modules/web-console/frontend/views/404.jade
new file mode 100644
index 0000000..7d2fc55
--- /dev/null
+++ b/modules/web-console/frontend/views/404.jade
@@ -0,0 +1,22 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+include includes/header
+
+.error-page
+    .container
+        h1.error-page__title 404
+        h2.error-page__description Page not found

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/base.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/base.jade b/modules/web-console/frontend/views/base.jade
new file mode 100644
index 0000000..a910d1b
--- /dev/null
+++ b/modules/web-console/frontend/views/base.jade
@@ -0,0 +1,22 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+include includes/header
+
+.container.body-container
+    .main-content(ui-view='')
+
+include includes/footer

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/configuration/caches.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/configuration/caches.jade b/modules/web-console/frontend/views/configuration/caches.jade
new file mode 100644
index 0000000..a1218ec
--- /dev/null
+++ b/modules/web-console/frontend/views/configuration/caches.jade
@@ -0,0 +1,53 @@
+//-
+    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.jade
+
+.docs-header
+    h1 Configure Ignite Caches
+.docs-body(ng-controller='cachesController')
+    ignite-information
+        ul
+            li Configure #[a(href='https://apacheignite.readme.io/docs/data-grid' target='_blank') memory] settings
+            li Configure persistence
+    div(ignite-loading='loadingCachesScreen' ignite-loading-text='Loading caches...' ignite-loading-position='top')
+        div(ng-show='ui.ready')
+            hr
+            +main-table('caches', 'caches', 'cacheName', 'selectItem(row)', '{{$index + 1}}) {{row.label}}', 'label')
+            .padding-top-dflt(bs-affix)
+                .panel-tip-container(data-placement='bottom' bs-tooltip='' data-title='Create new cache')
+                    button.btn.btn-primary(id='new-item' ng-click='createItem()') Add cache
+                +save-remove-clone-undo-buttons('cache')
+                hr
+            .bs-affix-fix
+            div(bs-collapse='' data-allow-multiple='true' ng-model='ui.activePanels')
+                form.form-horizontal(name='ui.inputForm' novalidate ng-if='contentVisible()')
+                    .panel-group
+                        include ../../app/modules/states/configuration/caches/general.jade
+                        include ../../app/modules/states/configuration/caches/memory.jade
+                        include ../../app/modules/states/configuration/caches/query.jade
+                        include ../../app/modules/states/configuration/caches/store.jade
+
+                        +advanced-options-toggle-default
+
+                        div(ng-show='ui.expanded')
+                            include ../../app/modules/states/configuration/caches/concurrency.jade
+                            include ../../app/modules/states/configuration/caches/node-filter.jade
+                            include ../../app/modules/states/configuration/caches/rebalance.jade
+                            include ../../app/modules/states/configuration/caches/server-near-cache.jade
+                            include ../../app/modules/states/configuration/caches/statistics.jade
+
+                            +advanced-options-toggle-default

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/configuration/clusters.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/configuration/clusters.jade b/modules/web-console/frontend/views/configuration/clusters.jade
new file mode 100644
index 0000000..b10a477
--- /dev/null
+++ b/modules/web-console/frontend/views/configuration/clusters.jade
@@ -0,0 +1,66 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+include ../../app/helpers/jade/mixins.jade
+
+.docs-header
+    h1 Configure Ignite Clusters
+.docs-body(ng-controller='clustersController')
+    ignite-information
+        ul
+            li Configure #[a(href='https://apacheignite.readme.io/docs/clustering' target='_blank') clusters] properties
+            li Associate clusters with caches and in-memory file systems
+    div(ignite-loading='loadingClustersScreen' ignite-loading-text='Loading clusters...' ignite-loading-position='top')
+        div(ng-show='ui.ready')
+            hr
+            +main-table('clusters', 'clusters', 'clusterName', 'selectItem(row)', '{{$index + 1}}) {{row.label}}', 'label')
+            .padding-top-dflt(bs-affix)
+                .panel-tip-container(data-placement='bottom' bs-tooltip='' data-title='Create new cluster')
+                    button.btn.btn-primary(id='new-item' ng-click='createItem()') Add cluster
+                +save-remove-clone-undo-buttons('cluster')
+                hr
+            .bs-affix-fix
+            div(bs-collapse='' data-allow-multiple='true' ng-model='ui.activePanels')
+                form.form-horizontal(name='ui.inputForm' novalidate ng-if='contentVisible()')
+                    .panel-group
+                        include ../../app/modules/states/configuration/clusters/general.jade
+
+                        +advanced-options-toggle-default
+
+                        div(ng-show='ui.expanded')
+                            
+                            include ../../app/modules/states/configuration/clusters/atomic.jade
+                            include ../../app/modules/states/configuration/clusters/binary.jade
+                            include ../../app/modules/states/configuration/clusters/cache-key-cfg.jade
+                            include ../../app/modules/states/configuration/clusters/collision.jade
+                            include ../../app/modules/states/configuration/clusters/communication.jade
+                            include ../../app/modules/states/configuration/clusters/connector.jade
+                            include ../../app/modules/states/configuration/clusters/deployment.jade
+                            include ../../app/modules/states/configuration/clusters/discovery.jade
+                            include ../../app/modules/states/configuration/clusters/events.jade
+                            include ../../app/modules/states/configuration/clusters/failover.jade
+                            include ../../app/modules/states/configuration/clusters/igfs.jade
+                            include ../../app/modules/states/configuration/clusters/logger.jade
+                            include ../../app/modules/states/configuration/clusters/marshaller.jade
+                            include ../../app/modules/states/configuration/clusters/metrics.jade
+                            include ../../app/modules/states/configuration/clusters/ssl.jade
+                            include ../../app/modules/states/configuration/clusters/swap.jade
+                            include ../../app/modules/states/configuration/clusters/thread.jade
+                            include ../../app/modules/states/configuration/clusters/time.jade
+                            include ../../app/modules/states/configuration/clusters/transactions.jade
+                            include ../../app/modules/states/configuration/clusters/attributes.jade
+
+                            +advanced-options-toggle-default

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/configuration/domains-import.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/configuration/domains-import.jade b/modules/web-console/frontend/views/configuration/domains-import.jade
new file mode 100644
index 0000000..d95e98a
--- /dev/null
+++ b/modules/web-console/frontend/views/configuration/domains-import.jade
@@ -0,0 +1,223 @@
+//-
+    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.jade
+
+mixin chk(mdl, change, tip)
+    input(type='checkbox' ng-model=mdl ng-change=change bs-tooltip='' data-title=tip data-trigger='hover' data-placement='top')
+
+mixin td-ellipses-lbl(w, lbl)
+    td.td-ellipsis(width='#{w}' style='min-width: #{w}; max-width: #{w}')
+        label #{lbl}
+
+.modal.modal-domain-import.center(role='dialog')
+    .modal-dialog.domains-import-dialog
+        .modal-content(ignite-loading='importDomainFromDb' ignite-loading-text='{{importDomain.loadingOptions.text}}')
+            #errors-container.modal-header.header
+                button.close(ng-click='$hide()' aria-hidden='true') ×
+                h4.modal-title(ng-if='!importDomain.demo') Import domain models from database
+                h4.modal-title(ng-if='importDomain.demo') Import domain models from demo database
+            .modal-body
+                .import-domain-model-wizard-page(ng-if='importDomain.action == "drivers" && !importDomain.jdbcDriversNotFound')
+                .import-domain-model-wizard-page(ng-if='importDomain.action == "drivers" && importDomain.jdbcDriversNotFound')
+                    | Domain model could not be imported
+                    ul
+                        li Agent failed to find JDBC drivers
+                        li Copy required JDBC drivers into agent 'jdbc-drivers' folder and try again
+                        li Refer to agent README.txt for more information
+                .import-domain-model-wizard-page(ng-if='importDomain.action == "connect" && importDomain.demo')
+                    div(ng-if='demoConnection.db == "H2"')
+                        label Demo description:
+                        ul
+                            li In-memory H2 database server will be started inside agent
+                            li Database will be populated with sample tables
+                            li You could test domain model generation with this demo database
+                            li Click "Next" to continue
+                    div(ng-if='demoConnection.db != "H2"')
+                        label Demo could not be started
+                            ul
+                                li Agent failed to resolve H2 database jar
+                                li Copy h2-x.x.x.jar into agent 'jdbc-drivers' folder and try again
+                                li Refer to agent README.txt for more information
+                .import-domain-model-wizard-page(ng-if='importDomain.action == "connect" && !importDomain.demo')
+                    - var form = 'connectForm'
+
+                    form.form-horizontal(name=form novalidate)
+                        .settings-row
+                            label.col-xs-4.col-sm-2.col-md-2.required Driver JAR:
+                            .col-xs-8.col-sm-10.col-md-10
+                                i.tipField.fa.fa-question-circle(bs-tooltip='' data-title='Select appropriate JAR with JDBC driver<br> To add another driver you need to place it into "/jdbc-drivers" folder of Ignite Web Agent<br> Refer to Ignite Web Agent README.txt for for more information')
+                                .input-tip
+                                    button.select-toggle.form-control(id='jdbcDriverJar' bs-select data-container='.modal-domain-import' ng-model='ui.selectedJdbcDriverJar' ng-class='{placeholder: !(jdbcDriverJars && jdbcDriverJars.length > 0)}' placeholder='Choose JDBC driver' bs-options='item.value as item.label for item in jdbcDriverJars')
+                        .settings-row
+                            label.col-xs-4.col-sm-2.col-md-2.required JDBC driver:
+                            .col-xs-8.col-sm-10.col-md-10
+                                - var name = '"jdbcDriverClass"'
+                                i.tipField.fa.fa-question-circle(bs-tooltip='' data-title='Fully qualified class name of JDBC driver that will be used to connect to database')
+
+                                +form-field-feedback(name, 'javaBuiltInClass', 'JDBC Driver should not be the Java built-in class!')
+                                +form-field-feedback(name, 'javaKeywords', 'JDBC Driver could not contains reserved Java keyword!')
+                                +form-field-feedback(name, 'javaPackageSpecified', 'JDBC Driver does not have package specified!')
+                                +form-field-feedback(name, 'javaIdentifier', 'JDBC Driver is invalid Java identifier!')
+
+                                .input-tip
+                                    +ignite-form-field-input(name, 'selectedPreset.jdbcDriverClass', false, true, 'Enter fully qualified class name')(
+                                        data-java-identifier='true'
+                                        data-java-package-specified='true'
+                                        data-java-keywords='true'
+                                        data-java-built-in-class='true'
+                                    )
+                        .settings-row
+                            label.col-xs-4.col-sm-2.col-md-2.required JDBC URL:
+                            .col-xs-8.col-sm-10.col-md-10
+                                i.tipField.fa.fa-question-circle(bs-tooltip='' data-title='JDBC URL for connecting to database<br>Refer to your database documentation for details')
+                                .input-tip
+                                    +ignite-form-field-input('jdbcUrl', 'selectedPreset.jdbcUrl', false, true, 'JDBC URL')
+                        .settings-row
+                            label.col-xs-4.col-sm-2.col-md-2 User:
+                            .col-xs-8.col-sm-10.col-md-10
+                                i.tipField.fa.fa-question-circle(bs-tooltip='' data-title='User name for connecting to database')
+                                .input-tip
+                                    input.form-control(id='user' type='text' ng-model='selectedPreset.user')
+                        .settings-row
+                            label.col-xs-4.col-sm-2.col-md-2 Password:
+                            .col-xs-8.col-sm-10.col-md-10
+                                i.tipField.fa.fa-question-circle(bs-tooltip='' data-title='Password for connecting to database<br>Note, password would not be saved in preferences for security reasons')
+                                .input-tip
+                                    input.form-control(id='password' type='password' ng-model='selectedPreset.password' ignite-on-enter='importDomainNext()')
+                        .settings-row
+                            .checkbox
+                                label
+                                    input(id='tablesOnly' type='checkbox' ng-model='selectedPreset.tablesOnly')
+                                    | Tables only
+                                i.tipLabel.fa.fa-question-circle(bs-tooltip='' data-title='If selected, then only tables metadata will be parsed<br>Otherwise table and view metadata will be parsed')
+                .import-domain-model-wizard-page(ng-show='importDomain.action == "schemas"')
+                    table.table.metadata(st-table='importDomain.displayedSchemas' st-safe-src='importDomain.schemas')
+                        thead
+                            tr
+                                th.header(colspan='2')
+                                    .col-sm-4.pull-right(style='margin-bottom: 5px')
+                                        input.form-control(type='text' st-search='name' placeholder='Filter schemas...' ng-model='importDomain.displayedSchemasFilter' ng-change='selectSchema()')
+                            tr
+                                th(width='30px')
+                                    +chk('importDomain.allSchemasSelected',  'selectAllSchemas()', 'Select all schemas')
+                                th
+                                    label Schema
+                            tbody
+                                tr
+                                    td(colspan='2')
+                                        .scrollable-y(style='height: 213px')
+                                            table.table-modal-striped(id='importSchemasData')
+                                                tbody
+                                                    tr(ng-repeat='schema in importDomain.displayedSchemas')
+                                                        td(width='30px')
+                                                            input(type='checkbox' ng-model='schema.use' ng-change='selectSchema()')
+                                                        td
+                                                            label {{schema.name}}
+                .import-domain-model-wizard-page(ng-show='importDomain.action == "tables"')
+                    table.table.metadata(st-table='importDomain.displayedTables' st-safe-src='importDomain.tables')
+                        thead
+                            tr
+                                th.header(colspan='6')
+                                    .col-sm-4.pull-right(style='margin-bottom: 8px')
+                                        input.form-control(type='text' st-search='label' placeholder='Filter tables...' ng-model='importDomain.displayedTablesFilter' ng-change='selectTable()')
+                            tr
+                                th(width='30px')
+                                    +chk('importDomain.allTablesSelected',  'selectAllTables()', 'Select all tables')
+                                th(width='130px')
+                                    label Schema
+                                th(width='160px')
+                                    label Table name
+                                th(colspan=2 width='288px')
+                                    label Cache
+                                th
+                        tbody
+                            tr
+                                td(colspan='6')
+                                    .scrollable-y(style='height: 143px')
+                                        table.table-modal-striped(id='importTableData')
+                                            tbody
+                                                tr(ng-repeat='table in importDomain.displayedTables track by $index')
+                                                    td(width='30px' style='min-width: 30px; max-width: 30px')
+                                                        input(type='checkbox' ng-model='table.use' ng-change='selectTable()')
+                                                    +td-ellipses-lbl('130px', '{{table.schema}}')
+                                                    +td-ellipses-lbl('160px', '{{table.tbl}}')
+                                                    td(colspan='2' width='288px' style='min-width: 160px; max-width: 160px')
+                                                        div.td-ellipsis
+                                                            a(ng-if='!table.edit' ng-click='startEditDbTableCache(table)') {{tableActionView(table)}}
+                                                            div(style='display: flex' ng-if='table.edit')
+                                                                button.select-toggle.form-control(style='width: 35%; margin-right: 5px' bs-select ng-model='table.action' data-container='.modal-domain-import' bs-options='item.value as item.shortLabel for item in importActions')
+                                                                button.select-toggle.form-control(style='width: 65%; margin-right: 0' bs-select ng-model='table.cacheOrTemplate' data-container='.modal-domain-import' bs-options='item.value as item.label for item in table.cachesOrTemplates')
+                                                    td
+                    .settings-row
+                        label Defaults to be applied for filtered tables
+                        i.tipLabel.fa.fa-question-circle(bs-tooltip='' data-title='Select and apply options for caches generation')
+                    .settings-row
+                        .col-sm-11
+                            .col-sm-6(style='padding-right: 5px')
+                                button.select-toggle.form-control(bs-select ng-model='importCommon.action' data-container='.modal-domain-import' bs-options='item.value as item.label for item in importActions')
+                            .col-sm-6(style='padding-left: 5px; padding-right: 5px')
+                                button.select-toggle.form-control(bs-select ng-model='importCommon.cacheOrTemplate' data-container='.modal-domain-import' bs-options='item.value as item.label for item in importCommon.cachesOrTemplates')
+                        .col-sm-1(style='padding-left: 5px')
+                            button.btn.btn-primary(ng-click='applyDefaults()') Apply
+                .import-domain-model-wizard-page(ng-show='importDomain.action == "options"')
+                    - var form = 'optionsForm'
+                    form.form-horizontal(name='optionsForm' novalidate)
+                        .settings-row
+                            .col-xs-3.col-sm-2.col-md-2.required
+                                label.required Package:
+                            .col-xs-9.col-sm-10.col-md-10
+                                - var name = '"domainPackageName"'
+                                i.tipField.fa.fa-question-circle(bs-tooltip='' data-title='Package that will be used for POJOs generation')
+
+                                +form-field-feedback(name, 'javaPackageName', 'Package name is invalid')
+                                +form-field-feedback(name, 'javaKeywords', 'Package name could not contains reserved java keyword')
+
+                                .input-tip
+                                    +ignite-form-field-input(name, 'ui.packageName', false, true, 'Enter package name')(
+                                        data-java-keywords='true'
+                                        data-java-package-name='package-only'
+                                        ng-model-options='{allowInvalid: true}'
+                                    )
+                        .settings-row
+                            .checkbox
+                                label
+                                    input(id='domainBuiltinKeys' type='checkbox' ng-model='ui.builtinKeys')
+                                    | Use Java built-in types for keys
+                                    i.tipLabel.fa.fa-question-circle(bs-tooltip='' data-title='Use Java built-in types like "Integer", "Long", "String" instead of POJO generation in case when table primary key contains only one field')
+                        .settings-row
+                            .checkbox
+                                label
+                                    input(id='domainUsePrimitives' type='checkbox' ng-model='ui.usePrimitives')
+                                    | Use primitive types for NOT NULL table columns
+                                    i.tipLabel.fa.fa-question-circle(bs-tooltip='' data-title='Use primitive types like "int", "long", "double" for POJOs fields generation in case of NOT NULL columns')
+                        .settings-row
+                            .checkbox
+                                label
+                                    input(id='domainGenerateAliases' type='checkbox' ng-model='ui.generateAliases')
+                                    | Generate aliases for query fields
+                                    i.tipLabel.fa.fa-question-circle(bs-tooltip='' data-title='Generate aliases for query fields with database field names when database field name differ from Java field name')
+                        .settings-row
+                            .col-xs-3.col-sm-2.col-md-2.required
+                                label Clusters:
+                            .col-xs-9.col-sm-10.col-md-10
+                                i.tipField.fa.fa-question-circle(bs-tooltip='' data-title='Choose clusters that will be associated with generated caches')
+                                .input-tip
+                                    button.select-toggle.form-control(id='generatedCachesClusters' bs-select ng-model='ui.generatedCachesClusters' ng-class='{placeholder: !(ui.generatedCachesClusters && ui.generatedCachesClusters.length > 0)}' data-container='.modal-domain-import' data-multiple='1' placeholder='Choose clusters for generated caches' bs-options='item.value as item.label for item in clusters')
+            .modal-footer
+                label(ng-hide='importDomain.action == "drivers" || (importDomain.action == "connect" && importDomain.demo)').labelField {{importDomain.info}}
+                a.btn.btn-primary(ng-hide='importDomain.action == "drivers" || importDomain.action == "connect"' ng-click='importDomainPrev()' bs-tooltip='' data-title='{{prevTooltipText()}}' data-placement='bottom') Prev
+                a.btn.btn-primary(ng-click='importDomainNext()' ng-disabled='!importDomainNextAvailable()' bs-tooltip='' data-title='{{nextTooltipText()}}' data-placement='bottom') {{importDomain.button}}