Separate Network settings UI into it's own tab (#389)

* Separate Network and regular Settings in UI

* Add missing files

* More cleanup and fixes

* Network -> Network Configuration
This commit is contained in:
Erik Olof Gunnar Andersson 2024-10-08 23:26:00 +02:00 committed by GitHub
parent 3636d2b399
commit 2c13f23b54
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 263 additions and 56 deletions

View File

@ -4,6 +4,7 @@ import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './components/home/home.component';
import { LogsComponent } from './components/logs/logs.component';
import { SettingsComponent } from './components/settings/settings.component';
import { NetworkComponent } from './components/network/network.component';
import { SwarmComponent } from './components/swarm/swarm.component';
import { AppLayoutComponent } from './layout/app.layout.component';
@ -20,6 +21,10 @@ const routes: Routes = [
path: 'logs',
component: LogsComponent
},
{
path: 'network',
component: NetworkComponent
},
{
path: 'settings',
component: SettingsComponent

View File

@ -11,9 +11,11 @@ import { ToastrModule } from 'ngx-toastr';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { EditComponent } from './components/edit/edit.component';
import { NetworkEditComponent } from './components/network-edit/network.edit.component';
import { HomeComponent } from './components/home/home.component';
import { LoadingComponent } from './components/loading/loading.component';
import { LogsComponent } from './components/logs/logs.component';
import { NetworkComponent } from './components/network/network.component';
import { SettingsComponent } from './components/settings/settings.component';
import { SwarmComponent } from './components/swarm/swarm.component';
import { AppLayoutModule } from './layout/app.layout.module';
@ -26,8 +28,10 @@ import { MessageModule } from 'primeng/message';
const components = [
AppComponent,
EditComponent,
NetworkEditComponent,
HomeComponent,
LoadingComponent,
NetworkComponent,
SettingsComponent,
LogsComponent
];

View File

@ -1,29 +1,5 @@
<ng-container *ngIf="form != null">
<form [formGroup]="form">
<div class="field grid p-fluid">
<label htmlFor="hostname" class="col-12 mb-2 md:col-2 md:mb-0">Hostname:</label>
<div class="col-12 md:col-10">
<input pInputText id="hostname" type="text" formControlName="hostname" />
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="ssid" class="col-12 mb-2 md:col-2 md:mb-0">WiFi SSID:</label>
<div class="col-12 md:col-10">
<input pInputText id="ssid" type="text" formControlName="ssid" />
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="wifiPass" class="col-12 mb-2 md:col-2 md:mb-0">WiFi Password:</label>
<div class="col-12 md:col-10 p-input-icon-right">
<i *ngIf="form.get('wifiPass')?.dirty" class="pi"
[ngClass]="{'pi-eye': !showWifiPassword, 'pi-eye-slash': showWifiPassword}"
(click)="toggleWifiPasswordVisibility()" style="cursor: pointer;"></i>
<input pInputText id="wifiPass" formControlName="wifiPass"
[type]="showWifiPassword ? 'text' : 'password'"
placeholder="Enter WiFi password" />
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="stratumURL" class="col-12 mb-2 md:col-2 md:mb-0">Stratum URL:</label>
<div class="col-12 md:col-10">
@ -172,7 +148,6 @@
</ng-container>
<div class="col-12 md:col-4">
<div class="field-checkbox">
<p-checkbox name="flipscreen" formControlName="flipscreen" inputId="flipscreen"

View File

@ -159,9 +159,6 @@ export class EditComponent implements OnInit {
stratumPassword: ['*****', [Validators.required]],
fallbackStratumUser: [info.fallbackStratumUser, [Validators.required]],
fallbackStratumPassword: ['password', [Validators.required]],
hostname: [info.hostname, [Validators.required]],
ssid: [info.ssid, [Validators.required]],
wifiPass: ['*****'],
coreVoltage: [info.coreVoltage, [Validators.required]],
frequency: [info.frequency, [Validators.required]],
autofanspeed: [info.autofanspeed == 1, [Validators.required]],
@ -198,12 +195,6 @@ export class EditComponent implements OnInit {
const form = this.form.getRawValue();
// Allow an empty wifi password
form.wifiPass = form.wifiPass == null ? '' : form.wifiPass;
if (form.wifiPass === '*****') {
delete form.wifiPass;
}
if (form.stratumPassword === '*****') {
delete form.stratumPassword;
}
@ -227,9 +218,4 @@ export class EditComponent implements OnInit {
this.showStratumPassword = !this.showStratumPassword;
}
showWifiPassword: boolean = false;
toggleWifiPasswordVisibility() {
this.showWifiPassword = !this.showWifiPassword;
}
}

View File

@ -0,0 +1,34 @@
<ng-container *ngIf="form != null">
<form [formGroup]="form">
<div class="field grid p-fluid">
<label htmlFor="hostname" class="col-12 mb-2 md:col-2 md:mb-0">Hostname:</label>
<div class="col-12 md:col-10">
<input pInputText id="hostname" type="text" formControlName="hostname" />
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="ssid" class="col-12 mb-2 md:col-2 md:mb-0">WiFi SSID:</label>
<div class="col-12 md:col-10">
<input pInputText id="ssid" type="text" formControlName="ssid" />
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="wifiPass" class="col-12 mb-2 md:col-2 md:mb-0">WiFi Password:</label>
<div class="col-12 md:col-10 p-input-icon-right">
<i *ngIf="form.get('wifiPass')?.dirty" class="pi"
[ngClass]="{'pi-eye': !showWifiPassword, 'pi-eye-slash': showWifiPassword}"
(click)="toggleWifiPasswordVisibility()" style="cursor: pointer;"></i>
<input pInputText id="wifiPass" formControlName="wifiPass"
[type]="showWifiPassword ? 'text' : 'password'"
placeholder="Enter WiFi password" />
</div>
</div>
<div class="mt-2">
<button pButton [disabled]="form.invalid" (click)="updateSystem()"
class="btn btn-primary mr-2">Save</button>
<b style="line-height: 34px;">You must restart this device after saving for changes to take effect.</b>
</div>
</form>
</ng-container>

View File

@ -0,0 +1,5 @@
.pi {
right: 1rem;
font-size: 1.5rem;
top: 1rem;
}

View File

@ -0,0 +1,21 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NetworkEditComponent } from './network.edit.component';
describe('NetworkEditComponent', () => {
let component: NetworkEditComponent;
let fixture: ComponentFixture<NetworkEditComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [NetworkEditComponent]
});
fixture = TestBed.createComponent(NetworkEditComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,70 @@
import { HttpErrorResponse } from '@angular/common/http';
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ToastrService } from 'ngx-toastr';
import { startWith } from 'rxjs';
import { LoadingService } from 'src/app/services/loading.service';
import { SystemService } from 'src/app/services/system.service';
@Component({
selector: 'app-network-edit',
templateUrl: './network.edit.component.html',
styleUrls: ['./network.edit.component.scss']
})
export class NetworkEditComponent implements OnInit {
public form!: FormGroup;
@Input() uri = '';
constructor(
private fb: FormBuilder,
private systemService: SystemService,
private toastr: ToastrService,
private toastrService: ToastrService,
private loadingService: LoadingService
) {
}
ngOnInit(): void {
this.systemService.getInfo(this.uri)
.pipe(this.loadingService.lockUIUntilComplete())
.subscribe(info => {
this.form = this.fb.group({
hostname: [info.hostname, [Validators.required]],
ssid: [info.ssid, [Validators.required]],
wifiPass: ['*****'],
});
});
}
public updateSystem() {
const form = this.form.getRawValue();
// Allow an empty wifi password
form.wifiPass = form.wifiPass == null ? '' : form.wifiPass;
if (form.wifiPass === '*****') {
delete form.wifiPass;
}
this.systemService.updateSystem(this.uri, form)
.pipe(this.loadingService.lockUIUntilComplete())
.subscribe({
next: () => {
this.toastr.success('Success!', 'Saved.');
},
error: (err: HttpErrorResponse) => {
this.toastr.error('Error.', `Could not save. ${err.message}`);
}
});
}
showWifiPassword: boolean = false;
toggleWifiPasswordVisibility() {
this.showWifiPassword = !this.showWifiPassword;
}
}

View File

@ -0,0 +1,5 @@
<div class="card">
<h2>Network Configuration</h2>
<app-network-edit></app-network-edit>
</div>

View File

@ -0,0 +1,35 @@
input[type="text"],
input[type="number"],
input[type="password"],
input[type="range"] {
min-width: 250px;
max-width: 90%;
}
select {
min-width: 268px;
max-width: 90%;
}
.restart {
margin-bottom: 1.5rem;
}
@media only screen and (min-width:900px) {
input[type="text"],
input[type="password"],
input[type="number"],
input[type="range"] {
min-width: 500px
}
select {
min-width: 518px
}
}
a {
color: white;
}

View File

@ -0,0 +1,21 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NetworkComponent } from './network.component';
describe('NetworkComponent', () => {
let component: NetworkComponent;
let fixture: ComponentFixture<NetworkComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [NetworkComponent]
});
fixture = TestBed.createComponent(NetworkComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,62 @@
import { HttpErrorResponse, HttpEventType } from '@angular/common/http';
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ToastrService } from 'ngx-toastr';
import { map, Observable, shareReplay, startWith } from 'rxjs';
import { LoadingService } from 'src/app/services/loading.service';
import { SystemService } from 'src/app/services/system.service';
@Component({
selector: 'app-network',
templateUrl: './network.component.html',
styleUrls: ['./network.component.scss']
})
export class NetworkComponent {
public form!: FormGroup;
public info$: Observable<any>;
constructor(
private fb: FormBuilder,
private systemService: SystemService,
private toastr: ToastrService,
private toastrService: ToastrService,
private loadingService: LoadingService,
) {
this.info$ = this.systemService.getInfo().pipe(shareReplay({refCount: true, bufferSize: 1}))
this.info$.pipe(this.loadingService.lockUIUntilComplete())
.subscribe(info => {
this.form = this.fb.group({
hostname: [info.hostname, [Validators.required]],
ssid: [info.ssid, [Validators.required]],
wifiPass: ['*****'],
});
});
}
public updateSystem() {
const form = this.form.getRawValue();
// Allow an empty wifi password
form.wifiPass = form.wifiPass == null ? '' : form.wifiPass;
if (form.wifiPass === '*****') {
delete form.wifiPass;
}
this.systemService.updateSystem(undefined, form)
.pipe(this.loadingService.lockUIUntilComplete())
.subscribe({
next: () => {
this.toastr.success('Success!', 'Saved.');
},
error: (err: HttpErrorResponse) => {
this.toastr.error('Error.', `Could not save. ${err.message}`);
}
});
}
}

