Skip to content

Commit

Permalink
tuning: login and setup-wizard
Browse files Browse the repository at this point in the history
  • Loading branch information
bwp91 committed Oct 2, 2024
1 parent b2b83b3 commit d6d29a0
Show file tree
Hide file tree
Showing 42 changed files with 350 additions and 293 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ All notable changes to `homebridge-config-ui-x` will be documented in this file.
### UI Changes

- switch from a top menu to a sidebar menu
- tuning: `login` and `setup-wizard`

### Other Changes

Expand Down
2 changes: 1 addition & 1 deletion src/core/config/config.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ export class ConfigService {
recommendChildBridges: this.recommendChildBridges,
},
formAuth: Boolean(this.ui.auth !== 'none'),
theme: this.ui.theme || 'orange',
theme: this.ui.theme || 'purple',
lightingMode: this.ui.lightingMode || 'auto',
serverTimestamp: new Date().toISOString(),
}
Expand Down
2 changes: 1 addition & 1 deletion ui/src/app/core/settings.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export class SettingsService {
setTheme(theme: string) {
// Default theme is orange
if (!theme || !this.themeList.includes(theme)) {
theme = 'orange'
theme = 'purple'
}

// Grab the body element
Expand Down
50 changes: 24 additions & 26 deletions ui/src/app/modules/login/login.component.html
Original file line number Diff line number Diff line change
@@ -1,46 +1,44 @@
<div class="login-container d-flex align-items-center justify-content-center"
[ngStyle]="{'background': backgroundStyle}">
<div class="card card-body mx-2 login-card">
<img class="homebridge-logo mx-auto my-3" src="/assets/homebridge-color-round.svg" alt="Homebridge Logo">
<form novalidate (ngSubmit)="onSubmit()" [formGroup]="form">
<p class="h4 text-center mb-4">Homebridge</p>

<h3 class="mb-4 text-center">{{ 'setup_wizard.welcome_to_homebridge' | translate }}</h3>
<div *ngIf="!twoFactorCodeRequired">
<div class="md-form">
<i class="fas fa-fw fa-user prefix grey-text"></i>
<div class="input-group mb-4">
<span class="input-group-text custom-input"><i class="fas fa-fw fa-user primary-text fa-lg"></i></span>
<input #username formControlName="username" type="text" id="form-username" autofocus autocomplete="username"
autocapitalize="none" tabindex="1" class="form-control px-0" [ngClass]="{
autocapitalize="none" tabindex="1" class="form-control custom-input" [ngClass]="{
'is-invalid': form.controls.username.dirty && form.controls.username.errors
}">
<label for="form-username">{{ 'login.label_username' | translate }}</label>
}" placeholder="{{ 'login.label_username' | translate }}" required>
</div>
<div class="md-form">
<i class="fas fa-fw fa-lock prefix grey-text"></i>
<div class="input-group mb-4">
<span class="input-group-text custom-input"><i class="fas fa-fw fa-lock primary-text fa-lg"></i></span>
<input #password formControlName="password" type="password" id="form-pass" autocomplete="current-password"
tabindex="2" class="form-control px-0" [ngClass]="{
tabindex="2" class="form-control custom-input" [ngClass]="{
'is-invalid': form.controls.password.dirty && form.controls.password.errors
}">
<label for="form-pass">{{ 'login.label_password' | translate }}</label>
}" placeholder="{{ 'login.label_password' | translate }}" required>
</div>
</div>

<div *ngIf="twoFactorCodeRequired">
<p class="text-center">{{ 'users.setup_2fa_enter_code' | translate }}</p>
<div class="md-form">
<i class="fas fa-fw fa-key prefix grey-text"></i>
<input #otp formControlName="otp" type="text" id="form-ota" autocomplete="one-time-code" autocapitalize="none"
inputmode="numeric" pattern="[0-9]*" tabindex="1" class="form-control px-0" [ngClass]="{
'is-invalid': form.controls.otp.dirty && form.controls.otp.errors
}">
<label for="form-ota">{{ 'login.label_2fa_code' | translate }}</label>
<div class="input-group mb-4">
<span class="input-group-text custom-input"><i class="fas fa-fw fa-key primary-text fa-lg"></i></span>
<input #otp formControlName="otp" type="text" id="form-ota" autofocus autocomplete="one-time-code"
autocapitalize="none" inputmode="numeric" pattern="[0-9]*" tabindex="1" class="form-control custom-input"
placeholder="{{ 'login.label_2fa_code' | translate }}">
</div>
</div>

