IGNITE-7650 Extracted signin/signup form to separate page, improved landing 
page.


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

Branch: refs/heads/ignite-7725
Commit: 19256745bdf239db73a5cbd13f9eb92e064ff500
Parents: 071e27e
Author: alexdel <verba...@yandex.ru>
Authored: Mon Feb 19 11:25:24 2018 +0700
Committer: Andrey Novikov <anovi...@gridgain.com>
Committed: Mon Feb 19 11:25:24 2018 +0700

----------------------------------------------------------------------
 modules/web-console/e2e/testcafe/Dockerfile     |   2 +
 modules/web-console/e2e/testcafe/envtools.js    |   1 +
 .../web-console/e2e/testcafe/fixtures/auth.js   |  73 ++++---
 .../e2e/testcafe/fixtures/user-profile.js       | 113 -----------
 .../fixtures/user-profile/credentials.js        |  63 ++++++
 .../testcafe/fixtures/user-profile/profile.js   |  84 ++++++++
 modules/web-console/e2e/testcafe/roles.js       |  23 +--
 modules/web-console/e2e/testcafe/testcafe.js    |   4 +-
 modules/web-console/e2e/testenv/Dockerfile      |   2 +
 modules/web-console/frontend/app/app.js         |  14 +-
 .../app/components/page-configure/index.js      |   3 +
 .../app/components/page-landing/index.js        |  65 ++++++
 .../app/components/page-landing/style.scss      | 104 ++++++++++
 .../app/components/page-landing/template.pug    |  66 ++++++
 .../page-password-changed/controller.js         |  18 ++
 .../components/page-password-changed/index.js   |  33 +++
 .../components/page-password-changed/style.scss |  34 ++++
 .../page-password-changed/template.pug          |  14 ++
 .../page-password-reset/controller.js           |  53 +++++
 .../app/components/page-password-reset/index.js |  57 ++++++
 .../components/page-password-reset/style.scss   |  31 +++
 .../components/page-password-reset/template.pug |  80 ++++++++
 .../app/components/page-profile/controller.js   |   8 +-
 .../app/components/page-profile/index.js        |  13 +-
 .../app/components/page-profile/style.scss      |  31 +++
 .../app/components/page-profile/template.pug    | 203 +++++++++++++------
 .../app/components/page-signin/controller.js    |  30 +++
 .../app/components/page-signin/index.js         |  56 +++++
 .../app/components/page-signin/style.scss       |  38 ++++
 .../app/components/page-signin/template.pug     | 161 +++++++++++++++
 .../components/web-console-header/style.scss    |   1 +
 .../components/web-console-header/template.pug  |   2 +-
 .../frontend/app/controllers/auth.controller.js |  29 ---
 .../frontend/app/data/countries.json            |  72 ++++---
 .../frontend/app/helpers/jade/mixins.pug        |   1 +
 .../app/modules/states/configuration.state.js   |   1 +
 .../app/modules/states/password.state.js        |  50 -----
 .../frontend/app/modules/states/signin.state.js |  53 -----
 .../frontend/app/modules/user/Auth.service.js   |   6 +-
 .../app/primitives/form-field/checkbox.pug      |  30 +++
 .../app/primitives/form-field/dropdown.pug      |  51 +++++
 .../app/primitives/form-field/email.pug         |  37 ++++
 .../app/primitives/form-field/error.pug         |  29 +++
 .../app/primitives/form-field/index.pug         |  27 +++
 .../app/primitives/form-field/index.scss        | 149 +++++++++++++-
 .../app/primitives/form-field/input.pug         |  28 +++
 .../app/primitives/form-field/label.pug         |  30 +++
 .../app/primitives/form-field/number.pug        |  46 +++++
 .../app/primitives/form-field/password.pug      |  37 ++++
 .../app/primitives/form-field/phone.pug         |  35 ++++
 .../frontend/app/primitives/form-field/text.pug |  35 ++++
 .../app/primitives/form-field/tooltip.pug       |  18 ++
 .../frontend/app/primitives/panel/index.scss    |  96 +++++++--
 .../frontend/app/primitives/tooltip/index.scss  |  17 ++
 .../frontend/app/primitives/ui-grid/index.scss  |  32 +--
 .../frontend/app/services/DefaultState.js       |  36 ++++
 .../web-console/frontend/app/services/index.js  |   2 +
 modules/web-console/frontend/app/vendor.js      |   5 +-
 modules/web-console/frontend/package.json       |   3 +-
 .../frontend/public/images/icons/collapse.svg   |   3 +
 .../public/images/icons/exclamation.svg         |   3 +
 .../frontend/public/images/icons/expand.svg     |   3 +
 .../frontend/public/images/icons/index.js       |   4 +
 .../frontend/public/images/main-screenshot.png  | Bin 0 -> 86830 bytes
 .../public/images/page-landing-carousel-1.png   | Bin 0 -> 84434 bytes
 .../public/images/page-landing-carousel-2.png   | Bin 0 -> 106670 bytes
 .../public/images/page-landing-carousel-3.png   | Bin 0 -> 70876 bytes
 .../public/stylesheets/_bootstrap-custom.scss   |   1 -
 .../web-console/frontend/views/reset.tpl.pug    |  44 ----
 .../web-console/frontend/views/signin.tpl.pug   | 165 ---------------
 70 files changed, 2006 insertions(+), 652 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/e2e/testcafe/Dockerfile
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/Dockerfile 
b/modules/web-console/e2e/testcafe/Dockerfile
index e58cbef..d890d10 100644
--- a/modules/web-console/e2e/testcafe/Dockerfile
+++ b/modules/web-console/e2e/testcafe/Dockerfile
@@ -25,6 +25,8 @@ WORKDIR /opt/testcafe/tests
 
 COPY . /opt/testcafe/tests
 