View File

@ -71,8 +71,6 @@ export class SettingsComponent {
]],
stratumUser: [info.stratumUser, [Validators.required]],
stratumPassword: ['*****', [Validators.required]],
ssid: [info.ssid, [Validators.required]],
wifiPass: ['*****'],
coreVoltage: [info.coreVoltage, [Validators.required]],
frequency: [info.frequency, [Validators.required]],
autofanspeed: [info.autofanspeed == 1, [Validators.required]],
@ -116,12 +114,6 @@ export class SettingsComponent {
form.invertfanpolarity = form.invertfanpolarity == true ? 1 : 0;
form.autofanspeed = form.autofanspeed == true ? 1 : 0;
// Allow an empty wifi password
form.wifiPass = form.wifiPass == null ? '' : form.wifiPass;
if (form.wifiPass === '*****') {
delete form.wifiPass;
}
if (form.stratumPassword === '*****') {
delete form.stratumPassword;
}
@ -211,9 +203,4 @@ export class SettingsComponent {
});
this.toastr.success('Success!', 'Bitaxe restarted');
}
}

View File

@ -24,22 +24,19 @@ export class AppMenuComponent implements OnInit {
items: [
{ label: 'Dashboard', icon: 'pi pi-fw pi-home', routerLink: ['/'] },
{ label: 'Swarm', icon: 'pi pi-fw pi-share-alt', routerLink: ['swarm'] },
{ label: 'Network', icon: 'pi pi-fw pi-wifi', routerLink: ['network'] },
{ label: 'Settings', icon: 'pi pi-fw pi-cog', routerLink: ['settings'] },
{ label: 'Logs', icon: 'pi pi-fw pi-list', routerLink: ['logs'] },
]
}
];
}
public restart() {
this.systemService.restart().subscribe(res => {
});
this.toastr.success('Success!', 'Bitaxe restarted');
}
}