<div class="alert alert-error p-2 mb-4" role="alert" *ngIf="invalidCredentials">
<small>{{ 'login.message_invalid_username_or_password' | translate }}</small>
</div>
<div class="alert alert-error p-2 mb-4" role="alert" *ngIf="invalid2faCode">
<small>{{ 'login.message_invalid_2fa_code' | translate }}</small>
</div>
<div class="text-center">
<p class="red-text" *ngIf="invalidCredentials"><small>{{ 'login.message_invalid_username_or_password' | translate }}</small></p>
<p class="red-text" *ngIf="invalid2faCode"><small>{{ 'login.message_invalid_2fa_code' | translate }}</small></p>
<button tabindex="3" class="btn btn-primary" type="submit" [disabled]="form.invalid">{{ 'login.button_login' | translate }}</button>
<button tabindex="3" class="btn btn-primary mb-4" type="submit" [disabled]="form.invalid">
{{ 'login.button_login' | translate }}
</button>
</div>

</form>
</div>
</div>
15 changes: 13 additions & 2 deletions ui/src/app/modules/login/login.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
* https://www.pexels.com/photo/architecture-bridge-building-city-220769/
*/

.homebridge-logo {
height: 125px;
padding-bottom: 10px;
}

.login-container {
background-color: #f4f4f4;
background-size: cover;
Expand All @@ -15,8 +20,9 @@
}

.login-card {
max-width: 500px;
max-width: 550px;
background-color: rgba(255, 255, 255, 0.90);
border-radius: 1rem;

.form-control:focus {
background-color: inherit !important;
Expand Down Expand Up @@ -45,4 +51,9 @@
@media screen and (max-height: 450px){
display: none;
}
}
}

.btn-primary {
background-color: #4a266c !important;
border-color: #4a266c !important;
}
10 changes: 5 additions & 5 deletions ui/src/app/modules/login/login.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,12 @@ export class LoginComponent implements OnInit {
}
}