+ENV NPM_CONFIG_LOGLEVEL warn
+
 RUN npm install --production && \
  npm cache verify --force && \
  rm -rf /tmp/*

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/e2e/testcafe/envtools.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/envtools.js 
b/modules/web-console/e2e/testcafe/envtools.js
index 846a33a..c251b5f 100644
--- a/modules/web-console/e2e/testcafe/envtools.js
+++ b/modules/web-console/e2e/testcafe/envtools.js
@@ -46,6 +46,7 @@ const insertTestUser = ({userId = '000000000000000000000001', 
token = 'ppw4tPI3J
                     lastName: 'Doe',
                     company: 'TestCompany',
                     country: 'Canada',
+                    industry: 'Banking',
                     admin: true,
                     token,
                     attempts: 0,

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/e2e/testcafe/fixtures/auth.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/fixtures/auth.js 
b/modules/web-console/e2e/testcafe/fixtures/auth.js
index 8f72b83..c845560 100644
--- a/modules/web-console/e2e/testcafe/fixtures/auth.js
+++ b/modules/web-console/e2e/testcafe/fixtures/auth.js
@@ -21,7 +21,7 @@ const { AngularJSSelector } = 
require('testcafe-angular-selectors');
 const { removeData, insertTestUser } = require('../envtools');
 
 fixture('Checking Ignite auth screen')
-    .page `${process.env.APP_URL || 'http://localhost:9001/'}`
+    .page `${process.env.APP_URL || 'http://localhost:9001/'}signin`
     .beforeEach(async(t) => {
         await removeData();
 
@@ -34,61 +34,59 @@ fixture('Checking Ignite auth screen')
 
 test('Testing Ignite signup validation and signup success', async(t) => {
     async function checkBtnDisabled() {
-        const btnDisabled = await 
t.expect(Selector('#signup').getAttribute('disabled')).ok();
+        const btnDisabled = await 
t.expect(Selector('#signup_submit').getAttribute('disabled')).ok();
 
         const btnNotWorks =  await t
-            .click('#signup')
+            .click('#signup_submit')
             .expect(Selector('title').innerText).eql('Apache Ignite - 
Management Tool and Configuration Wizard – Apache Ignite Web Console');
 
         return btnDisabled && btnNotWorks;
     }
 
-    await t.click(Selector('a').withText('Sign Up'));
-
     await t
-        .click(Selector('#signup_email'))
-        .typeText(Selector('#signup_email'), 't...@test.com');
+        .typeText(AngularJSSelector.byModel('ui_signup.email'), 
't...@test.com');
     await checkBtnDisabled();
 
     await t
-        .typeText(AngularJSSelector.byModel('ui.password'), 'qwerty')
+        .typeText(AngularJSSelector.byModel('ui_signup.password'), 'qwerty')
         .typeText(AngularJSSelector.byModel('ui_exclude.confirm'), 'qwerty');
     await checkBtnDisabled();
 
     await t
-        .typeText(AngularJSSelector.byModel('ui.firstName'), 'John')
-        .typeText(AngularJSSelector.byModel('ui.lastName'), 'Doe');
+        .typeText(AngularJSSelector.byModel('ui_signup.firstName'), 'John')
+        .typeText(AngularJSSelector.byModel('ui_signup.lastName'), 'Doe');
     await checkBtnDisabled();
 
     await t
-        .typeText(AngularJSSelector.byModel('ui.company'), 'DevNull LTD');
+        .typeText(AngularJSSelector.byModel('ui_signup.company'), 'DevNull 
LTD');
     await checkBtnDisabled();
 
     await t
-        .click('#country')
+        .click('#countryInput')
         .click(Selector('span').withText('Brazil'));
 
-    // checking passwords confirm dismatch
+    // Checking passwords confirm dismatch.
     await t
         .click(AngularJSSelector.byModel('ui_exclude.confirm'))
         .pressKey('ctrl+a delete')
         .typeText(AngularJSSelector.byModel('ui_exclude.confirm'), 'ytrewq');
     await checkBtnDisabled();
+
     await t
         .click(AngularJSSelector.byModel('ui_exclude.confirm'))
         .pressKey('ctrl+a delete')
         .typeText(AngularJSSelector.byModel('ui_exclude.confirm'), 'qwerty');
 
-    await t.click('#signup')
+    await t.click('#signup_submit')
         .expect(Selector('title').innerText).eql('Basic Configuration – 
Apache Ignite Web Console');
 
 });
 
 test('Testing Ignite validation and successful sign in of existing user', 
async(t) => {
     async function checkSignInBtnDisabled() {
-        const btnDisabled = await t.expect(await 
Selector('#login').getAttribute('disabled')).ok();
+        const btnDisabled = await t.expect(await 
Selector('#signin_submit').getAttribute('disabled')).ok();
         const btnNotWorks =  await t
-            .click('#login')
+            .click('#signin_submit')
             .expect(Selector('title').innerText).eql('Apache Ignite - 
Management Tool and Configuration Wizard – Apache Ignite Web Console');
 
         return btnDisabled && btnNotWorks;
@@ -96,14 +94,14 @@ test('Testing Ignite validation and successful sign in of 
existing user', async(
 
     await insertTestUser();
 
-    // checking signin validation
+    // Checking signin validation.
     await t
         .typeText(AngularJSSelector.byModel('ui.email'), 't...@test.com');
     await checkSignInBtnDisabled();
 
     await t
         .typeText(AngularJSSelector.byModel('ui.password'), 'b')
-        .click('#login');
+        .click('#signin_submit');
     await t.expect(Selector('#popover-validation-message').withText('Invalid 
email or password').exists).ok();
 
     await t
@@ -112,7 +110,7 @@ test('Testing Ignite validation and successful sign in of 
existing user', async(
         .typeText(AngularJSSelector.byModel('ui.email'), 'testtest.com');
     await checkSignInBtnDisabled();
 
-    // checking regular sigin in
+    // Checking regular sigin in
     await t
         .click(AngularJSSelector.byModel('ui.email'))
         .pressKey('ctrl+a delete')
@@ -120,7 +118,7 @@ test('Testing Ignite validation and successful sign in of 
existing user', async(
         .click(AngularJSSelector.byModel('ui.password'))
         .pressKey('ctrl+a delete')
         .typeText(AngularJSSelector.byModel('ui.password'), 'a')
-        .click('#login')
+        .click('#signin_submit')
         .expect(Selector('title').innerText).eql('Basic Configuration – 
Apache Ignite Web Console');
 
 });
@@ -128,46 +126,43 @@ test('Testing Ignite validation and successful sign in of 
existing user', async(
 test('Forbid Ignite signing up of already existing user', async(t) => {
     await insertTestUser();
 
-    await t.click(Selector('a').withText('Sign Up'));
-
     await t
-        .click(Selector('#signup_email'))
-        .typeText(Selector('#signup_email'), 'a@a')
-        .typeText(AngularJSSelector.byModel('ui.password'), 'a')
+        .typeText(AngularJSSelector.byModel('ui_signup.email'), 'a@a')
+        .typeText(AngularJSSelector.byModel('ui_signup.password'), 'a')
         .typeText(AngularJSSelector.byModel('ui_exclude.confirm'), 'a')
-        .typeText(AngularJSSelector.byModel('ui.firstName'), 'John')
-        .typeText(AngularJSSelector.byModel('ui.lastName'), 'Doe')
-        .typeText(AngularJSSelector.byModel('ui.company'), 'DevNull LTD')
-        .click('#country')
+        .typeText(AngularJSSelector.byModel('ui_signup.firstName'), 'John')
+        .typeText(AngularJSSelector.byModel('ui_signup.lastName'), 'Doe')
+        .typeText(AngularJSSelector.byModel('ui_signup.company'), 'DevNull 
LTD')
+        .click('#countryInput')
         .click(Selector('span').withText('Brazil'))
-        .click('#signup');
+        .click('#signup_submit');
 
     await t.expect(Selector('#popover-validation-message').withText('A user 
with the given username is already registered').exists).ok();
 
 });
 
 test('Test Ignite password reset', async(t) => {
-    await t.click(Selector('#password-forgot-signin'));
+    await t.click(Selector('#forgot_show'));
 
-    // testing incorrect email
+    // Testing incorrect email.
     await t
-        .typeText('#forgot_email', 'testtest')
+        .typeText('#forgotEmailInput', 'testtest')
         .expect(await Selector('button').withText('Send it to 
me').getAttribute('disabled')).ok();
 
-    // testing handling unknown email password reset
+    // Testing handling unknown email password reset.
     await t
-        .click(Selector('#forgot_email'))
+        .click(Selector('#forgotEmailInput'))
         .pressKey('ctrl+a delete')
-        .typeText(Selector('#forgot_email'), 'nonexist...@mail.com')
+        .typeText(Selector('#forgotEmailInput'), 'nonexist...@mail.com')
         .click(Selector('button').withText('Send it to me'));
 
     await t.expect(Selector('#popover-validation-message').withText('Account 
with that email address does not exists!').exists).ok();
 
-    // testing regular password reset
+    // Testing regular password reset.
     await t
-        .click(Selector('#forgot_email'))
+        .click(Selector('#forgotEmailInput'))
         .pressKey('ctrl+a delete')
-        .typeText(Selector('#forgot_email'), 'a@a')
+        .typeText(Selector('#forgotEmailInput'), 'a@a')
         .click(Selector('button').withText('Send it to me'));
 
     await t.expect(Selector('#popover-validation-message').withText('Account 
with that email address does not exists!').exists).notOk();

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/e2e/testcafe/fixtures/user-profile.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/fixtures/user-profile.js 
b/modules/web-console/e2e/testcafe/fixtures/user-profile.js
deleted file mode 100644
index 133b37e..0000000
--- a/modules/web-console/e2e/testcafe/fixtures/user-profile.js
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-const { Selector } = require('testcafe');
-const { removeData, insertTestUser } = require('../envtools');
-const { signIn, signUp } = require('../roles');
-
-fixture('Checking user profile')
-    .page `${process.env.APP_URL || 'http://localhost:9001/'}settings/profile`
-    .beforeEach(async(t) => {
-        await t.setNativeDialogHandler(() => true);
-        await removeData();
-        await insertTestUser();
-        await signIn(t);
-
-        await t.navigateTo(`${process.env.APP_URL || 
'http://localhost:9001/'}settings/profile`);
-    })
-    .after(async() => {
-        await removeData();
-    });
-
-test('Testing user data change', async(t) => {
-
-    const newUserData = {
-        firstName: {
-            selector: '#profile-firstname',
-            value: 'Richard'
-        },
-        lastName: {
-            selector: '#profile-lastname',
-            value: 'Roe'
-        },
-        email: {
-            selector: '#profile-email',
-            value: 'r....@mail.com'
-        },
-        company: {
-            selector: '#profile-company',
-            value: 'New Company'
-        },
-        country: {
-            selector: '#profile-country',
-            value: 'Israel'
-        }
-    };
-
-    ['firstName', 'lastName', 'email', 'company'].forEach(async(item) => {
-        await t
-           .click(newUserData[item].selector)
-           .pressKey('ctrl+a delete')
-           .typeText(newUserData[item].selector, newUserData[item].value);
-    });
-
-    await t
-        .click(newUserData.country.selector)
-        .click(Selector('span').withText(newUserData.country.value))
-        .click(Selector('a').withText('Save'));
-
-    await t.navigateTo(`${process.env.APP_URL || 
'http://localhost:9001/'}settings/profile`);
-
-    ['firstName', 'lastName', 'email', 'company'].forEach(async(item) => {
-        await t
-            .expect(await 
Selector(newUserData[item].selector).getAttribute('value'))
-            .eql(newUserData[item].value);
-    });
-
-    await t
-        .expect(Selector(newUserData.country.selector).innerText)
-        .eql(newUserData.country.value);
-});
-
-test('Testing secure token change', async(t) => {
-    await t.click(Selector('a').withAttribute('ng-click', 'toggleToken()'));
-
-    const currentToken = await Selector('#current-security-token').innerText;
-
-    await t
-        .click(Selector('i').withAttribute('ng-click', 'generateToken()'))
-        .expect(Selector('p').withText('Are you sure you want to change 
security token?').exists)
-        .ok()
-        .click('#confirm-btn-ok', {timeout: 5000});
-
-    await t
-        .expect(await Selector('#current-security-token').innerText)
-        .notEql(currentToken);
-});
-
-test('Testing password change', async(t) => {
-    await t.click(Selector('a').withAttribute('ng-click', 'togglePassword()'));
-
-    await t
-        .typeText('#profile_password', 'newPass')
-        .typeText('#profile_confirm', 'newPass')
-        .click(Selector('a').withText('Save'));
-
-    await t
-        .expect(Selector('span').withText('Profile saved.').exists)
-        .ok();
-});

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/e2e/testcafe/fixtures/user-profile/credentials.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/e2e/testcafe/fixtures/user-profile/credentials.js 
b/modules/web-console/e2e/testcafe/fixtures/user-profile/credentials.js
new file mode 100644
index 0000000..491a100
--- /dev/null
+++ b/modules/web-console/e2e/testcafe/fixtures/user-profile/credentials.js
@@ -0,0 +1,63 @@
+/*
+ * 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 { Selector } = require('testcafe');
+const { removeData, insertTestUser } = require('../../envtools');
+const { signIn } = require('../../roles');
+
+fixture('Checking user credentials change')
+    .page `${process.env.APP_URL || 'http://localhost:9001/'}settings/profile`
+    .beforeEach(async(t) => {
+        await t.setNativeDialogHandler(() => true);
+        await removeData();
+        await insertTestUser();
+        await signIn(t);
+
+        await t.navigateTo(`${process.env.APP_URL || 
'http://localhost:9001/'}settings/profile`);
+    })
+    .after(async() => {
+        await removeData();
+    });
+
+test('Testing secure token change', async(t) => {
+    await t.click(Selector('header').withAttribute('ng-click', 
'$ctrl.toggleToken()'));
+
+    const currentToken = await Selector('#current-security-token').innerText;
+
+    await t
+        .click(Selector('i').withAttribute('ng-click', 
'$ctrl.generateToken()'))
+        .expect(Selector('p').withText('Are you sure you want to change 
security token?').exists)
+        .ok()
+        .click('#confirm-btn-ok', {timeout: 5000});
+
+    await t
+        .expect(await Selector('#current-security-token').innerText)
+        .notEql(currentToken);
+});
+
+test('Testing password change', async(t) => {
+    await t.click(Selector('header').withAttribute('ng-click', 
'$ctrl.togglePassword()'));
+
+    await t
+        .typeText('#passwordInput', 'newPass')
+        .typeText('#passwordConfirmInput', 'newPass')
+        .click(Selector('button').withText('Save Changes'));
+
+    await t
+        .expect(Selector('span').withText('Profile saved.').exists)
+        .ok();
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/e2e/testcafe/fixtures/user-profile/profile.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/fixtures/user-profile/profile.js 
b/modules/web-console/e2e/testcafe/fixtures/user-profile/profile.js
new file mode 100644
index 0000000..738d596
--- /dev/null
+++ b/modules/web-console/e2e/testcafe/fixtures/user-profile/profile.js
@@ -0,0 +1,84 @@
+/*
+ * 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 { Selector } = require('testcafe');
+const { removeData, insertTestUser } = require('../../envtools');
+const { signIn } = require('../../roles');
+
+fixture('Checking user profile')
+    .page `${process.env.APP_URL || 'http://localhost:9001/'}settings/profile`
+    .beforeEach(async(t) => {
+        await t.setNativeDialogHandler(() => true);
+        await removeData();
+        await insertTestUser();
+        await signIn(t);
+
+        await t.navigateTo(`${process.env.APP_URL || 
'http://localhost:9001/'}settings/profile`);
+    })
+    .after(async() => {
+        await removeData();
+    });
+
+test('Testing user data change', async(t) => {
+
+    const newUserData = {
+        firstName: {
+            selector: '#firstNameInput',
+            value: 'Richard'
+        },
+        lastName: {
+            selector: '#lastNameInput',
+            value: 'Roe'
+        },
+        email: {
+            selector: '#emailInput',
+            value: 'r....@mail.com'
+        },
+        company: {
+            selector: '#companyInput',
+            value: 'New Company'
+        },
+        country: {
+            selector: '#countryInput',
+            value: 'Israel'
+        }
+    };
+
+    ['firstName', 'lastName', 'email', 'company'].forEach(async(item) => {
+        await t
+            .click(newUserData[item].selector)
+            .pressKey('ctrl+a delete')
+            .typeText(newUserData[item].selector, newUserData[item].value);
+    });
+
+    await t
+        .click(newUserData.country.selector)
+        .click(Selector('span').withText(newUserData.country.value))
+        .click(Selector('button').withText('Save Changes'));
+
+    await t.navigateTo(`${process.env.APP_URL || 
'http://localhost:9001/'}settings/profile`);
+
+    ['firstName', 'lastName', 'email', 'company'].forEach(async(item) => {
+        await t
+            .expect(await 
Selector(newUserData[item].selector).getAttribute('value'))
+            .eql(newUserData[item].value);
+    });
+
+    await t
+        .expect(Selector(newUserData.country.selector).innerText)
+        .eql(newUserData.country.value);
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/e2e/testcafe/roles.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/roles.js 
b/modules/web-console/e2e/testcafe/roles.js
index bfa9f13..568a520 100644
--- a/modules/web-console/e2e/testcafe/roles.js
+++ b/modules/web-console/e2e/testcafe/roles.js
@@ -20,21 +20,18 @@ const { Selector } = require('testcafe');
 const { AngularJSSelector } = require('testcafe-angular-selectors');
 
 const igniteSignUp = async(t) => {
-    await t.navigateTo(`${process.env.APP_URL || 'http://localhost:9001/'}`);
-
-    await t.click(Selector('a').withText('Sign Up'));
+    await t.navigateTo(`${process.env.APP_URL || 
'http://localhost:9001/'}signin`);
 
     await t
-        .click(Selector('#signup_email'))
-        .typeText(Selector('#signup_email'), 'a@a')
-        .typeText(AngularJSSelector.byModel('ui.password'), 'a')
+        .typeText(AngularJSSelector.byModel('ui_signup.email'), 'a@a')
+        .typeText(AngularJSSelector.byModel('ui_signup.password'), 'a')
         .typeText(AngularJSSelector.byModel('ui_exclude.confirm'), 'a')
-        .typeText(AngularJSSelector.byModel('ui.firstName'), 'John')
-        .typeText(AngularJSSelector.byModel('ui.lastName'), 'Doe')
-        .typeText(AngularJSSelector.byModel('ui.company'), 'DevNull LTD')
-        .click('#country')
+        .typeText(AngularJSSelector.byModel('ui_signup.firstName'), 'John')
+        .typeText(AngularJSSelector.byModel('ui_signup.lastName'), 'Doe')
+        .typeText(AngularJSSelector.byModel('ui_signup.company'), 'DevNull 
LTD')
+        .click('#countryInput')
         .click(Selector('span').withText('Brazil'))
-        .click('#signup');
+        .click('#signup_submit');
 
     // close modal window
     await t.click('.modal-header button.close');
@@ -42,12 +39,12 @@ const igniteSignUp = async(t) => {
 
 
 const igniteSignIn = async(t) => {
-    await t.navigateTo(`${process.env.APP_URL || 'http://localhost:9001/'}`);
+    await t.navigateTo(`${process.env.APP_URL || 
'http://localhost:9001/'}signin`);
 
     await t
         .typeText(AngularJSSelector.byModel('ui.email'), 'a@a')
         .typeText(AngularJSSelector.byModel('ui.password'), 'a')
-        .click('#login');
+        .click('#signin_submit');
 
     // close modal window
     await t.click('.modal-header button.close');

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/e2e/testcafe/testcafe.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/testcafe.js 
b/modules/web-console/e2e/testcafe/testcafe.js
index 597d29a..66610e8 100644
--- a/modules/web-console/e2e/testcafe/testcafe.js
+++ b/modules/web-console/e2e/testcafe/testcafe.js
@@ -33,11 +33,11 @@ const BROWSERS = ['chromium:headless --no-sandbox']; // For 
example: ['chrome',
 let testcafe = null;
 
 const resolveFixturesPaths = () => {
-    let fixturesPaths = glob.sync('./fixtures/*.js');
+    let fixturesPaths = glob.sync(' ./fixtures/**/*.js');
 
     if (process.env.IGNITE_MODULES) {
         const igniteModulesTestcafe = path.join(process.env.IGNITE_MODULES, 
'e2e/testcafe');
-        const additionalFixturesPaths = 
glob.sync(path.join(igniteModulesTestcafe, 'fixtures', '*.js'));
+        const additionalFixturesPaths = 
glob.sync(path.join(igniteModulesTestcafe, 'fixtures', '**/*.js'));
         const relativePaths = new 
Set(additionalFixturesPaths.map((fixturePath) => 
path.relative(igniteModulesTestcafe, fixturePath)));
 
         fixturesPaths = fixturesPaths.filter((fixturePath) => 
!relativePaths.has(path.relative(process.cwd(), 
fixturePath))).concat(additionalFixturesPaths);

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/e2e/testenv/Dockerfile
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testenv/Dockerfile 
b/modules/web-console/e2e/testenv/Dockerfile
index 5a8f24b..0db2f29 100644
--- a/modules/web-console/e2e/testenv/Dockerfile
+++ b/modules/web-console/e2e/testenv/Dockerfile
@@ -49,6 +49,8 @@ RUN curl -SLO 
"https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-
   tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C /usr/local 
--strip-components=1 && \
   rm "node-v$NODE_VERSION-linux-x64.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt
 
+ENV NPM_CONFIG_LOGLEVEL warn
+
 # Install global node packages.
 RUN npm install -g pm2
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/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 c19018c..6524450 100644
--- a/modules/web-console/frontend/app/app.js
+++ b/modules/web-console/frontend/app/app.js
@@ -25,9 +25,7 @@ import './modules/agent/agent.module';
 import './modules/nodes/nodes.module';
 import './modules/demo/Demo.module';
 
-import './modules/states/signin.state';
 import './modules/states/logout.state';
-import './modules/states/password.state';
 import './modules/states/configuration.state';
 import './modules/states/admin.state';
 import './modules/states/errors.state';
@@ -133,8 +131,12 @@ import uiGridFilters from './components/ui-grid-filters';
 import listEditable from './components/list-editable';
 import clusterSelector from './components/cluster-selector';
 import connectedClusters from './components/connected-clusters';
+import pageSignIn from './components/page-signin';
+import pageLanding from './components/page-landing';
 
 import pageProfile from './components/page-profile';
+import pagePasswordChanged from './components/page-password-changed';
+import pagePasswordReset from './components/page-password-reset';
 
 import igniteServices from './services';
 
@@ -148,6 +150,7 @@ angular.module('ignite-console', [
     // Optional AngularJS modules.
     'ngAnimate',
     'ngSanitize',
+    'ngMessages',
     // Third party libs.
     'btford.socket-io',
     'dndLists',
@@ -166,6 +169,7 @@ angular.module('ignite-console', [
     'ui.grid.selection',
     'ui.router',
     'ui.router.state.events',
+    'ui.carousel',
     // Base modules.
     'ignite-console.core',
     'ignite-console.ace',
@@ -178,9 +182,7 @@ angular.module('ignite-console', [
     'ignite-console.nodes',
     'ignite-console.demo',
     // States.
-    'ignite-console.states.login',
     'ignite-console.states.logout',
-    'ignite-console.states.password',
     'ignite-console.states.configuration',
     'ignite-console.states.admin',
     'ignite-console.states.errors',
@@ -218,6 +220,10 @@ angular.module('ignite-console', [
     connectedClusters.name,
     igniteListOfRegisteredUsers.name,
     pageProfile.name,
+    pageSignIn.name,
+    pageLanding.name,
+    pagePasswordChanged.name,
+    pagePasswordReset.name,
     // Ignite modules.
     IgniteModules.name
 ])

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/frontend/app/components/page-configure/index.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/page-configure/index.js 
b/modules/web-console/frontend/app/components/page-configure/index.js
index 172609f..8c4e3c2 100644
--- a/modules/web-console/frontend/app/components/page-configure/index.js
+++ b/modules/web-console/frontend/app/components/page-configure/index.js
@@ -23,6 +23,9 @@ import ConfigurationDownload from 
'./services/ConfigurationDownload';
 
 export default angular
     .module('ignite-console.page-configure', [])
+    .config(['DefaultStateProvider', (DefaultState) => {
+        DefaultState.setRedirectTo(() => 'base.configuration.tabs');
+    }])
     .component('pageConfigure', component)
     .service('PageConfigure', PageConfigure)
     .service('ConfigureState', ConfigureState)

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/frontend/app/components/page-landing/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-landing/index.js 
b/modules/web-console/frontend/app/components/page-landing/index.js
new file mode 100644
index 0000000..037f3d4
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-landing/index.js
@@ -0,0 +1,65 @@
+/*
+ * 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 template from './template.pug';
+import './style.scss';
+
+export default angular
+    .module('ignite-console.landing', [
+        'ui.router',
+        'ignite-console.user'
+    ])
+    .component('pageLanding', {
+        template,
+        controller: class LandingController {
+            static images = [
+                '/images/page-landing-carousel-1.png',
+                '/images/page-landing-carousel-2.png',
+                '/images/page-landing-carousel-3.png'
+            ];
+
+            $onInit() {
+                this.images = LandingController.images;
+            }
+        }
+    })
+    .config(['$stateProvider', function($stateProvider) {
+        // set up the states
+        $stateProvider
+        .state('landing', {
+            url: '/',
+            template: '<page-landing></page-landing>',
+            redirectTo: (trans) => {
+                return trans.injector().get('User').read()
+                    .then(() => {
+                        try {
+                            const {name, params} = 
JSON.parse(localStorage.getItem('lastStateChangeSuccess'));
+
+                            const restored = 
trans.router.stateService.target(name, params);
+
+                            return restored.valid() ? restored : 
'base.configuration.tabs';
+                        } catch (ignored) {
+                            return 'base.configuration.tabs';
+                        }
+                    })
+                    .catch(() => true);
+            },
+            unsaved: true
+        });
+    }]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/frontend/app/components/page-landing/style.scss
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/page-landing/style.scss 
b/modules/web-console/frontend/app/components/page-landing/style.scss
new file mode 100644
index 0000000..a92206b
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-landing/style.scss
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@mixin custom_btn {
+    font-weight: 500;
+    padding: 10px 25px !important;
+}
+
+#signin_show {
+    @include custom_btn;
+}
+
+page-landing {
+    font-family: Roboto;
+
+    .btn-custom {
+        @include custom_btn;
+    }
+
+    section.intro-container-wrapper {
+        padding: 40px 0;
+
+        background-color: #f9f9f9;
+        border-bottom: 1px solid #aaaaaa;
+
+        .intro-content {
+            padding-right: 70px;
+        }
+
+        h1 {
+            margin-top: 45px;
+            font-size: 48px;
+            line-height: 55px;
+            font-weight: 300;
+        }
+
+        h2 {
+            margin-bottom: 20px;
+            font-size: 24px;
+            font-style: italic;
+            font-weight: 300;
+        }
+
+        p {
+            font-size: 16px;
+            font-weight: 300;
+            color: #777777;
+        }
+
+        .btn-custom {
+            margin-top: 20px;
+            padding: 10px 40px !important;
+            border-color: #f9f9f9 !important;
+        }
+    }
+
+    section.features-container-wrapper {
+        padding: 25px 0 60px;
+        background-color: #ffffff;
+
+        .section-title {
+            font-size: 38px;
+            font-weight: 300;
+            color: #444444;
+            margin: 30px 0 60px;
+        }
+
+        .feature {
+            margin: 30px 0;
+
+            h3 {
+                font-size: 24px;
+                font-weight: normal;
+                color: #000000;
+                line-height: 28px;
+                margin-bottom: 10px;
+            }
+
+            p {
+                color: #666666;
+                font-size: 16px;
+            }
+
+            i.fa {
+                font-size: 48px;
+                color: #bbbbbb;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/frontend/app/components/page-landing/template.pug
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/page-landing/template.pug 
b/modules/web-console/frontend/app/components/page-landing/template.pug
new file mode 100644
index 0000000..a1ce4f7
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-landing/template.pug
@@ -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.
+
+web-console-header
+    web-console-header-left
+        ignite-header-title
+    web-console-header-right
+        a#signin_show.btn-ignite.btn-ignite--primary(ui-sref='signin') Sign In
+
+section.intro-container-wrapper
+    .container
+        .col-lg-6.col-md-6.col-sm-6.col-xs-12.intro-content
+            h1  Web Console
+            h2 An Interactive Configuration Wizard and Management Tool for 
Apache™ Ignite®
+            p It provides an interactive configuration wizard which helps you 
create and download configuration files and code snippets for your Apache 
Ignite projects. Additionally, the tool allows you to automatically load SQL 
metadata from any RDBMS, run SQL queries on your in-memory cache as well as 
view execution plans, in-memory schema, and streaming charts.
+            a#signup_show.btn.btn-lg.btn-primary.btn-custom(ui-sref='signin') 
Try Now
+        .col-lg-6.col-md-6.col-sm-6.col-xs-12
+            ui-carousel(slides='$ctrl.images' autoplay='true' 
slides-to-show='1' arrows='false')
+                carousel-item
+                    img(ng-src='{{item}}')
+section.features-container-wrapper
+    .container.features-container
+        .section-title  Web Console allows you to:
+        .row
+            .col-lg-6.col-md-6.col-sm-6.col-xs-12.feature
+                .col-lg-2.col-md-2.col-sm-2.col-xs-2
+                    i.fa.fa-sitemap
+                .col-lg-9.col-md-9.col-sm-9.col-xs-9
+                    h3 Configure Apache Ignite Clusters and Caches
+                    p The Web Console configuration wizard takes you through a 
step-by-step process to define all of your required configuration parameters. 
The system then generates a ready-to-use project with all of the required 
config files for you.
+            .col-lg-6.col-md-6.col-sm-6.col-xs-12.feature
+                .col-lg-2.col-md-2.col-sm-2.col-xs-2
+                    i.fa.fa-search
+                .col-lg-9.col-md-9.col-sm-9.col-xs-9
+                    h3 Run Free Form SQL Queries on #[br] Apache Ignite Caches
+                    p By connecting The Web Console to your Apache Ignite 
cluster, you can execute SQL queries on your in-memory cache. You can also view 
the execution plan, in-memory schema, and streaming charts for your cluster.
+        .row
+            .col-lg-6.col-md-6.col-sm-6.col-xs-12.feature
+                .col-lg-2.col-md-2.col-sm-2.col-xs-2
+                    i.fa.fa-database
+                .col-lg-9.col-md-9.col-sm-9.col-xs-9
+                    h3 Import Database Schemas from #[br] Virtually Any RDBMS
+                    p To speed the creation of your configuration files, The 
Web Console allows you to automatically import the database schema from any 
current RDBMS.  and Apache Ignite support virtually any RDBMS including Oracle, 
SAP, MySQL, PostgreSQL and many more.
+            .col-lg-6.col-md-6.col-sm-6.col-xs-12.feature
+                .col-lg-2.col-md-2.col-sm-2.col-xs-2
+                    i.fa.fa-gears
+                .col-lg-9.col-md-9.col-sm-9.col-xs-9
+                    h3 Manage The Web Console users
+                    p With The Web Console you can have accounts with 
different roles.
+        .align-center.text-center
+            a.btn.btn-lg.btn-primary.btn-custom(ui-sref='signin') Get Started
+
+web-console-footer

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/frontend/app/components/page-password-changed/controller.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/page-password-changed/controller.js
 
b/modules/web-console/frontend/app/components/page-password-changed/controller.js
new file mode 100644
index 0000000..5b8301d
--- /dev/null
+++ 
b/modules/web-console/frontend/app/components/page-password-changed/controller.js
@@ -0,0 +1,18 @@
+/*
+ *  Copyright (C) GridGain Systems. All Rights Reserved.
+ *  _________        _____ __________________        _____
+ *  __  ____/___________(_)______  /__  ____/______ ____(_)_______
+ *  _  / __  __  ___/__  / _  __  / _  / __  _  __ `/__  / __  __ \
+ *  / /_/ /  _  /    _  /  / /_/ /  / /_/ /  / /_/ / _  /  _  / / /
+ *  \____/   /_/     /_/   \_,__/   \____/   \__,_/  /_/   /_/ /_/
+ */
+
+export default class {
+    static $inject = ['$state', '$timeout'];
+
+    constructor($state, $timeout) {
+        $timeout(() => {
+            $state.go('signin');
+        }, 10000);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/frontend/app/components/page-password-changed/index.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/page-password-changed/index.js 
b/modules/web-console/frontend/app/components/page-password-changed/index.js
new file mode 100644
index 0000000..4d624a7
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-password-changed/index.js
@@ -0,0 +1,33 @@
+/*
+ *  Copyright (C) GridGain Systems. All Rights Reserved.
+ *  _________        _____ __________________        _____
+ *  __  ____/___________(_)______  /__  ____/______ ____(_)_______
+ *  _  / __  __  ___/__  / _  __  / _  / __  _  __ `/__  / __  __ \
+ *  / /_/ /  _  /    _  /  / /_/ /  / /_/ /  / /_/ / _  /  _  / / /
+ *  \____/   /_/     /_/   \_,__/   \____/   \__,_/  /_/   /_/ /_/
+ */
+
+import angular from 'angular';
+
+import template from './template.pug';
+import controller from './controller';
+
+import './style.scss';
+
+export default angular
+    .module('ignite-console.page-password-changed', [
+    ])
+    .component('pagePasswordChanged', {
+        template,
+        controller
+    })
+    .config(['$stateProvider', ($stateProvider) => {
+        $stateProvider.state('password.send', {
+            url: '/changed',
+            component: 'pagePasswordChanged',
+            tfMetaTags: {
+                title: 'Password send'
+            },
+            unsaved: true
+        });
+    }]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/frontend/app/components/page-password-changed/style.scss
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/page-password-changed/style.scss 
b/modules/web-console/frontend/app/components/page-password-changed/style.scss
new file mode 100644
index 0000000..944fc47
--- /dev/null
+++ 
b/modules/web-console/frontend/app/components/page-password-changed/style.scss
@@ -0,0 +1,34 @@
+/*
+ *  Copyright (C) GridGain Systems. All Rights Reserved.
+ *  _________        _____ __________________        _____
+ *  __  ____/___________(_)______  /__  ____/______ ____(_)_______
+ *  _  / __  __  ___/__  / _  __  / _  / __  _  __ `/__  / __  __ \
+ *  / /_/ /  _  /    _  /  / /_/ /  / /_/ /  / /_/ / _  /  _  / / /
+ *  \____/   /_/     /_/   \_,__/   \____/   \__,_/  /_/   /_/ /_/
+ */
+
+page-password-changed {
+    display: flex;
+    flex: 1 0 auto;
+    flex-direction: column;
+
+    min-height: 100%;
+
+    font-family: Roboto;
+
+    .body-container {
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        align-items: center;
+    }
+
+    h2 {
+        margin-bottom: 30px;
+    }
+
+    p {
+        font-size: 16px;
+        text-align: center;
+    }
+}    

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/frontend/app/components/page-password-changed/template.pug
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/page-password-changed/template.pug
 
b/modules/web-console/frontend/app/components/page-password-changed/template.pug
new file mode 100644
index 0000000..33f20d4
--- /dev/null
+++ 
b/modules/web-console/frontend/app/components/page-password-changed/template.pug
@@ -0,0 +1,14 @@
+//-
+   Copyright (C) GridGain Systems. All Rights Reserved.
+   _________        _____ __________________        _____
+   __  ____/___________(_)______  /__  ____/______ ____(_)_______
+   _  / __  __  ___/__  / _  __  / _  / __  _  __ `/__  / __  __ \
+   / /_/ /  _  /    _  /  / /_/ /  / /_/ /  / /_/ / _  /  _  / / /
+   \____/   /_/     /_/   \_,__/   \____/   \__,_/  /_/   /_/ /_/
+
+.container.body-container
+    h2 Ready!
+
+    p 
+        | Further instructions for password reset have been sent to your 
e-mail address.#[br]
+        | You'll be redirected back automatically in a few seconds. If not, 
please #[a(ui-sref='signin') click here].

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/frontend/app/components/page-password-reset/controller.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/page-password-reset/controller.js 
b/modules/web-console/frontend/app/components/page-password-reset/controller.js
new file mode 100644
index 0000000..6b40228
--- /dev/null
+++ 
b/modules/web-console/frontend/app/components/page-password-reset/controller.js
@@ -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.
+ */
+
+export default class {
+    static $inject = ['$modal', '$http', '$state', 'IgniteMessages'];
+
+    /**
+     * @param {mgcrea.ngStrap.modal.IModalService} $modal
+     * @param $http
+     * @param {StateProvider} $state
+     * @param Messages
+     */
+    constructor($modal, $http, $state, Messages) {
+        this.$http = $http;
+        this.$state = $state;
+        this.Messages = Messages;
+    }
+
+    $onInit() {
+        this.$http.post('/api/v1/password/validate/token', {token: 
this.$state.params.token})
+            .then(({data}) => this.ui = data);
+    }
+
+    // Try to reset user password for provided token.
+    resetPassword() {
+        this.$http.post('/api/v1/password/reset', {token: this.ui.token, 
password: this.ui.password})
+            .then(() => {
+                this.$state.go('signin');
+
+                this.Messages.showInfo('Password successfully changed');
+            })
+            .catch(({data, state}) => {
+                if (state === 503)
+                    this.$state.go('signin');
+
+                this.Messages.showError(data);
+            });
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/frontend/app/components/page-password-reset/index.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/page-password-reset/index.js 
b/modules/web-console/frontend/app/components/page-password-reset/index.js
new file mode 100644
index 0000000..e1042a6
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-password-reset/index.js
@@ -0,0 +1,57 @@
+/*
+/*
+ * 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 _ from 'lodash';
+
+import template from './template.pug';
+import controller from './controller';
+
+import './style.scss';
+
+export default angular
+    .module('ignite-console.page-password-reset', [
+    ])
+    .component('pagePasswordReset', {
+        template,
+        controller
+    })
+    .config(['$stateProvider', ($stateProvider) => {
+        // set up the states
+        $stateProvider
+        .state('password', {
+            url: '/password',
+            abstract: true,
+            template: '<ui-view></ui-view>'
+        })
+        .state('password.reset', {
+            url: '/reset?{token}',
+            component: 'pagePasswordReset',
+            redirectTo: (trans) => {
+                if (_.isEmpty(trans.params('to').token))
+                    return 'signin';
+
+                return true;
+            },
+            unsaved: true,
+            tfMetaTags: {
+                title: 'Reset password'
+            }
+        });
+    }]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/frontend/app/components/page-password-reset/style.scss
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/page-password-reset/style.scss 
b/modules/web-console/frontend/app/components/page-password-reset/style.scss
new file mode 100644
index 0000000..75f758e
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-password-reset/style.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.
+ */
+
+page-password-reset {
+       display: flex;
+    flex: 1 0 auto;
+    flex-direction: column;
+
+    footer {
+        display: flex;
+        justify-content: flex-end;
+    }
+
+    .btn-ignite + .btn-ignite {
+        margin-left: 10px;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/frontend/app/components/page-password-reset/template.pug
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/page-password-reset/template.pug 
b/modules/web-console/frontend/app/components/page-password-reset/template.pug
new file mode 100644
index 0000000..1acfab8
--- /dev/null
+++ 
b/modules/web-console/frontend/app/components/page-password-reset/template.pug
@@ -0,0 +1,80 @@
+//-
+    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
+
+web-console-header
+    web-console-header-left
+        ignite-header-title
+
+.container.body-container
+    .row
+        .main-content(ng-if='error')
+            .text-center
+                p {{::$ctrl.ui.error}}
+        div(ng-if='$ctrl.ui.token && !$ctrl.ui.error')
+            header.header-with-selector
+                div
+                    h1 Reset Password
+
+            -var form = '$ctrl.form'
+            form.theme--ignite(name='$ctrl.form' ng-init='reset_info.token = 
token')
+                .row
+                    .col-50
+                        +form-field__email({
+                            label: 'E-mail:',
+                            model: '$ctrl.ui.email',
+                            disabled: true
+                        })
+
+                .row
+                    .col-50
+                        +form-field__password({
+                            label: 'New password:',
+                            model: '$ctrl.ui.password',
+                            name: '"password"',
+                            required: true,
+                            placeholder: 'New password'
+                        })(
+                            ignite-auto-focus
+                            ignite-on-enter-focus-move='passwordConfirmInput'
+                        )
+
+                .row
+                    .col-50
+                        +form-field__password({
+                            label: 'Confirm password:',
+                            model: 'confirm',
+                            name: '"passwordConfirm"',
+                            required: true,
+                            placeholder: 'Confirm new password'
+                        })(
+                            ignite-on-enter-focus-move='resetForm.$valid && 
resetPassword(user_info)'
+                            ignite-match='$ctrl.ui.password'
+                        )
+
+                hr
+
+                footer
+                    a.btn-ignite.btn-ignite--link-success(type='button' 
ui-sref='default-state') Cancel
+                    button.btn-ignite.btn-ignite--success(
+                        ng-disabled='$ctrl.form.$invalid'
+                        ng-click='$ctrl.resetPassword()'
+                    )
+                        svg.icon-left(ignite-icon='checkmark')
+                        | Save Changes
+
+web-console-footer

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/frontend/app/components/page-profile/controller.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/page-profile/controller.js 
b/modules/web-console/frontend/app/components/page-profile/controller.js
index b60340b..3fc7318 100644
--- a/modules/web-console/frontend/app/components/page-profile/controller.js
+++ b/modules/web-console/frontend/app/components/page-profile/controller.js
@@ -25,14 +25,12 @@ export default class PageProfileController {
     }
 
     $onInit() {
-        const self = this;
-
-        self.ui = {};
+        this.ui = {};
 
         this.User.read()
-            .then((user) => self.ui.user = angular.copy(user));
+            .then((user) => this.ui.user = angular.copy(user));
 
-        self.ui.countries = this.Countries.getAll();
+        this.ui.countries = this.Countries.getAll();
     }
 
     toggleToken() {

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/frontend/app/components/page-profile/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-profile/index.js 
b/modules/web-console/frontend/app/components/page-profile/index.js
index d9921b3..faa3c21 100644
--- a/modules/web-console/frontend/app/components/page-profile/index.js
+++ b/modules/web-console/frontend/app/components/page-profile/index.js
@@ -16,7 +16,11 @@
  */
 
 import angular from 'angular';
+
 import component from './component';
+import template from 'views/base2.pug';
+
+import './style.scss';
 
 export default angular
     .module('ignite-console.page-profile', [
@@ -26,7 +30,14 @@ export default angular
         // set up the states
         $stateProvider.state('base.settings.profile', {
             url: '/profile',
-            component: 'pageProfile',
+            views: {
+                '@': {
+                    template
+                },
+                '@base.settings.profile': {
+                    component: 'pageProfile'
+                }
+            },
             permission: 'profile',
             tfMetaTags: {
                 title: 'User profile'

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/frontend/app/components/page-profile/style.scss
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/page-profile/style.scss 
b/modules/web-console/frontend/app/components/page-profile/style.scss
new file mode 100644
index 0000000..a96914e
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-profile/style.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.
+ */
+
+page-profile {
+    .panel--ignite {
+        width: 100%;
+    }
+
+    footer {
+        display: flex;
+        justify-content: flex-end;
+    }
+
+    .btn-ignite + .btn-ignite {
+        margin-left: 10px;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/frontend/app/components/page-profile/template.pug
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/page-profile/template.pug 
b/modules/web-console/frontend/app/components/page-profile/template.pug
index 5331670..48aa151 100644
--- a/modules/web-console/frontend/app/components/page-profile/template.pug
+++ b/modules/web-console/frontend/app/components/page-profile/template.pug
@@ -14,70 +14,143 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 
-mixin lbl(txt)
-    label.col-sm-2.required.labelFormField #{txt}
+include /app/helpers/jade/mixins
 
-mixin lbl-not-required(txt)
-    label.col-sm-2.labelFormField #{txt}
-
-.row
-    .docs-content
-        .docs-header
+div
+    header.header-with-selector
+        div
             h1 User profile
-            hr
-        .docs-body
-            form.form-horizontal(name='$ctrl.form' novalidate)
-                .col-sm-10(style='padding: 0')
-                    .details-row
-                        +lbl('First name:')
-                        .col-xs-5.col-sm-4
-                            
input#profile-firstname.form-control(ignite-on-enter-focus-move='profile-lastname'
 type='text' ng-model='$ctrl.ui.user.firstName' placeholder='Input first name' 
required ignite-auto-focus)
-                    .details-row
-                        +lbl('Last name:')
-                        .col-xs-5.col-sm-4
-                            
input#profile-lastname.form-control(ignite-on-enter-focus-move='profile-email' 
type='text' ng-model='$ctrl.ui.user.lastName' placeholder='Input last name' 
required)
-                    .details-row
-                        +lbl('Email:')
-                        .col-xs-5.col-sm-4
-                            
input#profile-email.form-control(ignite-on-enter-focus-move='profile-company' 
type='email' ng-model='$ctrl.ui.user.email' placeholder='Input email' required)
-                    .details-row
-                        +lbl-not-required('Phone:')
-                        .col-xs-5.col-sm-4
-                            
input#profile-phone.form-control(ignite-on-enter-focus-move='profile-company' 
type='tel' ng-model='$ctrl.ui.user.phone' placeholder='Input phone')
-                    .details-row
-                        +lbl('Company:')
-                        .col-xs-5.col-sm-4
-                            
input#profile-company.form-control(ignite-on-enter-focus-move='profile-country' 
type='text' ng-model='$ctrl.ui.user.company' placeholder='Input company name' 
required)
-                    .details-row
-                        +lbl('Country:')
-                        .col-xs-5.col-sm-4
-                            
button#profile-country.select-toggle.form-control(bs-select 
bs-options='item.name as item.name for item in $ctrl.ui.countries' type='text' 
ng-model='$ctrl.ui.user.country' placeholder='Choose your country' 
ng-required='true')
-                    .details-row#security-token-section
-                        .advanced-options
-                            i.fa(
-                            ng-click='$ctrl.toggleToken()'
-                            ng-class='$ctrl.ui.expandedToken ? 
"fa-chevron-circle-down" : "fa-chevron-circle-right"')
-                            a(ng-click='$ctrl.toggleToken()') 
{{$ctrl.ui.expandedToken ? 'Cancel security token changing...' : 'Show security 
token...'}}
-                        div(ng-if='$ctrl.ui.expandedToken')
-                            +lbl('Security token:')
-                            label#current-security-token {{$ctrl.ui.user.token 
|| 'No security token. Regenerate please.'}}
-                            
i.tipLabel.fa.fa-refresh(ng-click='$ctrl.generateToken()' bs-tooltip='' 
data-title='Generate random security token')
-                            
i.tipLabel.fa.fa-clipboard(ignite-copy-to-clipboard='{{$ctrl.ui.user.token}}' 
bs-tooltip='' data-title='Copy security token to clipboard')
-                            i.tipLabel.icon-help(ng-if=lines bs-tooltip='' 
data-title='The security token is used for authorization of web agent')
-                    .details-row#change-password-section
-                        .advanced-options
-                            i.fa(
-                            ng-click='$ctrl.togglePassword()'
-                            ng-class='$ctrl.ui.expandedPassword ? 
"fa-chevron-circle-down" : "fa-chevron-circle-right"')
-                            a(ng-click='$ctrl.togglePassword()') 
{{$ctrl.ui.expandedPassword ? 'Cancel password changing...' : 'Change 
password...'}}
-                        div(ng-if='$ctrl.ui.expandedPassword')
-                            .details-row
-                                +lbl('New password:')
-                                .col-xs-5.col-sm-4
-                                    
input#profile_password.form-control(ignite-on-enter-focus-move='profile_confirm'
 type='password' ng-model='$ctrl.ui.user.password' placeholder='New password' 
required)
-                            .details-row
-                                +lbl('Confirm:')
-                                .col-xs-5.col-sm-4
-                                    
input#profile_confirm.form-control(type='password' ng-model='user.confirm' 
ignite-match='$ctrl.ui.user.password' placeholder='Confirm new password' 
required)
-                .col-xs-12.col-sm-12.details-row
-                    button.btn.btn-primary(ng-click='$ctrl.saveUser()' 
ng-disabled='$ctrl.form.$invalid') Save
+
+    -var form = '$ctrl.form'
+    form.theme--ignite(name='$ctrl.form' novalidate)
+        .row
+            .col-25
+                +form-field__text({
+                    label: 'First name:',
+                    model: '$ctrl.ui.user.firstName',
+                    name: '"firstName"',
+                    required: true,
+                    placeholder: 'Input first name'
+                })(
+                ignite-auto-focus
+                    ignite-on-enter-focus-move='lastNameInput'
+                )
+            .col-25
+                +form-field__text({
+                    label: 'Last name:',
+                    model: '$ctrl.ui.user.lastName',
+                    name: '"lastName"',
+                    required: true,
+                    placeholder: 'Input last name'
+                })(
+                    ignite-on-enter-focus-move='emailInput'
+                )
+        .row
+            .col-50
+                +form-field__email({
+                    label: 'Email:',
+                    model: '$ctrl.ui.user.email',
+                    name: '"email"',
+                    required: true,
+                    placeholder: 'Input email'
+                })(
+                    ignite-on-enter-focus-move='phoneInput'
+                )
+        .row
+            .col-25
+                +form-field__phone({
+                    label: 'Phone:',
+                    model: '$ctrl.ui.user.phone',
+                    name: '"phone"',
+                    optional: true,
+                    placeholder: 'Input phone (ex.: +15417543010)'
+                })(
+                    ignite-on-enter-focus-move='companyInput'
+                )
+            .col-25
+                +form-field__dropdown({
+                    label: 'Country:',
+                    model: '$ctrl.ui.user.country',
+                    name: '"country"',
+                    required: true,
+                    placeholder: 'Choose your country',
+                    options: '$ctrl.ui.countries'
+                })
+        .row
+            .col-50
+                +form-field__text({
+                    label: 'Company:',
+                    model: '$ctrl.ui.user.company',
+                    name: '"company"',
+                    required: true,
+                    placeholder: 'Input company name'
+                })(
+                    ignite-on-enter-focus-move='countryInput'
+                )
+
+        .row#security-token-section
+            .col-50
+                .panel--ignite.panel--collapse(ng-class='{ in: 
!$ctrl.ui.expandedToken }')
+                    header(ng-click='$ctrl.toggleToken()')
+                        svg(ignite-icon='expand')
+                        svg(ignite-icon='collapse')
+
+                        | {{$ctrl.ui.expandedToken ? 'Cancel security token 
changing...' : 'Show security token...'}}
+                    hr
+                    section(ng-if='$ctrl.ui.expandedToken')
+                        .row
+                            .col-25
+                                label.required Security token:
+                            .col-75
+                                label#current-security-token 
{{$ctrl.ui.user.token || 'No security token. Regenerate please.'}}
+                                label
+                                    
i.tipLabel.fa.fa-refresh(ng-click='$ctrl.generateToken()' bs-tooltip='' 
data-title='Generate random security token')
+                                    
i.tipLabel.fa.fa-clipboard(ignite-copy-to-clipboard='{{$ctrl.ui.user.token}}' 
bs-tooltip='' data-title='Copy security token to clipboard')
+                                    i.tipLabel.icon-help(ng-if=lines 
bs-tooltip='' data-title='The security token is used for authorization of web 
agent')
+
+        .row
+            .col-50
+                .panel--ignite.panel--collapse(ng-class='{ in: 
!$ctrl.ui.expandedPassword }')
+                    header(ng-click='$ctrl.togglePassword()')
+                        svg(ignite-icon='expand')
+                        svg(ignite-icon='collapse')
+
+                        | {{ $ctrl.ui.expandedPassword ? 'Cancel password 
changing...' : 'Change password...' }}
+                    hr
+                    section(ng-if='$ctrl.ui.expandedPassword')
+                        .row
+                            .col-100
+                                +form-field__password({
+                                    label: 'New password:',
+                                    model: '$ctrl.ui.user.password',
+                                    name: '"password"',
+                                    required: true,
+                                    placeholder: 'New password'
+                                })(
+                                    ignite-auto-focus
+                                    
ignite-on-enter-focus-move='passwordConfirmInput'
+                                )
+
+                        .row
+                            .col-100
+                                +form-field__password({
+                                    label: 'Confirm password:',
+                                    model: 'user.confirm',
+                                    name: '"passwordConfirm"',
+                                    required: true,
+                                    placeholder: 'Confirm new password'
+                                })(
+                                    
ignite-on-enter-focus-move='passwordConfirmInput'
+                                    ignite-match='$ctrl.ui.user.password'
+                                )
+
+    hr
+
+    footer
+        a.btn-ignite.btn-ignite--link-success(type='button' 
ui-sref='default-state') Cancel
+        button.btn-ignite.btn-ignite--success(
+            ng-click='$ctrl.saveUser()'
+            ng-disabled='$ctrl.form.$invalid'
+        )
+            svg.icon-left(ignite-icon='checkmark')
+            | Save Changes

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/frontend/app/components/page-signin/controller.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/page-signin/controller.js 
b/modules/web-console/frontend/app/components/page-signin/controller.js
new file mode 100644
index 0000000..585bb7a
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-signin/controller.js
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Sign in controller.
+export default class {
+    static $inject = ['$scope', '$uiRouterGlobals', 'IgniteFocus', 
'IgniteCountries', 'Auth'];
+
+    constructor($scope, $uiRouterGlobals, Focus, Countries, Auth) {
+        this.auth = Auth.auth;
+        this.forgotPassword = Auth.forgotPassword;
+        this.action = 'signin';
+        this.countries = Countries.getAll();
+
+        Focus.move('user_email');
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/frontend/app/components/page-signin/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-signin/index.js 
b/modules/web-console/frontend/app/components/page-signin/index.js
new file mode 100644
index 0000000..6be374f
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-signin/index.js
@@ -0,0 +1,56 @@
+/*
+ * 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 template from './template.pug';
+import controller from './controller';
+import './style.scss';
+
+export default angular
+    .module('ignite-console.sign-in', [
+        'ui.router',
+        'ignite-console.user'
+    ])
+    .component('pageSignIn', {
+        controller,
+        template
+    })
+    .config(['$stateProvider', function($stateProvider) {
+        // set up the states
+        $stateProvider
+        .state('signin', {
+            url: '/signin',
+            template: '<page-sign-in></page-sign-in>',
+            redirectTo: (trans) => {
+                return trans.injector().get('User').read()
+                    .then(() => {
+                        try {
+                            const {name, params} = 
JSON.parse(localStorage.getItem('lastStateChangeSuccess'));
+
+                            const restored = 
trans.router.stateService.target(name, params);
+
+                            return restored.valid() ? restored : 
'default-state';
+                        } catch (ignored) {
+                            return 'default-state';
+                        }
+                    })
+                    .catch(() => true);
+            },
+            unsaved: true
+        });
+    }]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/19256745/modules/web-console/frontend/app/components/page-signin/style.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-signin/style.scss 
b/modules/web-console/frontend/app/components/page-signin/style.scss
new file mode 100644
index 0000000..7e13ffe
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-signin/style.scss
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+page-sign-in {
+    display: flex;
+    flex-direction: column;
+    flex: 1 0 auto;
+
+    font-family: Roboto;
+
+    h3 {
+        font-size: 38px;
+        font-weight: 300;
+        margin: 30px 0 60px;
+    }
+
+    section {
+        flex-grow: 1;
+        padding: 25px 0 60px;
+
+        background-color: #ffffff;
+        color: #444444;
+    }
+}
\ No newline at end of file

Reply via email to