From 12eb4d33823034930c7b416dc76115069b7b99f1 Mon Sep 17 00:00:00 2001 From: Steven Zou Date: Wed, 15 Feb 2017 11:02:59 +0800 Subject: [PATCH] Implement user sign-in component --- .gitignore | 12 ++ harbor-app/package.json | 114 ++++++++--------- harbor-app/src/app/account/account.module.ts | 2 +- .../src/app/account/sign-in.component.html | 29 ----- .../src/app/account/sign-in.component.ts | 10 -- .../app/account/sign-in/sign-in-credential.ts | 15 +++ .../app/account/sign-in/sign-in.component.css | 7 + .../account/sign-in/sign-in.component.html | 39 ++++++ .../app/account/sign-in/sign-in.component.ts | 121 ++++++++++++++++++ .../app/account/sign-in/sign-in.service.ts | 41 ++++++ .../src/app/account/sign-up.component.html | 1 + harbor-app/src/app/harbor-routing.module.ts | 2 +- 12 files changed, 295 insertions(+), 98 deletions(-) create mode 100644 .gitignore delete mode 100644 harbor-app/src/app/account/sign-in.component.html delete mode 100644 harbor-app/src/app/account/sign-in.component.ts create mode 100644 harbor-app/src/app/account/sign-in/sign-in-credential.ts create mode 100644 harbor-app/src/app/account/sign-in/sign-in.component.css create mode 100644 harbor-app/src/app/account/sign-in/sign-in.component.html create mode 100644 harbor-app/src/app/account/sign-in/sign-in.component.ts create mode 100644 harbor-app/src/app/account/sign-in/sign-in.service.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..2eab1ad71 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +coverage/ +dist/ +html-report/ +node_modules/ +typings/ +**/*npm-debug.log.* +**/*yarn-error.log.* +.idea/ +.DS_Store +proxy.config.json +*.log +**/*.log diff --git a/harbor-app/package.json b/harbor-app/package.json index dc6631441..cf7068e87 100644 --- a/harbor-app/package.json +++ b/harbor-app/package.json @@ -1,58 +1,58 @@ { - "name": "clarity-seed", - "version": "0.8.0", - "description": "Angular-CLI starter for a Clarity project", - "angular-cli": {}, - "scripts": { - "start": "ng serve --host 0.0.0.0", - "lint": "tslint \"src/**/*.ts\"", - "test": "ng test --single-run", - "pree2e": "webdriver-manager update", - "e2e": "protractor" - }, - "private": true, - "dependencies": { - "@angular/common": "^2.4.1", - "@angular/compiler": "^2.4.1", - "@angular/core": "^2.4.1", - "@angular/forms": "^2.4.1", - "@angular/http": "^2.4.1", - "@angular/platform-browser": "^2.4.1", - "@angular/platform-browser-dynamic": "^2.4.1", - "@angular/router": "^3.4.1", - "@webcomponents/custom-elements": "1.0.0-alpha.3", - "clarity-angular": "^0.8.0", - "clarity-icons": "^0.8.0", - "clarity-ui": "^0.8.0", - "core-js": "^2.4.1", - "mutationobserver-shim": "^0.3.2", - "rxjs": "^5.0.1", - "ts-helpers": "^1.1.1", - "web-animations-js": "^2.2.1", - "zone.js": "^0.7.2" - }, - "devDependencies": { - "@angular/compiler-cli": "^2.4.1", - "@types/core-js": "^0.9.34", - "@types/jasmine": "^2.2.30", - "@types/node": "^6.0.42", - "angular-cli": "^1.0.0-beta.24", - "bootstrap": "4.0.0-alpha.5", - "codelyzer": "~1.0.0-beta.3", - "enhanced-resolve": "^3.0.0", - "jasmine-core": "2.4.1", - "jasmine-spec-reporter": "2.5.0", - "karma": "1.2.0", - "karma-cli": "^1.0.1", - "karma-jasmine": "^1.0.2", - "karma-mocha-reporter": "^2.2.1", - "karma-phantomjs-launcher": "^1.0.0", - "karma-remap-istanbul": "^0.2.1", - "protractor": "4.0.9", - "ts-node": "1.2.1", - "tslint": "^4.1.1", - "typescript": "~2.0.3", - "typings": "^1.4.0", - "webdriver-manager": "10.2.5" - } -} + "name": "clarity-seed", + "version": "0.8.0", + "description": "Angular-CLI starter for a Clarity project", + "angular-cli": {}, + "scripts": { + "start": "ng serve --host 0.0.0.0 --proxy-config proxy.config.json", + "lint": "tslint \"src/**/*.ts\"", + "test": "ng test --single-run", + "pree2e": "webdriver-manager update", + "e2e": "protractor" + }, + "private": true, + "dependencies": { + "@angular/common": "^2.4.1", + "@angular/compiler": "^2.4.1", + "@angular/core": "^2.4.1", + "@angular/forms": "^2.4.1", + "@angular/http": "^2.4.1", + "@angular/platform-browser": "^2.4.1", + "@angular/platform-browser-dynamic": "^2.4.1", + "@angular/router": "^3.4.1", + "@webcomponents/custom-elements": "1.0.0-alpha.3", + "clarity-angular": "^0.8.0", + "clarity-icons": "^0.8.0", + "clarity-ui": "^0.8.0", + "core-js": "^2.4.1", + "mutationobserver-shim": "^0.3.2", + "rxjs": "^5.0.1", + "ts-helpers": "^1.1.1", + "web-animations-js": "^2.2.1", + "zone.js": "^0.7.2" + }, + "devDependencies": { + "@angular/compiler-cli": "^2.4.1", + "@types/core-js": "^0.9.34", + "@types/jasmine": "^2.2.30", + "@types/node": "^6.0.42", + "angular-cli": "^1.0.0-beta.24", + "bootstrap": "4.0.0-alpha.5", + "codelyzer": "~1.0.0-beta.3", + "enhanced-resolve": "^3.0.0", + "jasmine-core": "2.4.1", + "jasmine-spec-reporter": "2.5.0", + "karma": "1.2.0", + "karma-cli": "^1.0.1", + "karma-jasmine": "^1.0.2", + "karma-mocha-reporter": "^2.2.1", + "karma-phantomjs-launcher": "^1.0.0", + "karma-remap-istanbul": "^0.2.1", + "protractor": "4.0.9", + "ts-node": "1.2.1", + "tslint": "^4.1.1", + "typescript": "~2.0.3", + "typings": "^1.4.0", + "webdriver-manager": "10.2.5" + } +} \ No newline at end of file diff --git a/harbor-app/src/app/account/account.module.ts b/harbor-app/src/app/account/account.module.ts index f701c9753..9aa924a84 100644 --- a/harbor-app/src/app/account/account.module.ts +++ b/harbor-app/src/app/account/account.module.ts @@ -1,5 +1,5 @@ import { NgModule } from '@angular/core'; -import { SignInComponent } from './sign-in.component'; +import { SignInComponent } from './sign-in/sign-in.component'; import { SharedModule } from '../shared/shared.module'; import { RouterModule } from '@angular/router'; diff --git a/harbor-app/src/app/account/sign-in.component.html b/harbor-app/src/app/account/sign-in.component.html deleted file mode 100644 index b51046ab0..000000000 --- a/harbor-app/src/app/account/sign-in.component.html +++ /dev/null @@ -1,29 +0,0 @@ -
- -
- \ No newline at end of file diff --git a/harbor-app/src/app/account/sign-in.component.ts b/harbor-app/src/app/account/sign-in.component.ts deleted file mode 100644 index 0647801e7..000000000 --- a/harbor-app/src/app/account/sign-in.component.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Component } from '@angular/core'; -import { Router } from '@angular/router'; - -@Component({ - selector: 'sign-in', - templateUrl: "sign-in.component.html" -}) -export class SignInComponent { - // constructor(private router: Router){} -} \ No newline at end of file diff --git a/harbor-app/src/app/account/sign-in/sign-in-credential.ts b/harbor-app/src/app/account/sign-in/sign-in-credential.ts new file mode 100644 index 000000000..eb639416e --- /dev/null +++ b/harbor-app/src/app/account/sign-in/sign-in-credential.ts @@ -0,0 +1,15 @@ + +/** + * Declare class for store the sign in data, + * two prperties: + * principal: The username used to sign in + * password: The password used to sign in + * + * @export + * @class SignInCredential + */ + +export class SignInCredential { + principal: string; + password: string; +} \ No newline at end of file diff --git a/harbor-app/src/app/account/sign-in/sign-in.component.css b/harbor-app/src/app/account/sign-in/sign-in.component.css new file mode 100644 index 000000000..6004a33f6 --- /dev/null +++ b/harbor-app/src/app/account/sign-in/sign-in.component.css @@ -0,0 +1,7 @@ +.progress-size-small { + height: 0.5em !important; +} + +.visibility-hidden { + visibility: hidden; +} \ No newline at end of file diff --git a/harbor-app/src/app/account/sign-in/sign-in.component.html b/harbor-app/src/app/account/sign-in/sign-in.component.html new file mode 100644 index 000000000..d88f07c92 --- /dev/null +++ b/harbor-app/src/app/account/sign-in/sign-in.component.html @@ -0,0 +1,39 @@ +
+ +
\ No newline at end of file diff --git a/harbor-app/src/app/account/sign-in/sign-in.component.ts b/harbor-app/src/app/account/sign-in/sign-in.component.ts new file mode 100644 index 000000000..1b8a8617d --- /dev/null +++ b/harbor-app/src/app/account/sign-in/sign-in.component.ts @@ -0,0 +1,121 @@ +import { Component } from '@angular/core'; +import { Router } from '@angular/router'; +import { Input, ViewChild, AfterViewChecked } from '@angular/core'; +import { NgForm } from '@angular/forms'; + +import { SignInService } from './sign-in.service'; +import { SignInCredential } from './sign-in-credential' + +//Define status flags for signing in states +export const signInStatusNormal = 0; +export const signInStatusOnGoing = 1; +export const signInStatusError = -1; + +@Component({ + selector: 'sign-in', + templateUrl: "sign-in.component.html", + styleUrls: ['sign-in.component.css'], + + providers: [SignInService] +}) + +export class SignInComponent implements AfterViewChecked { + //Form reference + signInForm: NgForm; + @ViewChild('signInForm') currentForm: NgForm; + + //Status flag + signInStatus: number = 0; + + //Initialize sign in credential + @Input() signInCredential: SignInCredential = { + principal: "", + password: "" + }; + + constructor( + private signInService: SignInService, + private router: Router + ) { } + + //For template accessing + get statusError(): number { + return signInStatusError; + } + + get statusOnGoing(): number { + return signInStatusOnGoing; + } + + //Validate the related fields + private validate(): boolean { + return true; + //return this.signInForm.valid; + } + + //Hande form values changes + private formChanged() { + if (this.currentForm === this.signInForm) { + return; + } + this.signInForm = this.currentForm; + if (this.signInForm) { + this.signInForm.valueChanges + .subscribe(data => { + this.updateState(); + }); + } + + } + + //Implement interface + //Watch the view change only when view is in error state + ngAfterViewChecked() { + if (this.signInStatus === signInStatusError) { + this.formChanged(); + } + } + + //Update the status if we have done some changes + updateState(): void { + if (this.signInStatus === signInStatusError) { + this.signInStatus = signInStatusNormal; //reset + } + } + + //Trigger the signin action + signIn(): void { + //Should validate input firstly + if (!this.validate()) { + console.info("return"); + return; + } + + //Start signing in progress + this.signInStatus = signInStatusOnGoing; + + //Call the service to send out the http request + this.signInService.signIn(this.signInCredential) + .then(() => { + //Set status + this.signInStatus = signInStatusNormal; + + //Routing to the right location + let nextRoute = ["/harbor", "dashboard"]; + this.router.navigate(nextRoute); + }) + .catch(error => { + //Set error status + this.signInStatus = signInStatusError; + + let message = error.status ? error.status + ":" + error.statusText : error; + console.error("An error occurred when signing in:", message); + }); + } + + //Help user navigate to the sign up + signUp(): void { + let nextRoute = ["/harbor", "signup"]; + this.router.navigate(nextRoute); + } +} \ No newline at end of file diff --git a/harbor-app/src/app/account/sign-in/sign-in.service.ts b/harbor-app/src/app/account/sign-in/sign-in.service.ts new file mode 100644 index 000000000..c6a798451 --- /dev/null +++ b/harbor-app/src/app/account/sign-in/sign-in.service.ts @@ -0,0 +1,41 @@ +import { Injectable } from '@angular/core'; +import { Headers, Http, URLSearchParams } from '@angular/http'; +import 'rxjs/add/operator/toPromise'; + +import { SignInCredential } from './sign-in-credential'; + +const signInUrl = '/login'; +/** + * + * Define a service to provide sign in methods + * + * @export + * @class SignInService + */ +@Injectable() +export class SignInService { + private headers = new Headers({ + "Content-Type": 'application/x-www-form-urlencoded' + }); + + constructor(private http: Http) {} + + //Handle the related exceptions + private handleError(error: any): Promise{ + return Promise.reject(error.message || error); + } + + //Submit signin form to backend (NOT restful service) + signIn(signInCredential: SignInCredential): Promise{ + //Build the form package + const body = new URLSearchParams(); + body.set('principal', signInCredential.principal); + body.set('password', signInCredential.password); + + //Trigger Http + return this.http.post(signInUrl, body.toString(), { headers: this.headers }) + .toPromise() + .then(()=>null) + .catch(this.handleError); + } +} \ No newline at end of file diff --git a/harbor-app/src/app/account/sign-up.component.html b/harbor-app/src/app/account/sign-up.component.html index e69de29bb..fae4c1f44 100644 --- a/harbor-app/src/app/account/sign-up.component.html +++ b/harbor-app/src/app/account/sign-up.component.html @@ -0,0 +1 @@ +

Placeholder for signup

\ No newline at end of file diff --git a/harbor-app/src/app/harbor-routing.module.ts b/harbor-app/src/app/harbor-routing.module.ts index 4ed93c39e..8a6e95e96 100644 --- a/harbor-app/src/app/harbor-routing.module.ts +++ b/harbor-app/src/app/harbor-routing.module.ts @@ -2,7 +2,7 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; -import { SignInComponent } from './account/sign-in.component'; +import { SignInComponent } from './account/sign-in/sign-in.component'; const harborRoutes: Routes = [ { path: '', redirectTo: '/sign-in', pathMatch: 'full' },