await this.$auth.login(this.form.getRawValue()).then(() => {
try {
await this.$auth.login(this.form.getRawValue())
this.$router.navigateByUrl(this.targetRoute)
window.sessionStorage.removeItem('target_route')
}).catch((err) => {
if (err.status === 412) {
} catch (error) {
if (error.status === 412) {
if (!this.form.controls.otp) {
this.form.addControl('otp', new FormControl('', [
Validators.required,
Expand All @@ -110,8 +111,7 @@ export class LoginComponent implements OnInit {
} else {
this.invalidCredentials = true
}
})

}
this.inProgress = false
}
}
2 changes: 1 addition & 1 deletion ui/src/app/modules/settings/restore/restore.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ <h5 class="modal-title">{{ 'backup.title_restore' | translate }}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" [attr.aria-label]="'form.button_close' | translate"
(click)="$activeModal.dismiss('Dismiss')"></button>
</div>
<div class="modal-body" *ngIf="!restoreStarted && !setupWizardRestore">
<div class="modal-body" *ngIf="!restoreStarted">
<div class="text-center mt-2 mb-3">
<i class="fas fa-fw fa-hard-drive primary-text" style="font-size: 75px;"></i>
</div>
Expand Down
13 changes: 1 addition & 12 deletions ui/src/app/modules/settings/restore/restore.component.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ApiService } from '@/app/core/api.service'
import { IoNamespace, WsService } from '@/app/core/ws.service'
import { HttpEventType, HttpResponse } from '@angular/common/http'
import { Component, Input, OnDestroy, OnInit } from '@angular/core'
import { Component, OnDestroy, OnInit } from '@angular/core'
import { Router } from '@angular/router'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { TranslateService } from '@ngx-translate/core'
Expand All @@ -13,8 +13,6 @@ import { FitAddon } from 'xterm-addon-fit'
templateUrl: './restore.component.html',
})
export class RestoreComponent implements OnInit, OnDestroy {
@Input() setupWizardRestore = false

public clicked = false
public maxFileSizeText = globalThis.backup.maxBackupSizeText
public selectedFile: File
Expand Down Expand Up @@ -48,12 +46,6 @@ export class RestoreComponent implements OnInit, OnDestroy {
this.io.socket.on('stdout', (data) => {
this.term.write(data)
})

if (this.setupWizardRestore) {
this.restoreStarted = true
this.restoreInProgress = true
this.startRestore()
}
}

onRestoreBackupClick() {
Expand Down Expand Up @@ -91,9 +83,6 @@ export class RestoreComponent implements OnInit, OnDestroy {
next: () => {
this.restoreInProgress = false
this.$toastr.success(this.$translate.instant('backup.backup_restored'), this.$translate.instant('toast.title_success'))
if (this.setupWizardRestore) {
this.postBackupRestart()
}
},
error: (error) => {
this.restoreFailed = true
Expand Down
102 changes: 48 additions & 54 deletions ui/src/app/modules/setup-wizard/setup-wizard.component.html
Original file line number Diff line number Diff line change
@@ -1,102 +1,96 @@
<div class="setup-container d-flex align-items-center justify-content-center">
<div class="w-100 setup-card d-flex py-5">
<div class="w-100 setup-card d-flex py-4 flex-column">
<img class="homebridge-logo mx-auto" src="/assets/homebridge-color-round.svg" alt="Homebridge Logo">
<div class="progress w-100 my-4">
<div class="progress-bar progress-bar-striped bg-success" role="progressbar" [style.width]="progress + '%'"
[attr.aria-valuenow]="progress" aria-valuemin="0" aria-valuemax="100" [ngClass]="{
'progress-bar-animated': loading || restoreUploading
}"></div>
</div>
<div *ngIf="step === 'welcome'" class="w-100 d-flex flex-column align-items-center">
<img class="homebridge-logo mx-auto" src="/assets/homebridge-color-round.svg" alt="hb logo">
<h3 class="pt-4 pb-3 text-center">{{ 'setup_wizard.welcome_to_homebridge' | translate }}</h3>
<button type="button" class="btn btn-lg btn-primary" (click)="onClickGettingStarted()">
<h3 class="mb-4 text-center">{{ 'setup_wizard.welcome_to_homebridge' | translate }}</h3>
<button type="button" class="btn btn-lg btn-primary mb-3" (click)="onClickGettingStarted()">
{{ 'setup_wizard.button_get_started' | translate }}
</button>
<small class="mt-3">
<a href="javascript:void(0)" class="grey-text" (click)="onClickRestoreBackup()">{{ 'setup_wizard_message_restore' | translate }}</a>
</small>
<a href="javascript:void(0)" class="grey-text" (click)="onClickRestoreBackup()">{{ 'setup_wizard_message_restore' | translate }}</a>
</div>

<div *ngIf="step === 'create-account'" class="w-100 d-flex flex-column align-items-center">
<img class="homebridge-logo homebridge-logo-small mx-auto" src="/assets/homebridge-color-round.svg" alt="hb logo">
<h3 class="pt-4 pb-3 text-center">{{ 'setup_wizard.create_account' | translate }}</h3>

<h3 class="mb-3 text-center">{{ 'setup_wizard.create_account' | translate }}</h3>
<div class="w-100">
<p>{{ 'setup_wizard.create_account_reason' | translate }}</p>
<p class="text-center">{{ 'setup_wizard.create_account_reason' | translate }}</p>
<form novalidate (ngSubmit)="createFirstUser()" [formGroup]="createUserForm">
<div class="md-form">
<i class="fas fa-fw fa-user prefix grey-text"></i>
<div class="input-group mb-4">
<span class="input-group-text custom-input"><i class="fas fa-fw fa-user primary-text fa-lg"></i></span>
<input formControlName="username" type="text" id="form-username" autocomplete="username"
autocapitalize="none" tabindex="1" class="form-control px-0" [readonly]="loading" [ngClass]="{
autocapitalize="none" tabindex="1" class="form-control custom-input" [readonly]="loading" [ngClass]="{
'is-valid': (createUserForm.controls.username.dirty) && createUserForm.controls.username.valid,
'is-invalid': (createUserForm.controls.username.dirty) && createUserForm.controls.username.invalid
}">
<label for="form-username">{{ 'users.label_username' | translate }}</label>
}" placeholder="{{ 'login.label_username' | translate }}" required>
</div>

<div class="md-form">
<i class="fas fa-fw fa-lock prefix grey-text"></i>
<div class="input-group mb-4">
<span class="input-group-text custom-input"><i class="fas fa-fw fa-lock fa-lg"></i></span>
<input formControlName="password" type="password" id="form-pass" autocomplete="new-password" tabindex="2"
class="form-control px-0" [readonly]="loading" [ngClass]="{
class="form-control custom-input" [readonly]="loading" [ngClass]="{
'is-valid': (createUserForm.controls.password.dirty) && createUserForm.controls.password.valid,
'is-invalid': (createUserForm.controls.password.dirty) && createUserForm.controls.password.errors
}">
<label for="form-pass">{{ 'users.label_password' | translate }}</label>
}" placeholder="{{ 'login.label_password' | translate }}" required>
</div>

<div class="md-form">
<i class="fas fa-fw fa-lock prefix grey-text"></i>
<div class="input-group mb-4">
<span class="input-group-text custom-input"><i class="fas fa-fw fa-lock fa-lg"></i></span>
<input formControlName="passwordConfirm" type="password" id="form-pass-confirm" autocomplete="new-password"
tabindex="2" class="form-control px-0" [readonly]="loading" [ngClass]="{
tabindex="2" class="form-control custom-input" [readonly]="loading" [ngClass]="{
'is-valid': (createUserForm.controls.passwordConfirm.dirty) && createUserForm.controls.passwordConfirm.valid,
'is-invalid': (createUserForm.controls.passwordConfirm.dirty) && createUserForm.controls.passwordConfirm.errors
}">
<label for="form-pass-confirm">{{ 'users.label_confirm_password' | translate }}</label>
}" placeholder="{{ 'users.label_confirm_password' | translate }}" required>
</div>

