Commit d155ddb7 authored by David Burke's avatar David Burke

Added login style server select to reset password page

parent 75c6e468
Pipeline #36135175 failed with stage
in 6 minutes and 42 seconds
import { tap, withLatestFrom, map, exhaustMap } from "rxjs/operators";
import { of as observableOf } from "rxjs";
import {
tap,
withLatestFrom,
map,
exhaustMap,
catchError
} from "rxjs/operators";
import { of as observableOf, of, from } from "rxjs";
import { Injectable } from "@angular/core";
import { Router } from "@angular/router";
......@@ -35,20 +41,22 @@ export class LoginEffects {
map(([action, form]) => form.value),
exhaustMap(auth => {
const callLogin = () => {
return this.userService
.login(
return from(
this.userService.login(
auth.email,
auth.password,
auth.rememberMe ? auth.rememberMe : false
)
.then(resp => new LoginSuccessAction(resp))
.catch(err => new LoginFailureAction(err));
).pipe(
map(resp => new LoginSuccessAction(resp)),
catchError(err => of(new LoginFailureAction(err)))
);
};
const callCheckAndSetUrl = (url: string) => {
return this.userService
.checkAndSetUrl(url)
.then(() => callLogin())
.catch(err => new LoginFailureAction(err));
return this.userService.checkAndSetUrl(url).pipe(
exhaustMap(() => callLogin()),
catchError(err => of(new LoginFailureAction(err)))
);
};
if (auth.url) {
......
......@@ -44,6 +44,7 @@ import { PasswordInputComponent } from "./change-password/password-input/passwor
import { SetPasswordComponent } from "./reset-password/set-password/set-password.component";
import { SetPasswordContainer } from "./reset-password/set-password/set-password.container";
import { SetPasswordEffects } from "./reset-password/set-password/set-password.effects";
import { ServerSelectComponent } from "./shared/server-select.component";
export const COMPONENTS = [
AccountComponent,
......@@ -67,7 +68,8 @@ export const COMPONENTS = [
ResetPasswordVerifyContainer,
SetPasswordComponent,
SetPasswordContainer,
MarketingFrameComponent
MarketingFrameComponent,
ServerSelectComponent
];
export const SERVICES = [UserService, ConfirmEmailGuard];
......
......@@ -57,39 +57,15 @@
[control]="form.controls.rememberMe"
tabindex="4"
></app-checkbox>
</div>
<div *ngIf="isExtension">
<app-checkbox
title="My company has its own Passit server"
subtext="If you signed up for Passit anywhere other than app.passit.io (e.g. passit.mycompany.com, or your self-hosted server), you’ll need to specify where you want to log&nbsp;in."
[control]="form.controls.showUrl"
tabindex="5"
></app-checkbox>
<div *ngIf="form.value.showUrl" class="form-field form-field--large">
<label [for]="form.controls.url.id" class="form-field__label">Server URL</label>
<input
type="url"
[ngrxFormControlState]="form.controls.url"
class="form-field__input"
[class.form-field__input--invalid]="form.errors._url"
[class.form-field__input--one-action]="form.controls.url.isValidationPending"
tabindex="6"
>
<div class="form-field__actions" *ngIf="form.controls.url.isValidationPending">
<progress-indicator
[inProgress]="form.controls.url.isValidationPending"
[inputAction]="true"></progress-indicator>
</div>
</div>
<ul class="form-field__error-list">
<li *ngIf="form.errors._url?.$exists" class="form-field__error">
Cannot connect to {{ form.errors._url?.$exists }}
</li>
</ul>
</div>
<app-server-select
*ngIf="isExtension"
[showUrlControl]="form.controls.showUrl"
[urlControl]="form.controls.url"
[formErrors]="form.errors"
></app-server-select>
<div class="auth-form__actions">
<button
id="loginSubmit"
......@@ -104,7 +80,8 @@
[inProgress]="hasLoginStarted"
inProgressText="Logging In"
[completed]="hasLoginFinished"
completedText="Logged In"></progress-indicator>
completedText="Logged In"
></progress-indicator>
</div>
</form>
......
......@@ -16,13 +16,20 @@ import { FormGroupState } from "ngrx-forms";
changeDetection: ChangeDetectionStrategy.OnPush
})
export class LoginComponent {
@Input() form: FormGroupState<ILoginForm>;
@Input() errorMessage: string;
@Input() hasLoginStarted: boolean;
@Input() hasLoginFinished: boolean;
@Input() isPopup: boolean;
@Output() login = new EventEmitter();
@Output() goToRegister = new EventEmitter();
@Input()
form: FormGroupState<ILoginForm>;
@Input()
errorMessage: string;
@Input()
hasLoginStarted: boolean;
@Input()
hasLoginFinished: boolean;
@Input()
isPopup: boolean;
@Output()
login = new EventEmitter();
@Output()
goToRegister = new EventEmitter();
isExtension = IS_EXTENSION;
constructor() {}
......
......@@ -14,6 +14,7 @@ import * as fromRoot from "../../app.reducers";
import { RouterTestingModule } from "@angular/router/testing";
import { SharedModule } from "../../shared";
import { MarketingFrameComponent } from "../marketing-frame/marketing-frame.component";
import { ServerSelectComponent } from "../shared/server-select.component";
describe("LoginComponent", () => {
let component: LoginContainer;
......@@ -25,6 +26,7 @@ describe("LoginComponent", () => {
ProgressIndicatorComponent,
LoginContainer,
LoginComponent,
ServerSelectComponent,
MarketingFrameComponent
],
imports: [
......
import { map, exhaustMap, filter, tap, withLatestFrom } from "rxjs/operators";
import {
map,
exhaustMap,
filter,
tap,
withLatestFrom,
catchError
} from "rxjs/operators";
import "rxjs/add/operator/do";
import "rxjs/add/operator/exhaustMap";
import "rxjs/add/operator/map";
......@@ -30,6 +37,7 @@ import { MoonMail } from "../moonmail/moonmail.service";
import { Store } from "@ngrx/store";
import { IState } from "../../app.reducers";
import { IPassitSDKError } from "../../ngsdk";
import { of } from "rxjs";
@Injectable()
export class RegisterEffects {
......@@ -69,14 +77,10 @@ export class RegisterEffects {
withLatestFrom(this.store.select(fromAccount.getUrlForm)),
map(([action, form]) => form),
exhaustMap(form => {
return this.userService
.checkAndSetUrl(form.value.url)
.then(() => {
return new CheckUrlSuccessAction();
})
.catch(() => {
return new CheckUrlFailureAction();
});
return this.userService.checkAndSetUrl(form.value.url).pipe(
map(() => new CheckUrlSuccessAction()),
catchError(() => of(new CheckUrlFailureAction()))
);
})
);
......
......@@ -33,24 +33,12 @@
</div>
<div *ngIf="!hasFinished">
<div *ngIf="isExtension">
<app-checkbox title="My company has its own Passit server" subtext="If you signed up for Passit anywhere other than app.passit.io (e.g. passit.mycompany.com, or your self-hosted server), you’ll need to specify where you want to log&nbsp;in."
[control]="form.controls.showUrl"></app-checkbox>
<div *ngIf="form.value.showUrl" class="form-field form-field--large">
<label [for]="form.controls.url.id" class="form-field__label">Server URL</label>
<input type="url" [ngrxFormControlState]="form.controls.url" class="form-field__input"
[class.form-field__input--invalid]="form.errors._url" [class.form-field__input--one-action]="form.controls.url.isValidationPending">
<div class="form-field__actions" *ngIf="form.controls.url.isValidationPending">
<progress-indicator [inProgress]="form.controls.url.isValidationPending" [inputAction]="true"></progress-indicator>
</div>
</div>
<ul class="form-field__error-list">
<li *ngIf="form.errors._url?.$exists" class="form-field__error">
Cannot connect to {{ form.errors._url?.$exists }}
</li>
</ul>
</div>
<app-server-select
*ngIf="isExtension"
[showUrlControl]="form.controls.showUrl"
[urlControl]="form.controls.url"
[formErrors]="form.errors"
></app-server-select>
</div>
<div *ngIf="!hasFinished" class="auth-form__actions">
......
......@@ -6,12 +6,25 @@ import {
SubmitFormSuccess,
SubmitFormFailure
} from "./reset-password.actions";
import { withLatestFrom, map, exhaustMap, catchError } from "rxjs/operators";
import {
withLatestFrom,
map,
exhaustMap,
catchError,
filter,
distinctUntilChanged,
switchMap
} from "rxjs/operators";
import { Store } from "@ngrx/store";
import { IState } from "../../app.reducers";
import { getResetPasswordForm } from "../account.reducer";
import { UserService } from "../user";
import { of } from "rxjs";
import { of, concat, timer } from "rxjs";
import {
StartAsyncValidationAction,
ClearAsyncErrorAction,
SetAsyncErrorAction
} from "ngrx-forms";
@Injectable()
export class ResetPasswordEffects {
......@@ -29,7 +42,7 @@ export class ResetPasswordEffects {
);
};
const callCheckAndSetUrl = (url: string) => {
return of(this.userService.checkAndSetUrl(url)).pipe(
return this.userService.checkAndSetUrl(url).pipe(
exhaustMap(() => callForgotPassword()),
catchError(err => of(new SubmitFormFailure()))
);
......@@ -43,6 +56,33 @@ export class ResetPasswordEffects {
})
);
@Effect()
asyncServerUrlCheck$ = this.store.select(getResetPasswordForm).pipe(
filter(form => form.value.showUrl),
distinctUntilChanged(
(first, second) => first.value.url === second.value.url
),
switchMap(form =>
concat(
timer(300).pipe(
map(
() => new StartAsyncValidationAction(form.controls.url.id, "exists")
)
),
this.userService.checkUrl(form.value.url).pipe(
map(() => new ClearAsyncErrorAction(form.controls.url.id, "exists")),
catchError(() => [
new SetAsyncErrorAction(
form.controls.url.id,
"exists",
form.value.url
)
])
)
)
)
);
constructor(
private actions$: Actions,
private store: Store<IState>,
......
import { Component, ChangeDetectionStrategy, Input } from "@angular/core";
import { AbstractControlState, ValidationErrors } from "ngrx-forms";
@Component({
selector: "app-server-select",
template: `
<app-checkbox
title="My company has its own Passit server"
subtext="If you signed up for Passit anywhere other than app.passit.io (e.g. passit.mycompany.com, or your self-hosted server), you’ll need to specify where you want to log&nbsp;in."
[control]="showUrlControl"
tabindex="5"
></app-checkbox>
<div *ngIf="showUrlControl.value" class="form-field form-field--large">
<label [for]="urlControl.id" class="form-field__label">Server URL</label>
<input
type="url"
[ngrxFormControlState]="urlControl"
class="form-field__input"
[class.form-field__input--invalid]="formErrors._url"
[class.form-field__input--one-action]="urlControl.isValidationPending"
tabindex="6"
>
<div class="form-field__actions" *ngIf="urlControl.isValidationPending">
<progress-indicator
[inProgress]="urlControl.isValidationPending"
[inputAction]="true"></progress-indicator>
</div>
</div>
<ul class="form-field__error-list">
<li *ngIf="formErrors._url?.$exists" class="form-field__error">
Cannot connect to {{ formErrors._url?.$exists }}
</li>
</ul>
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ServerSelectComponent {
@Input()
showUrlControl: AbstractControlState<boolean>;
@Input()
urlControl: AbstractControlState<string>;
@Input()
formErrors: ValidationErrors;
constructor() {}
}
......@@ -53,7 +53,7 @@ describe("Service: UserService", () => {
// url: correctUrl,
// });
const url = "passit.io"; // The service should prefix https and api
service.checkAndSetUrl(url).then(() => {
service.checkAndSetUrl(url).subscribe(() => {
store.select(getUrl).subscribe(storeUrl => {
expect(storeUrl).toBe(correctUrl);
});
......
import { take, mergeMap } from "rxjs/operators";
import { take, mergeMap, catchError } from "rxjs/operators";
import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Store } from "@ngrx/store";
......@@ -71,25 +71,23 @@ export class UserService {
if (url === "api:8000/api/" || url === "localhost:8000/api/") {
apiUrl = "http://" + url;
}
return this.http
.get(apiUrl + "ping/")
.toPromise()
.then(() => {
return this.http.get(apiUrl + "ping/").pipe(
mergeMap(() => {
this.setSdkUrl(apiUrl);
return apiUrl;
})
.catch(() => {
}),
catchError(() => {
// Try api.domain (legacy recommendation)
// Force https only
url = "https://api." + url;
return this.http
.get(url + "ping/")
.toPromise()
.then(() => {
return this.http.get(url + "ping/").pipe(
mergeMap(() => {
this.setSdkUrl(url);
return url;
});
});
})
);
})
);
}
/** Check url to see if there is a passit server there and return resulting observable */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment