Repository: ignite
Updated Branches:
  refs/heads/master e1a62b2f0 -> b2a707748


IGNITE-8370 Web Console: Trigger validation before submitting auth forms.


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

Branch: refs/heads/master
Commit: b2a7077484f59e2bde76299577d8c3aafe0e1152
Parents: e1a62b2
Author: Ilya Borisov <klast...@gmail.com>
Authored: Thu May 17 15:53:46 2018 +0700
Committer: Alexey Kuznetsov <akuznet...@apache.org>
Committed: Thu May 17 15:53:46 2018 +0700

----------------------------------------------------------------------
 .../testcafe/fixtures/auth/forgot-password.js   |  3 +-
 .../fixtures/auth/signup-validation-local.js    | 52 ++++++++++++++++++++
 .../e2e/testcafe/fixtures/auth/signup.js        | 15 +-----
 modules/web-console/frontend/app/app.js         |  2 +
 .../frontend/app/components/form-field/index.js | 23 +++++++++
 .../form-field/showValidationError.directive.js | 47 ++++++++++++++++++
 .../page-configure/components/pcValidation.js   | 22 ---------
 .../page-forgot-password/controller.js          | 22 +++++++--
 .../page-forgot-password/template.pug           |  1 -
 .../app/components/page-signin/controller.js    | 24 +++++++--
 .../app/components/page-signin/template.pug     |  5 +-
 .../app/components/page-signup/controller.js    | 21 ++++++--
 .../app/components/page-signup/template.pug     |  1 -
 .../app/primitives/form-field/dropdown.pug      |  1 +
 .../app/primitives/form-field/index.scss        | 28 +++++++++++
 .../frontend/app/services/FormUtils.service.js  |  6 +--
 16 files changed, 214 insertions(+), 59 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/b2a70774/modules/web-console/e2e/testcafe/fixtures/auth/forgot-password.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/fixtures/auth/forgot-password.js 