<div class="w-100 text-center">
<div class="mt-3 w-100 d-flex justify-content-between">
<button type="button" class="btn btn-elegant ms-0" [disabled]="restoreUploading" (click)="onClickCancelRestore()">
{{ 'form.button_back' | translate }}
</button>
<button type="submit" class="btn btn-primary" [disabled]="createUserForm.invalid || loading" [ngClass]="{
'button-loading': loading
}">
{{ 'setup_wizard.create_account' | translate }}
{{ 'form.button_continue' | translate }}
<i class="button-loading-overlay fas fa-fw fa-spinner fa-pulse"></i>
</button>
</div>
</form>
</div>
</div>

<div *ngIf="step === 'restore-backup'" class="w-100 d-flex flex-column align-items-center">
<img class="homebridge-logo homebridge-logo-small mx-auto" src="/assets/homebridge-color-round.svg" alt="hb logo">
<h3 class="pt-4 pb-3 text-center">{{ 'backup.title_restore' | translate }}</h3>
<p>{{ 'backup.restore_help_one' | translate }}</p>

<input type="file" class="form-control" id="restoreFileUpload" accept="application/gzip, .gz"
<h3 class="mb-3 text-center">{{ 'setup_wizard_message_restore' | translate }}</h3>
<p class="text-center mb-4">{{ 'backup.restore_help_one' | translate }}</p>
<input type="file" class="form-control custom-input mb-3" id="restoreFileUpload" accept="application/gzip, .gz"
(change)="handleRestoreFileInput($event.target.files)">

<div class="mt-3 w-100 d-flex justify-content-between">
<button type="button" class="btn btn-elegant ms-0" [disabled]="restoreUploadStarted" (click)="onClickCancelRestore()">
{{ 'form.button_cancel' | translate }}
<button type="button" class="btn btn-elegant ms-0" [disabled]="restoreUploading" (click)="onClickCancelRestore()">
{{ 'form.button_back' | translate }}
</button>

<button type="button" class="btn btn-primary me-0" (click)="onRestoreBackupClick()"
[disabled]="restoreUploading || !selectedFile">
<span *ngIf="restoreUploading">
<i class="fas fa-fw fa-spinner fa-pulse"></i>
{{ 'backup.label_uploading' | translate }}
</span>
<span *ngIf="!restoreUploading">{{ 'backup.button_restore_backup' | translate }}</span>
<span *ngIf="!restoreUploading">{{ 'form.button_continue' | translate }}</span>
</button>
</div>
</div>

<div *ngIf="step === 'restoring'" class="w-100 d-flex flex-column align-items-center">
<h3 class="mb-3 text-center">{{ 'setup_wizard_message_restoring' | translate }}</h3>
</div>
<div *ngIf="step === 'restarting'" class="w-100 d-flex flex-column align-items-center">
<img class="homebridge-logo homebridge-logo-small mx-auto" src="/assets/homebridge-color-round.svg" alt="hb logo">
<h3 class="pt-4 pb-3 text-center">{{ 'restart.title_restart' | translate }}</h3>
<h1>
<i class="fas fa-fw fa-spinner fa-pulse"></i>
</h1>
<h3 class="mb-3 text-center">{{ 'restart.title_restart' | translate }}</h3>
</div>

<div *ngIf="step === 'setup-complete'" class="w-100 d-flex flex-column align-items-center">
<img class="homebridge-logo homebridge-logo-small mx-auto" src="/assets/homebridge-color-round.svg" alt="hb logo">
<h3 class="pt-4 pb-3">{{ 'setup_wizard_message_complete_title' | translate }}</h3>
<div *ngIf="step === 'setup-complete' || step === 'restore-complete'" class="w-100 d-flex flex-column align-items-center">
<h3 class="mb-3">{{ 'setup_wizard_message_complete_title' | translate }}</h3>
<p class="text-center">{{ 'setup_wizard_message_complete_message' | translate }}</p>
<a class="btn btn-lg btn-primary mt-3" routerLink="/">{{ 'setup_wizard.open_dashboard' | translate }}</a>
<a class="btn btn-lg btn-primary mt-3" *ngIf="step === 'restore-complete'" href="/login">
{{ 'form.button_continue' | translate }}
</a>
<a class="btn btn-lg btn-primary mt-3" routerLink="/" *ngIf="step === 'setup-complete'">
{{ 'form.button_continue' | translate }}
</a>
</div>
</div>
</div>
Loading

0 comments on commit d6d29a0

Please sign in to comment.