Move homeserver input into LoginView

Signed-off-by: RMidhunSuresh <rmidhunsuresh@gmail.com>
This commit is contained in:
RMidhunSuresh 2021-08-18 13:05:05 +05:30
parent 13cb8979ac
commit 10a6aca477
6 changed files with 81 additions and 57 deletions

View file

@ -32,39 +32,51 @@ export class LoginViewModel extends ViewModel {
this._passwordLoginViewModel = null; this._passwordLoginViewModel = null;
this._startSSOLoginViewModel = null; this._startSSOLoginViewModel = null;
this._completeSSOLoginViewModel = null; this._completeSSOLoginViewModel = null;
this._start(); this._homeserver = null;
this._errorMessage = "";
this._start(this._defaultHomeServer);
} }
get passwordLoginViewModel() { return this._passwordLoginViewModel; } get passwordLoginViewModel() { return this._passwordLoginViewModel; }
get startSSOLoginViewModel() { return this._startSSOLoginViewModel; } get startSSOLoginViewModel() { return this._startSSOLoginViewModel; }
get completeSSOLoginViewModel(){ return this._completeSSOLoginViewModel; } get completeSSOLoginViewModel(){ return this._completeSSOLoginViewModel; }
get defaultHomeServer() { return this._defaultHomeServer; }
get errorMessage() { return this._errorMessage; }
async _start() { async _start(homeserver) {
if (this._loginToken) { if (this._loginToken) {
this._completeSSOLoginViewModel = this.track(new CompleteSSOLoginViewModel(this.childOptions({loginToken: this._loginToken}))); this._completeSSOLoginViewModel = this.track(new CompleteSSOLoginViewModel(this.childOptions({loginToken: this._loginToken})));
this.emitChange("completeSSOLoginViewModel"); this.emitChange("completeSSOLoginViewModel");
} }
else { else {
await this.queryLogin(this._defaultHomeServer); this._errorMessage = "";
this._showPasswordLogin(); await this.queryLogin(homeserver);
this._showSSOLogin(this._defaultHomeServer); if (this._loginOptions) {
if (this._loginOptions.sso) { this._showSSOLogin(); }
if (this._loginOptions.password) { this._showPasswordLogin(); }
if (!this._loginOptions.sso && !this._loginOptions.password) {
this._showError("This homeserver neither supports SSO nor Password based login flows");
}
}
else {
this._showError("Could not query login methods supported by the homeserver");
}
} }
} }
_showPasswordLogin() { _showPasswordLogin() {
this._passwordLoginViewModel = new PasswordLoginViewModel(this.childOptions({defaultHomeServer: this._defaultHomeServer})); this._passwordLoginViewModel = this.track(new PasswordLoginViewModel(this.childOptions()));
const observable = this._passwordLoginViewModel.homeserverObservable;
this.track(observable.subscribe(newHomeServer => this._onHomeServerChange(newHomeServer)));
this.emitChange("passwordLoginViewModel"); this.emitChange("passwordLoginViewModel");
} }
_showSSOLogin(homeserver) { _showSSOLogin() {
this._startSSOLoginViewModel = this.disposeTracked(this._ssoLoginViewModel); this._startSSOLoginViewModel = this.track(new StartSSOLoginViewModel(this.childOptions()));
this.emitChange("startSSOLoginViewModel"); this.emitChange("startSSOLoginViewModel");
if (this._loginOptions?.sso && !this._loginToken) { }
this._startSSOLoginViewModel = this.track(new StartSSOLoginViewModel(this.childOptions({homeserver})));
this.emitChange("startSSOLoginViewModel"); _showError(message) {
} this._errorMessage = message;
this.emitChange("errorMessage");
} }
async queryLogin(homeserver) { async queryLogin(homeserver) {
@ -73,16 +85,22 @@ export class LoginViewModel extends ViewModel {
} }
catch (e) { catch (e) {
this._loginOptions = null; this._loginOptions = null;
console.error("Could not query login methods supported by the homeserver");
} }
} }
async _onHomeServerChange(homeserver) { _disposeViewModels() {
await this.queryLogin(homeserver); this._startSSOLoginViewModel = this.disposeTracked(this._ssoLoginViewModel);
this._showSSOLogin(homeserver); this._passwordLoginViewModel = this.disposeTracked(this._passwordLoginViewModel);
this.emitChange("disposeViewModels");
} }
childOptions(options) { updateHomeServer(newHomeserver) {
this._homeserver = newHomeserver;
this._disposeViewModels();
this._start(newHomeserver);
}
childOptions(options = {}) {
return { return {
...super.childOptions(options), ...super.childOptions(options),
ready: sessionContainer => { ready: sessionContainer => {
@ -91,7 +109,8 @@ export class LoginViewModel extends ViewModel {
this._ready(sessionContainer); this._ready(sessionContainer);
}, },
sessionContainer: this._sessionContainer, sessionContainer: this._sessionContainer,
loginOptions: this._loginOptions loginOptions: this._loginOptions,
homeserver: this._homeserver ?? this._defaultHomeServer
} }
} }

View file

@ -16,30 +16,22 @@ limitations under the License.
import {ViewModel} from "../ViewModel.js"; import {ViewModel} from "../ViewModel.js";
import {SessionLoadViewModel} from "../SessionLoadViewModel.js"; import {SessionLoadViewModel} from "../SessionLoadViewModel.js";
import {ObservableValue} from "../../observable/ObservableValue.js";
export class PasswordLoginViewModel extends ViewModel { export class PasswordLoginViewModel extends ViewModel {
constructor(options) { constructor(options) {
super(options); super(options);
const {ready, defaultHomeServer, loginOptions, sessionContainer} = options; const {ready, loginOptions, sessionContainer, homeserver} = options;
this._ready = ready; this._ready = ready;
this._defaultHomeServer = defaultHomeServer;
this._sessionContainer = sessionContainer; this._sessionContainer = sessionContainer;
this._loadViewModel = null; this._loadViewModel = null;
this._loadViewModelSubscription = null; this._loadViewModelSubscription = null;
this._loginOptions = loginOptions; this._loginOptions = loginOptions;
this._homeserverObservable = new ObservableValue(this._defaultHomeServer); this._homeserver = homeserver;
} }
get defaultHomeServer() { return this._defaultHomeServer; }
get loadViewModel() {return this._loadViewModel; } get loadViewModel() {return this._loadViewModel; }
get homeserverObservable() { return this._homeserverObservable; }
get cancelUrl() { return this.urlCreator.urlForSegment("session"); } get cancelUrl() { return this.urlCreator.urlForSegment("session"); }
updateHomeServer(homeserver) {
this._homeserverObservable.set(homeserver);
}
get isBusy() { get isBusy() {
if (!this._loadViewModel) { if (!this._loadViewModel) {
return false; return false;
@ -48,7 +40,8 @@ export class PasswordLoginViewModel extends ViewModel {
} }
} }
async login(username, password, homeserver) { async login(username, password) {
const homeserver = this._homeserver;
if (!this._loginOptions.password) { if (!this._loginOptions.password) {
const path = this.navigation.pathFrom([this.navigation.segment("session")]); const path = this.navigation.pathFrom([this.navigation.segment("session")]);
this.navigation.applyPath(path); this.navigation.applyPath(path);

View file

@ -50,8 +50,8 @@ limitations under the License.
margin: 0 20px; margin: 0 20px;
} }
.LoginView { .PasswordLoginView {
padding: 0.4em; padding: 0 0.4em 0.4em;
} }
.SessionLoadStatusView { .SessionLoadStatusView {
@ -81,7 +81,7 @@ limitations under the License.
margin-top: 10px; margin-top: 10px;
} }
.StartSSOLoginView_separator { .LoginView_separator {
justify-content: center; justify-content: center;
display: flex; display: flex;
margin: 8px; margin: 8px;
@ -91,3 +91,11 @@ limitations under the License.
display: flex; display: flex;
justify-content: center; justify-content: center;
} }
.LoginView_sso {
padding: 0.4em 0.4em 0;
}
.LoginView_error {
padding: 0.4em
}

View file

@ -228,7 +228,7 @@ a.button-action {
border-radius: 8px; border-radius: 8px;
} }
.StartSSOLoginView_separator { .LoginView_separator {
font-weight: 500; font-weight: 500;
font-size: 1.5rem; font-size: 1.5rem;
} }

View file

@ -20,12 +20,25 @@ import {PasswordLoginView} from "./PasswordLoginView.js";
import {CompleteSSOView} from "./CompleteSSOView.js"; import {CompleteSSOView} from "./CompleteSSOView.js";
export class LoginView extends TemplateView { export class LoginView extends TemplateView {
render(t) { render(t, vm) {
return t.div({ className: "PreSessionScreen" }, [ const homeserver = t.input({
t.div({ className: "logo" }), id: "homeserver",
t.mapView(vm => vm.completeSSOLoginViewModel, vm => vm? new CompleteSSOView(vm): null), type: "text",
t.mapView(vm => vm.passwordLoginViewModel, vm => vm? new PasswordLoginView(vm): null), placeholder: vm.i18n`Your matrix homeserver`,
t.mapView(vm => vm.startSSOLoginViewModel, vm => vm? new StartSSOLoginView(vm): null), value: vm.defaultHomeServer,
onChange: () => vm.updateHomeServer(homeserver.value),
});
return t.div({className: "PreSessionScreen"}, [
t.div({className: "logo"}),
t.h1([vm.i18n`Sign In`]),
t.mapView(vm => vm.completeSSOLoginViewModel, vm => vm ? new CompleteSSOView(vm) : null),
t.if(vm => !vm.completeSSOLoginViewModel,
(t, vm) => t.div({ className: "LoginView_sso form form-row" }, [t.label({ for: "homeserver" }, vm.i18n`Homeserver`), homeserver])),
t.mapView(vm => vm.passwordLoginViewModel, vm => vm ? new PasswordLoginView(vm): null),
t.if(vm => vm.passwordLoginViewModel && vm.startSSOLoginViewModel, t => t.p({className: "LoginView_separator"}, vm.i18n`or`)),
t.mapView(vm => vm.startSSOLoginViewModel, vm => vm ? new StartSSOLoginView(vm) : null),
t.if(vm => vm.errorMessage, (t, vm) => t.h5({className: "LoginView_error"}, vm.i18n(vm.errorMessage))),
// use t.mapView rather than t.if to create a new view when the view model changes too // use t.mapView rather than t.if to create a new view when the view model changes too
t.p(hydrogenGithubLink(t)) t.p(hydrogenGithubLink(t))
]); ]);
@ -35,10 +48,11 @@ export class LoginView extends TemplateView {
class StartSSOLoginView extends TemplateView { class StartSSOLoginView extends TemplateView {
render(t, vm) { render(t, vm) {
return t.div({ className: "StartSSOLoginView" }, return t.div({ className: "StartSSOLoginView" },
[ t.button({
t.p({ className: "StartSSOLoginView_separator" }, "or"), className: "StartSSOLoginView_button button-action secondary",
t.button({ className: "StartSSOLoginView_button button-action secondary", type: "button", onClick: () => vm.startSSOLogin() }, "Log in with SSO") type: "button",
] onClick: () => vm.startSSOLogin()
}, vm.i18n`Log in with SSO`)
); );
} }
} }

View file

@ -32,27 +32,17 @@ export class PasswordLoginView extends TemplateView {
placeholder: vm.i18n`Password`, placeholder: vm.i18n`Password`,
disabled disabled
}); });
const homeserver = t.input({
id: "homeserver",
type: "text",
placeholder: vm.i18n`Your matrix homeserver`,
value: vm.defaultHomeServer,
onChange: () => vm.updateHomeServer(homeserver.value),
disabled
});
return t.div({className: "LoginView form"}, [ return t.div({className: "PasswordLoginView form"}, [
t.h1([vm.i18n`Sign In`]),
t.if(vm => vm.error, t => t.div({ className: "error" }, vm => vm.error)), t.if(vm => vm.error, t => t.div({ className: "error" }, vm => vm.error)),
t.form({ t.form({
onSubmit: evnt => { onSubmit: evnt => {
evnt.preventDefault(); evnt.preventDefault();
vm.login(username.value, password.value, homeserver.value); vm.login(username.value, password.value);
} }
}, [ }, [
t.div({ className: "form-row" }, [t.label({ for: "username" }, vm.i18n`Username`), username]), t.div({ className: "form-row" }, [t.label({ for: "username" }, vm.i18n`Username`), username]),
t.div({ className: "form-row" }, [t.label({ for: "password" }, vm.i18n`Password`), password]), t.div({ className: "form-row" }, [t.label({ for: "password" }, vm.i18n`Password`), password]),
t.div({ className: "form-row" }, [t.label({ for: "homeserver" }, vm.i18n`Homeserver`), homeserver]),
t.mapView(vm => vm.loadViewModel, loadViewModel => loadViewModel ? new SessionLoadStatusView(loadViewModel) : null), t.mapView(vm => vm.loadViewModel, loadViewModel => loadViewModel ? new SessionLoadStatusView(loadViewModel) : null),
t.div({ className: "button-row" }, [ t.div({ className: "button-row" }, [
t.a({ t.a({