From: Tiago Melo Date: Fri, 23 Mar 2018 16:40:29 +0000 (+0000) Subject: mgr/dashboard: Add submit button component X-Git-Tag: wip-pdonnell-testing-20180329.205607~57^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=03fa8585ef85e74e3eb5ca90e2ed8cfd5fb89fa3;p=ceph-ci.git mgr/dashboard: Add submit button component This component is to be used inside a form. It will render a submit button with the given label. The button will disabled itself and show a loading icon when the user clicks it, usually initiating a request to the server, and it will stay in that state until the request is finished. To indicate that the request failed, returning the button to the enable state, you need to insert an error in the form with the 'cdSubmitButton' key. It will also check if the form is valid, when clicking the button, and will focus on the first invalid input. Signed-off-by: Tiago Melo --- diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts index 7094e1e24cc..efa9144bc57 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts @@ -6,6 +6,7 @@ import { AlertModule, PopoverModule } from 'ngx-bootstrap'; import { HelperComponent } from './helper/helper.component'; import { SparklineComponent } from './sparkline/sparkline.component'; +import { SubmitButtonComponent } from './submit-button/submit-button.component'; import { ViewCacheComponent } from './view-cache/view-cache.component'; @NgModule({ @@ -18,13 +19,15 @@ import { ViewCacheComponent } from './view-cache/view-cache.component'; declarations: [ ViewCacheComponent, SparklineComponent, - HelperComponent + HelperComponent, + SubmitButtonComponent ], providers: [], exports: [ ViewCacheComponent, SparklineComponent, - HelperComponent + HelperComponent, + SubmitButtonComponent ] }) export class ComponentsModule { } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/submit-button/submit-button.component.html b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/submit-button/submit-button.component.html new file mode 100644 index 00000000000..860473fc98d --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/submit-button/submit-button.component.html @@ -0,0 +1,9 @@ + diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/submit-button/submit-button.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/submit-button/submit-button.component.scss new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/submit-button/submit-button.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/submit-button/submit-button.component.spec.ts new file mode 100644 index 00000000000..6ff309f0762 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/submit-button/submit-button.component.spec.ts @@ -0,0 +1,30 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormGroup } from '@angular/forms'; + +import { SubmitButtonComponent } from './submit-button.component'; + +describe('SubmitButtonComponent', () => { + let component: SubmitButtonComponent; + let fixture: ComponentFixture; + + beforeEach( + async(() => { + TestBed.configureTestingModule({ + declarations: [SubmitButtonComponent] + }).compileComponents(); + }) + ); + + beforeEach(() => { + fixture = TestBed.createComponent(SubmitButtonComponent); + component = fixture.componentInstance; + + component.form = new FormGroup({}, {}); + + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/submit-button/submit-button.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/submit-button/submit-button.component.ts new file mode 100644 index 00000000000..c9b0ac41645 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/submit-button/submit-button.component.ts @@ -0,0 +1,66 @@ +import { Component, ElementRef, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { FormGroup } from '@angular/forms'; + +import * as _ from 'lodash'; + +/** + * This component will render a submit button with the given label. + * + * The button will disabled itself and show a loading icon when the user clicks + * it, usually initiating a request to the server, and it will stay in that + * state until the request is finished. + * + * To indicate that the request failed, returning the button to the enable + * state, you need to insert an error in the form with the 'cdSubmitButton' key. + * p.e.: this.rbdForm.setErrors({'cdSubmitButton': true}); + * + * It will also check if the form is valid, when clicking the button, and will + * focus on the first invalid input. + * + * @export + * @class SubmitButtonComponent + * @implements {OnInit} + */ +@Component({ + selector: 'cd-submit-button', + templateUrl: './submit-button.component.html', + styleUrls: ['./submit-button.component.scss'] +}) +export class SubmitButtonComponent implements OnInit { + @Input() form: FormGroup; + @Output() submitAction = new EventEmitter(); + + loading = false; + + constructor(private elRef: ElementRef) {} + + ngOnInit() { + this.form.statusChanges.subscribe(() => { + if (_.has(this.form.errors, 'cdSubmitButton')) { + this.loading = false; + _.unset(this.form.errors, 'cdSubmitButton'); + this.form.updateValueAndValidity(); + } + }); + } + + submit() { + if (this.form.invalid) { + this.focusInvalid(); + return; + } + + this.loading = true; + this.submitAction.emit(); + } + + focusInvalid() { + const target = this.elRef.nativeElement.offsetParent.querySelector( + 'input.ng-invalid, select.ng-invalid' + ); + + if (target) { + target.focus(); + } + } +}