b/modules/web-console/e2e/testcafe/fixtures/auth/forgot-password.js
index 1163595..33963fa 100644
--- a/modules/web-console/e2e/testcafe/fixtures/auth/forgot-password.js
+++ b/modules/web-console/e2e/testcafe/fixtures/auth/forgot-password.js
@@ -33,8 +33,7 @@ fixture('Password reset')
 test('Incorrect email', async(t) => {
     await t
         .typeText(page.email.control, 'aa')
-        .expect(page.email.getError('email').exists).ok('Marks field as 
invalid')
-        
.expect(page.remindPasswordButton.getAttribute('disabled')).ok('Disables submit 
button');
+        .expect(page.email.getError('email').exists).ok('Marks field as 
invalid');
 });
 
 test('Unknown email', async(t) => {

http://git-wip-us.apache.org/repos/asf/ignite/blob/b2a70774/modules/web-console/e2e/testcafe/fixtures/auth/signup-validation-local.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/e2e/testcafe/fixtures/auth/signup-validation-local.js 
b/modules/web-console/e2e/testcafe/fixtures/auth/signup-validation-local.js
new file mode 100644
index 0000000..d2e125c
--- /dev/null
+++ b/modules/web-console/e2e/testcafe/fixtures/auth/signup-validation-local.js
@@ -0,0 +1,52 @@
+/*
+ * 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 {resolveUrl} from '../../envtools';
+import {pageSignup as page} from '../../page-models/pageSignup';
+
+fixture('Signup validation local').page(resolveUrl('/signup'));
+
+test('Most fields have validation', async(t) => {
+    await page.fillSignupForm({
+        email: 'foobar',
+        password: '1',
+        passwordConfirm: '2',
+        firstName: '  ',
+        lastName: '   ',
+        company: '   ',
+        country: 'Brazil'
+    });
+
+    await t
+        .expect(page.email.getError('email').exists).ok()
+        .expect(page.passwordConfirm.getError('mismatch').exists).ok()
+        .expect(page.firstName.getError('required').exists).ok()
+        .expect(page.lastName.getError('required').exists).ok()
+        .expect(page.company.getError('required').exists).ok();
+});
+
+test('Errors on submit', async(t) => {
+    await t
+        .typeText(page.email.control, 'em...@example.com')
+        .click(page.signupButton)
+        .expect(page.password.control.focused).ok()
+        .expect(page.password.getError('required').exists).ok()
+        .typeText(page.password.control, 'Foo')
+        .click(page.signupButton)
+        .expect(page.passwordConfirm.control.focused).ok()
+        .expect(page.passwordConfirm.getError('required').exists).ok();
+});

http://git-wip-us.apache.org/repos/asf/ignite/blob/b2a70774/modules/web-console/e2e/testcafe/fixtures/auth/signup.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/fixtures/auth/signup.js 
b/modules/web-console/e2e/testcafe/fixtures/auth/signup.js
index f0951d9..cd08282 100644
--- a/modules/web-console/e2e/testcafe/fixtures/auth/signup.js
+++ b/modules/web-console/e2e/testcafe/fixtures/auth/signup.js
@@ -31,8 +31,6 @@ fixture('Signup')
     });
 
 test('Local validation', async(t) => {
-    const isButtonDisabled = page.signupButton.hasAttribute('disabled');
-    await t.expect(isButtonDisabled).ok('Button disabled by default');
     await page.fillSignupForm({
         email: 'foobar',
         password: '1',
@@ -45,18 +43,7 @@ test('Local validation', async(t) => {
     await t
         .expect(page.email.getError('email').exists).ok()
         .expect(page.passwordConfirm.getError('mismatch').exists).ok()
-        .expect(page.firstName.getError('required').exists).ok()
-        .expect(isButtonDisabled).ok('Button disabled with invalid fields');
-    await page.fillSignupForm({
-        email: 'foo...@bar.baz',
-        password: '1',
-        passwordConfirm: '1',
-        firstName: 'John',
-        lastName: 'Doe',
-        company: 'FooBar',
-        country: 'Brazil'
-    });
-    await t.expect(isButtonDisabled).notOk('Button enabled with valid fields');
+        .expect(page.firstName.getError('required').exists).ok();
 });
 test('Server validation', async(t) => {
     await page.fillSignupForm({

http://git-wip-us.apache.org/repos/asf/ignite/blob/b2a70774/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 b4e71fa..d28f1bc 100644
--- a/modules/web-console/frontend/app/app.js
+++ b/modules/web-console/frontend/app/app.js
@@ -139,6 +139,7 @@ import connectedClusters from 
'./components/connected-clusters';
 import pageLanding from './components/page-landing';
 import passwordVisibility from './components/password-visibility';
 import progressLine from './components/progress-line';
+import formField from './components/form-field';
 
 import pageProfile from './components/page-profile';
 import pagePasswordChanged from './components/page-password-changed';
@@ -246,6 +247,7 @@ angular.module('ignite-console', [
     breadcrumbs.name,
     passwordVisibility.name,
     progressLine.name,
+    formField.name,
     // Ignite modules.
     IgniteModules.name
 ])

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

http://git-wip-us.apache.org/repos/asf/ignite/blob/b2a70774/modules/web-console/frontend/app/components/form-field/showValidationError.directive.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/form-field/showValidationError.directive.js
 
b/modules/web-console/frontend/app/components/form-field/showValidationError.directive.js
new file mode 100644
index 0000000..32123cc
--- /dev/null
+++ 
b/modules/web-console/frontend/app/components/form-field/showValidationError.directive.js
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+/**
+ * Brings user attention to invalid form fields.
+ * Use IgniteFormUtils.triggerValidation to trigger the event.
+ */
+export function directive($timeout) {
+    return {
+        require: ['ngModel', '?^^bsCollapseTarget', '?^^igniteFormField', 
'?^^panelCollapsible'],
+        link(scope, el, attr, [ngModel, bsCollapseTarget, igniteFormField, 
panelCollapsible]) {
+            const off = scope.$on('$showValidationError', (e, target) => {
+                if (target !== ngModel) return;
+                ngModel.$setTouched();
+                bsCollapseTarget && bsCollapseTarget.open();
+                panelCollapsible && panelCollapsible.open();
+                $timeout(() => {
+                    if (el[0].scrollIntoViewIfNeeded)
+                        el[0].scrollIntoViewIfNeeded();
+                    else
+                        el[0].scrollIntoView();
+
+                    if (!attr.bsSelect)
+                        $timeout(() => el[0].focus());
+
+                    igniteFormField && igniteFormField.notifyAboutError();
+                });
+            });
+        }
+    };
+}
+
+directive.$inject = ['$timeout'];

http://git-wip-us.apache.org/repos/asf/ignite/blob/b2a70774/modules/web-console/frontend/app/components/page-configure/components/pcValidation.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/page-configure/components/pcValidation.js
 
b/modules/web-console/frontend/app/components/page-configure/components/pcValidation.js
index 5ddd4ef..e4c7314 100644
--- 
a/modules/web-console/frontend/app/components/page-configure/components/pcValidation.js
+++ 
b/modules/web-console/frontend/app/components/page-configure/components/pcValidation.js
@@ -146,28 +146,6 @@ export default 
angular.module('ignite-console.page-configure.validation', [])
             }]
         };
     })
