Skip to content

Commit

Permalink
enhancements to login and setup-wizard modules
Browse files Browse the repository at this point in the history
  • Loading branch information
bwp91 committed Oct 6, 2024
1 parent 21492ff commit 0aa2568
Show file tree
Hide file tree
Showing 54 changed files with 832 additions and 565 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
- enhancements to `login` and `setup-wizard` modules

### Other Changes

Expand Down
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions scripts/lang-sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ async function main() {
// Check each key
const unusedKeys = []
for (const key of keys) {
if (key.startsWith('login.tips_')) {
continue
}
const isUsed = await Promise.all(allFiles.map(file => isKeyUsedInFile(key, file)))
.then(results => results.some(result => result))
if (!isUsed) {
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 @@ -207,7 +207,7 @@ export class ConfigService {
formAuth: Boolean(this.ui.auth !== 'none'),
lightingMode: this.ui.lightingMode || 'auto',
serverTimestamp: new Date().toISOString(),
theme: this.ui.theme || 'orange',
theme: this.ui.theme || 'purple',
}

if (!authorized) {
Expand Down
12 changes: 6 additions & 6 deletions ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions ui/src/app/core/settings.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,9 @@ export class SettingsService {
}

setTheme(theme: string) {
// Default theme is orange
// Default theme is purple
if (!theme || !this.themeList.includes(theme)) {
theme = 'orange'
theme = 'purple'
}

// Grab the body element
Expand Down
60 changes: 36 additions & 24 deletions ui/src/app/modules/login/login.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,21 @@
[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.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" [hidden]="isMobile">
<div class="input-group-text custom-input">
<i class="fas fa-fw fa-lightbulb yellow-text fa-lg"></i>
</div>
<div class="form-control custom-input">
<div class="small grey-text fw-semibold">{{ 'login.tips' | translate }}</div>
<div class="small grey-text">{{ 'login.tips_' + randomTip | translate }}</div>
</div>
</div>
<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"
Expand All @@ -18,59 +27,62 @@
autocomplete="username"
autocapitalize="none"
tabindex="1"
class="form-control px-0"
class="form-control custom-input"
[ngClass]="{
'is-invalid': form.controls.username.dirty && form.controls.username.errors
}"
placeholder="{{ 'login.label_username' | translate }}"
required
/>
<label for="form-username">{{ 'login.label_username' | translate }}</label>
</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"
class="form-control custom-input"
[ngClass]="{
'is-invalid': form.controls.password.dirty && form.controls.password.errors
}"
placeholder="{{ 'login.label_password' | translate }}"
required
/>
<label for="form-pass">{{ 'login.label_password' | translate }}</label>
</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>
<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 px-0"
[ngClass]="{
'is-invalid': form.controls.otp.dirty && form.controls.otp.errors
}"
class="form-control custom-input"
placeholder="{{ 'login.label_2fa_code' | translate }}"
/>
<label for="form-ota">{{ 'login.label_2fa_code' | translate }}</label>
</div>
</div>

<div class="alert alert-error p-2 mb-4" role="alert" *ngIf="invalidCredentials">
{{ 'login.invalid_credentials' | translate }}<br />
<span class="small" [innerHTML]="'login.invalid_credentials_2' | translate"></span>
</div>
<div class="alert alert-error p-2 mb-4" role="alert" *ngIf="invalid2faCode">
{{ 'login.invalid_code' | translate }}<br />
<span class="small" [innerHTML]="'login.invalid_credentials_2' | translate"></span>
</div>
<div class="text-center">
<p class="red-text" *ngIf="invalidCredentials"><small>{{ 'login.invalid_credentials' | 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 tabindex="3" id="submit-button" class="btn btn-primary mb-4" type="submit" [disabled]="form.invalid">
{{ 'form.button_continue' | translate }}
</button>
</div>
</form>
Expand Down
44 changes: 19 additions & 25 deletions ui/src/app/modules/login/login.component.scss
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
::ng-deep body {
background-color: #4a266c !important;
overflow: scroll !important;
}

.login-container {
background-color: #f4f4f4;
background-size: cover;
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
z-index: -1;
padding-top: 3em;
padding-bottom: 3em;
min-height: 100%;
}

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

.form-control:focus {
background-color: inherit !important;
Expand All @@ -21,22 +25,12 @@
}
}

.login-logo {
position: absolute;
top: -35%;
z-index: 2000;
max-width: 450px;

@media screen and (max-width: 450px) {
max-width: 320px;
top: -25%;
}

@media screen and (max-width: 320px) {
max-width: 280px;
}
.homebridge-logo {
height: 125px;
padding-bottom: 10px;
}

@media screen and (max-height: 450px) {
display: none;
}
.btn-primary {
background-color: #4a266c !important;
border-color: #4a266c !important;
}
22 changes: 16 additions & 6 deletions ui/src/app/modules/login/login.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { AuthService } from '@/app/core/auth/auth.service'
import { MobileDetectService } from '@/app/core/mobile-detect.service'
import { SettingsService } from '@/app/core/settings.service'
import { environment } from '@/environments/environment'
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'
Expand All @@ -16,24 +17,32 @@ export class LoginComponent implements OnInit {
@ViewChild('username') private usernameInput: ElementRef
@ViewChild('otp') private otpInput: ElementRef

protected readonly Math = Math

public form: FormGroup<{
username: FormControl<string>
password: FormControl<string>
otp?: FormControl<string>
}>

public isMobile: any = false
public backgroundStyle: string
public invalidCredentials = false
public invalid2faCode = false
public twoFactorCodeRequired = false
public inProgress = false
public randomTip = Math.floor(Math.random() * 3) + 1

private targetRoute: string

constructor(
private $auth: AuthService,
private $md: MobileDetectService,
private $router: Router,
private $settings: SettingsService,
) {}
) {
this.isMobile = this.$md.detect.mobile()
}

ngOnInit() {
this.form = new FormGroup({
Expand Down Expand Up @@ -69,6 +78,7 @@ export class LoginComponent implements OnInit {
this.invalidCredentials = false
this.invalid2faCode = false
this.inProgress = true
document.getElementById('submit-button')?.blur()

// grab the values from the native element as they may be "populated" via autofill.
const passwordInputValue = this.passwordInput?.nativeElement.value
Expand All @@ -88,11 +98,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 +121,7 @@ export class LoginComponent implements OnInit {
} else {
this.invalidCredentials = true
}
})

}
this.inProgress = false
}
}
18 changes: 8 additions & 10 deletions ui/src/app/modules/settings/restore/restore.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ <h5 class="modal-title">{{ 'backup.title_restore' | translate }}</h5>
[disabled]="restoreInProgress"
></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 All @@ -20,15 +20,13 @@ <h5 class="modal-title">{{ 'backup.title_restore' | translate }}</h5>
<li>{{ 'backup.restore_max_size' | translate: { maxBackupSizeText: maxFileSizeText } }}</li>
<li>{{ 'backup.restore_warning' | translate }}</li>
</ul>
<div class="custom-file">
<input
type="file"
class="form-control"
id="restoreFileUpload"
accept="application/gzip, .gz"
(change)="handleRestoreFileInput($event.target.files)"
/>
</div>
<input
type="file"
class="form-control"
id="restoreFileUpload"
accept="application/gzip, .gz, .hbfx"
(change)="handleRestoreFileInput($event.target.files)"
/>
</div>

<div [hidden]="!restoreStarted" id="plugin-log-output" class="modal-body"></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
Loading

0 comments on commit 0aa2568

Please sign in to comment.