-    .directive('ngModel', ['$timeout', function($timeout) {
-        return {
-            require: ['ngModel', '?^^bsCollapseTarget', '?^^igniteFormField', 
'?^^panelCollapsible'],
-            link(scope, el, attr, [ngModel, bsCollapseTarget, igniteFormField, 
panelCollapsible]) {
-                const off = scope.$on('$showValidationError', (e, target) => {
-                    if (target !== ngModel) return;
-                    ngModel.$setTouched();
-                    bsCollapseTarget && bsCollapseTarget.open();
-                    panelCollapsible && panelCollapsible.open();
-                    $timeout(() => {
-                        if (el[0].scrollIntoViewIfNeeded)
-                            el[0].scrollIntoViewIfNeeded();
-                        else
-                            el[0].scrollIntoView();
-
-                        if (!attr.bsSelect) $timeout(() => el[0].focus());
-                        igniteFormField && igniteFormField.notifyAboutError();
-                    });
-                });
-            }
-        };
-    }])
     .directive('igniteFormField', function() {
         return {
             restrict: 'C',

http://git-wip-us.apache.org/repos/asf/ignite/blob/b2a70774/modules/web-console/frontend/app/components/page-forgot-password/controller.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/page-forgot-password/controller.js
 
b/modules/web-console/frontend/app/components/page-forgot-password/controller.js
index 92e8541..7d06773 100644
--- 
a/modules/web-console/frontend/app/components/page-forgot-password/controller.js
+++ 
b/modules/web-console/frontend/app/components/page-forgot-password/controller.js
@@ -25,14 +25,15 @@ export default class PageForgotPassword {
     /** @type {string} */
     serverError = null;
 
-    static $inject = ['Auth', 'IgniteMessages'];
+    static $inject = ['Auth', 'IgniteMessages', 'IgniteFormUtils'];
 
     /**
      * @param {import('app/modules/user/Auth.service').default} Auth
      */
-    constructor(Auth, IgniteMessages) {
+    constructor(Auth, IgniteMessages, IgniteFormUtils) {
         this.Auth = Auth;
         this.IgniteMessages = IgniteMessages;
+        this.IgniteFormUtils = IgniteFormUtils;
     }
     /** @param {import('./types').IForgotPasswordFormController} form */
     canSubmitForm(form) {
@@ -41,6 +42,13 @@ export default class PageForgotPassword {
     $postLink() {
         this.form.email.$validators.server = () => !this.serverError;
     }
+
+    /** @param {string} error */
+    setServerError(error) {
+        this.serverError = error;
+        this.form.email.$validate();
+    }
+
     /**
      * @param {{email: ng.IChangesObject<string>}} changes
      */
@@ -48,10 +56,16 @@ export default class PageForgotPassword {
         if ('email' in changes) this.data.email = changes.email.currentValue;
     }
     remindPassword() {
+        this.IgniteFormUtils.triggerValidation(this.form);
+
+        this.setServerError(null);
+
+        if (!this.canSubmitForm(this.form))
+            return;
+
         return this.Auth.remindPassword(this.data.email).catch((res) => {
             this.IgniteMessages.showError(null, res.data);
-            this.serverError = res.data;
-            this.form.email.$validate();
+            this.setServerError(res.data);
         });
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/b2a70774/modules/web-console/frontend/app/components/page-forgot-password/template.pug
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/page-forgot-password/template.pug 
b/modules/web-console/frontend/app/components/page-forgot-password/template.pug
index 6a11baf..2532959 100644
--- 
a/modules/web-console/frontend/app/components/page-forgot-password/template.pug
+++ 
b/modules/web-console/frontend/app/components/page-forgot-password/template.pug
@@ -44,7 +44,6 @@ web-console-header
                 button.btn-ignite.btn-ignite--primary(
                     tabindex='1'
                     type='submit'
-                    ng-disabled=`!$ctrl.canSubmitForm(${form})`
                 ) Send it to me
 
 web-console-footer

http://git-wip-us.apache.org/repos/asf/ignite/blob/b2a70774/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
index b13cf4b..f2d28e8 100644
--- a/modules/web-console/frontend/app/components/page-signin/controller.js
+++ b/modules/web-console/frontend/app/components/page-signin/controller.js
@@ -26,14 +26,15 @@ export default class {
     /** @type {string} */
     serverError = null;
 
-    static $inject = ['Auth', 'IgniteMessages'];
+    static $inject = ['Auth', 'IgniteMessages', 'IgniteFormUtils'];
 
     /**
      * @param {import('app/modules/user/Auth.service').default} Auth
      */
-    constructor(Auth, IgniteMessages) {
+    constructor(Auth, IgniteMessages, IgniteFormUtils) {
         this.Auth = Auth;
         this.IgniteMessages = IgniteMessages;
+        this.IgniteFormUtils = IgniteFormUtils;
     }
 
     /** @param {import('./types').ISigninFormController} form */
@@ -42,15 +43,28 @@ export default class {
     }
 
     $postLink() {
+        this.form.email.$validators.server = () => !this.serverError;
         this.form.password.$validators.server = () => !this.serverError;
     }
 
+    /** @param {string} error */
+    setServerError(error) {
+        this.serverError = error;
+        this.form.email.$validate();
+        this.form.password.$validate();
+    }
+
     signin() {
+        this.IgniteFormUtils.triggerValidation(this.form);
+
+        this.setServerError(null);
+
+        if (!this.canSubmitForm(this.form))
+            return;
+
         return this.Auth.signin(this.data.email, 
this.data.password).catch((res) => {
             this.IgniteMessages.showError(null, res.data);
-            this.serverError = res.data;
-            this.form.email.$validate();
-            this.form.password.$validate();
+            this.setServerError(res.data);
         });
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/b2a70774/modules/web-console/frontend/app/components/page-signin/template.pug
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/page-signin/template.pug 
b/modules/web-console/frontend/app/components/page-signin/template.pug
index fd5e95f..6047e65 100644
--- a/modules/web-console/frontend/app/components/page-signin/template.pug
+++ b/modules/web-console/frontend/app/components/page-signin/template.pug
@@ -36,7 +36,7 @@ web-console-header
                 autocomplete='email'
                 ignite-auto-focus
             )
-                +form-field__error({error: 'server', message: 
`{{$ctrl.serverErrors.}`})
+                +form-field__error({error: 'server', message: 
`{{$ctrl.serverError}}`})
             +form-field__password({
                 label: 'Password:',
                 model: '$ctrl.data.password',
@@ -47,12 +47,11 @@ web-console-header
                 ng-model-options='{allowInvalid: true}'
                 autocomplete='current-password'
             )
-                +form-field__error({error: 'server', message: 
`{{$ctrl.serverErrors}}`})
+                +form-field__error({error: 'server', message: 
`{{$ctrl.serverError}}`})
             footer.form-footer
                 a(ui-sref='forgotPassword({email: $ctrl.data.email})') Forgot 
password?
                 button.btn-ignite.btn-ignite--primary(
                     type='submit'
-                    ng-disabled=`!$ctrl.canSubmitForm(${form})`
                 ) Sign In
         footer.page-signin__no-account-message
             | Don't have an account? #[a(ui-sref='signup') Get started]

http://git-wip-us.apache.org/repos/asf/ignite/blob/b2a70774/modules/web-console/frontend/app/components/page-signup/controller.js
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/page-signup/controller.js 
b/modules/web-console/frontend/app/components/page-signup/controller.js
index ffc534a..57f404a 100644
--- a/modules/web-console/frontend/app/components/page-signup/controller.js
+++ b/modules/web-console/frontend/app/components/page-signup/controller.js
@@ -30,15 +30,16 @@ export default class PageSignup {
     /** @type {string} */
     serverError = null;
 
-    static $inject = ['IgniteCountries', 'Auth', 'IgniteMessages'];
+    static $inject = ['IgniteCountries', 'Auth', 'IgniteMessages', 
'IgniteFormUtils'];
 
     /**
      * @param {import('app/modules/user/Auth.service').default} Auth
      */
-    constructor(Countries, Auth, IgniteMessages) {
+    constructor(Countries, Auth, IgniteMessages, IgniteFormUtils) {
         this.Auth = Auth;
         this.IgniteMessages = IgniteMessages;
         this.countries = Countries.getAll();
+        this.IgniteFormUtils = IgniteFormUtils;
     }
 
     /** @param {import('./types').ISignupFormController} form */
@@ -50,11 +51,23 @@ export default class PageSignup {
         this.form.email.$validators.server = () => !this.serverError;
     }
 
+    /** @param {string} error */
+    setServerError(error) {
+        this.serverError = error;
+        this.form.email.$validate();
+    }
+
     signup() {
+        this.IgniteFormUtils.triggerValidation(this.form);
+
+        this.setServerError(null);
+
+        if (!this.canSubmitForm(this.form))
+            return;
+
         return this.Auth.signnup(this.data).catch((res) => {
             this.IgniteMessages.showError(null, res.data);
-            this.serverError = res.data;
-            this.form.email.$validate();
+            this.setServerError(res.data);
         });
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/b2a70774/modules/web-console/frontend/app/components/page-signup/template.pug
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/components/page-signup/template.pug 
b/modules/web-console/frontend/app/components/page-signup/template.pug
index 8cc7b14..254243e 100644
--- a/modules/web-console/frontend/app/components/page-signup/template.pug
+++ b/modules/web-console/frontend/app/components/page-signup/template.pug
@@ -114,7 +114,6 @@ web-console-header
             footer.full-width.form-footer
                 button.btn-ignite.btn-ignite--primary(
                     type='submit'
-                    ng-disabled=`!$ctrl.canSubmitForm(${form})`
                 ) Sign Up
         footer.page-signup__has-account-message
             | Already have an account? #[a(ui-sref='signin') Sign in here]

http://git-wip-us.apache.org/repos/asf/ignite/blob/b2a70774/modules/web-console/frontend/app/primitives/form-field/dropdown.pug
----------------------------------------------------------------------
diff --git 
a/modules/web-console/frontend/app/primitives/form-field/dropdown.pug 
b/modules/web-console/frontend/app/primitives/form-field/dropdown.pug
index c41825c..de83bf9 100644
--- a/modules/web-console/frontend/app/primitives/form-field/dropdown.pug
+++ b/modules/web-console/frontend/app/primitives/form-field/dropdown.pug
@@ -15,6 +15,7 @@
     limitations under the License.
 
 mixin form-field__dropdown({ label, model, name, disabled, required, multiple, 
placeholder, placeholderEmpty, options, tip })
+    -var errLbl = label.substring(0, label.length - 1)
     mixin __form-field__input()
         button.select-toggle(
             type='button'

http://git-wip-us.apache.org/repos/asf/ignite/blob/b2a70774/modules/web-console/frontend/app/primitives/form-field/index.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/primitives/form-field/index.scss 
b/modules/web-console/frontend/app/primitives/form-field/index.scss
index 800daa8..83dd55d 100644
--- a/modules/web-console/frontend/app/primitives/form-field/index.scss
+++ b/modules/web-console/frontend/app/primitives/form-field/index.scss
@@ -309,6 +309,7 @@
 }
 
 .form-field__checkbox {
+    $errorSize: 16px;
     display: flex;
 
     .form-field {
@@ -321,6 +322,7 @@
             width: auto;
             margin-right: 10px;
             padding: 3px 0;
+            flex: 0 0 auto;
 
             input {
                 width: auto;
@@ -328,6 +330,32 @@
                 margin: 0;
             }
         }
+
+        &__errors {
+            position: static;
+            right: initial;
+            bottom: initial;
+            order: 3;
+            margin-left: 5px;
+
+            .form-field__error {
+                width: $errorSize;
+                height: $errorSize;
+
+                div {
+                    // Required to correctly position error popover
+                    top: -10px;
+                    height: 36px;
+                    
+                    width: $errorSize;                    
+                }
+
+                [ignite-icon] {
+                    width: $errorSize;
+                    top: 0;
+                }
+            }
+        }
     }
 }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/b2a70774/modules/web-console/frontend/app/services/FormUtils.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/FormUtils.service.js 
b/modules/web-console/frontend/app/services/FormUtils.service.js
index da1d737..da6b417 100644
--- a/modules/web-console/frontend/app/services/FormUtils.service.js
+++ b/modules/web-console/frontend/app/services/FormUtils.service.js
@@ -16,7 +16,7 @@
  */
 import _ from 'lodash';
 
-export default ['IgniteFormUtils', ['$window', 'IgniteFocus', ($window, Focus) 
=> {
+export default ['IgniteFormUtils', ['$window', 'IgniteFocus', '$rootScope', 
($window, Focus, $rootScope) => {
     function ensureActivePanel(ui, pnl, focusId) {
         if (ui && ui.loadPanel) {
             const collapses = $('[bs-collapse-target]');
@@ -326,7 +326,7 @@ export default ['IgniteFormUtils', ['$window', 
'IgniteFocus', ($window, Focus) =
     }
 
     // TODO: move somewhere else
-    function triggerValidation(form, $scope) {
+    function triggerValidation(form) {
         const fe = (m) => Object.keys(m.$error)[0];
         const em = (e) => (m) => {
             if (!e) return;
@@ -338,7 +338,7 @@ export default ['IgniteFormUtils', ['$window', 
'IgniteFocus', ($window, Focus) =
             return walk(m);
         };
 
-        $scope.$broadcast('$showValidationError', em(fe(form))(form));
+        $rootScope.$broadcast('$showValidationError', em(fe(form))(form));
     }
 
     return {

Reply via email to