Skip to content

Commit

Permalink
Fix 457 - Added admin user settings and added "hide usernames" into it (
Browse files Browse the repository at this point in the history
hobbyfarm#226)

* adding backend conversation for hideUsername button

* fixing saving changes with settings modal

* cleaned up files

* deleted terminal theme from settings

---------

Co-authored-by: Tanja Ulmen <[email protected]>
  • Loading branch information
tanemlu and Tanja Ulmen authored Oct 21, 2024
1 parent 55c1df9 commit a4c563b
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 12 deletions.
4 changes: 2 additions & 2 deletions src/app/configuration/settings/settings.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, OnChanges, OnInit, ViewChild } from '@angular/core';
import { Component, ViewChild } from '@angular/core';
import { TypedInput, FormGroupType } from '../../typed-form/TypedInput';
import {
PreparedScope,
Expand All @@ -20,7 +20,7 @@ export class SettingsComponent {
public valid: boolean = true;
public scopes: PreparedScope[] = [];
public selectedScope: PreparedScope;
public loading: boolean = true;
public loading: boolean = true;
public scopesLoading: boolean = true;
readonly FormGroupType = FormGroupType; // Reference to TypedInputTypes enum for template use

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
type="checkbox"
clrToggle
name="hideUsernames"
[(ngModel)]="hideUsernames"
[(ngModel)]="hide_usernames_status"
(ngModelChange)="saveSettings($event)"
/>
<label>Hide Usernames</label>
</clr-toggle-wrapper>
Expand Down Expand Up @@ -118,7 +119,7 @@
<progress-card
[progress]="p"
[pause]="pause"
[hideUsername]="hideUsernames"
[hideUsername]="hide_usernames_status"
(nameClickedEvent)="filterName($event)"
></progress-card>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, OnInit, ViewChild, Input } from '@angular/core';
import { Component, OnInit, ViewChild, Input, OnDestroy, OnChanges } from '@angular/core';
import { ProgressService } from 'src/app/data/progress.service';
import { Progress } from 'src/app/data/progress';
import { UserService } from '../../data/user.service';
Expand All @@ -8,15 +8,17 @@ import { ScenarioService } from '../../data/scenario.service';
import { CourseService } from '../../data/course.service';
import { EventUserListComponent } from './event-user-list/event-user-list.component';
import { JwtHelperService } from '@auth0/angular-jwt';
import { combineLatest } from 'rxjs';
import { combineLatest, Subject, takeUntil } from 'rxjs';
import { User } from '../../data/user';
import { Settings, SettingsService } from 'src/app/data/settings.service';
import { FormGroup } from '@angular/forms';

@Component({
selector: 'progress-dashboard',
templateUrl: './progress-dashboard.component.html',
styleUrls: ['./progress-dashboard.component.scss'],
})
export class ProgressDashboardComponent implements OnInit {
export class ProgressDashboardComponent implements OnInit, OnDestroy, OnChanges {
@Input()
selectedEvent: ScheduledEvent;

Expand All @@ -26,7 +28,9 @@ export class ProgressDashboardComponent implements OnInit {
public callInterval: any;
public circleVisible: boolean = true;
public users: User[];
public hideUsernames: boolean = false;
public settingsForm: FormGroup;
public hide_usernames_status: boolean = false;
private settings_service$ = new Subject<Readonly<Settings>>();

public pauseCall: boolean = false; // Stop refreshing if we are looking at a progress
public pause = (pause: boolean) => {
Expand All @@ -48,17 +52,35 @@ export class ProgressDashboardComponent implements OnInit {
public courseService: CourseService,
public progressService: ProgressService,
public scheduledeventService: ScheduledeventService,
public helper: JwtHelperService
public helper: JwtHelperService,
public settingsService: SettingsService
) {}

ngOnInit() {
this.settingsForm = this.settingsService.getForm()
this.settingsService.settings$
.pipe(takeUntil(this.settings_service$))
.subscribe(
({
hide_usernames_status = false,
}) => {
this.settingsForm.patchValue({
hide_usernames_status
});
this.hide_usernames_status = this.settingsForm.get('hide_usernames_status')?.value
},
);
this.refresh();
}

ngOnChanges() {
this.refresh();
}

ngOnDestroy() {
this.settings_service$.unsubscribe();
}

filter() {
if (this.userFilter != '') {
try {
Expand Down Expand Up @@ -152,6 +174,19 @@ export class ProgressDashboardComponent implements OnInit {
});
}

saveSettings(newHideUsernamesStatus: boolean) {
if (this.settingsForm.value) {
this.settingsService.update({hide_usernames_status: newHideUsernamesStatus}).subscribe({
next: () => {
console.log('Saved Settings.');
},
error: (err) => {
console.error('Error while saving settings:', err);
}
})
}
}

exportCSV() {
let progressCSV = '';
this.filteredProgress.forEach((progress) => {
Expand Down
32 changes: 30 additions & 2 deletions src/app/data/settings.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ import {
extractResponseContent,
GargantuaClientFactory,
} from '../data/gargantua.service';
import { FormControl, FormGroup, Validators } from '@angular/forms';

export interface Settings {
terminal_theme: (typeof themes)[number]['id'];
hide_usernames_status: boolean;
}

/**
Expand All @@ -31,11 +33,30 @@ export class SettingsService {
private subject = new Subject<Readonly<Settings>>();
readonly settings$ = concat(this.fetch(), this.subject).pipe(shareReplay(1));

public settingsForm: FormGroup = new FormGroup({
terminal_theme: new FormControl<typeof themes[number]['id'] | null> (null, [Validators.required,]),
hide_usernames_status: new FormControl<boolean>(false),
})

fetch() {
return this.garg.get('/settings').pipe(
map(extractResponseContent),
tap((s: Readonly<Settings>) => {
map((s: Readonly<Settings | null>) =>
s
? s
: ({
terminal_theme: themes[0].id,
hide_usernames_status: false
} as Settings),
),
tap((s: Settings) => {
s.hide_usernames_status = JSON.parse(String(s.hide_usernames_status ?? false));
this.settingsForm.patchValue(s);
this.subject.next(s);
}),
catchError((error) => {
console.error('Error on fetching settings:', error);
return throwError(() => error);
})
);
}
Expand All @@ -46,7 +67,10 @@ export class SettingsService {
catchError((e: HttpErrorResponse) => {
return throwError(() => e.error);
}),
tap(() => this.subject.next(newSettings))
tap(() => {
this.settingsForm.patchValue(newSettings);
this.subject.next(newSettings);
})
);
}

Expand All @@ -58,4 +82,8 @@ export class SettingsService {
})
);
}

getForm() {
return this.settingsForm;
}
}
43 changes: 43 additions & 0 deletions src/app/header/header.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,54 @@
</button>
<clr-dropdown-menu *clrIfOpen clrPosition="bottom-right">
<a (click)="about()" clrDropdownItem>About</a>
<a (click)="openSettings()" clrDropdownItem>Settings</a>
<a (click)="logout()" clrDropdownItem>Logout</a>
</clr-dropdown-menu>
</clr-dropdown>
</div>

<clr-modal #settingsmodal [(clrModalOpen)]="settingsModalOpened">
<h3 class="modal-title">Settings</h3>
<div class="modal-body">
<ng-container *ngIf="fetchingSettings">
<span class="spinner spinner-inline"> Loading... </span>
<span> Loading... </span>
</ng-container>
<ng-container *ngIf="!fetchingSettings">
<form clrForm [formGroup]="settingsForm">
<clr-tabs>
<clr-tab>
<button clrTabLink>General</button>
<clr-tab-content>
<clr-toggle-container>
<label class="clr-col-md-4">Hide Usernames</label>
<clr-toggle-wrapper>
<input
class="clr-col-md-8"
type="checkbox"
clrToggle
name="hide_usernames_status"
formControlName="hide_usernames_status"
/>
<label>Hide Usernames</label>
</clr-toggle-wrapper>
<clr-control-helper
>Keep names hidden in screensharings
</clr-control-helper>
</clr-toggle-container>
</clr-tab-content>
<clr-tab-content> </clr-tab-content>
</clr-tab>
</clr-tabs>
</form>
</ng-container>
</div>
<div class="modal-footer">
<button class="btn" (click)="settingsModalOpened = false">Close</button>
<button class="btn btn-success" (click)="doSaveSettings()" [disabled]="isButtonDisabled">Save</button>
</div>
</clr-modal>

<clr-modal #logoutmodal [(clrModalOpen)]="logoutModalOpened">
<h3 class="modal-title">Confirm Logout</h3>
<div class="modal-body">
Expand Down
51 changes: 50 additions & 1 deletion src/app/header/header.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,28 @@ import { JwtHelperService } from '@auth0/angular-jwt';
import { AppConfigService } from '../app-config.service';
import { RbacService } from '../data/rbac.service';
import { Title } from '@angular/platform-browser';
import { FormGroup } from '@angular/forms';
import { themes } from '../step/terminal-themes/themes';
import { first } from 'rxjs/operators';
import { SettingsService } from '../data/settings.service';

@Component({
selector: '[app-header]',
templateUrl: './header.component.html',
})
export class HeaderComponent implements OnInit {
public logoutModalOpened: boolean = false;
public settingsModalOpened: boolean = false;
public aboutModalOpened: boolean = false;
public version = environment.version;
public email: string = '';
public configurationRbac: boolean = false;

public fetchingSettings = false;
public settingsForm: FormGroup;
public hide_usernames_status: boolean;
public isButtonDisabled: boolean = false;

private config = this.configService.getConfig();
public title = this.config.title || 'HobbyFarm Administration';
public logo = this.config.logo || '/assets/default/logo.svg';
Expand All @@ -29,6 +39,7 @@ export class HeaderComponent implements OnInit {
public helper: JwtHelperService,
public configService: AppConfigService,
private rbacService: RbacService,
private settingsService: SettingsService,
private titleService: Title
) {
this.configService.getLogo(this.logo).then((obj: string) => {
Expand Down Expand Up @@ -69,11 +80,13 @@ export class HeaderComponent implements OnInit {
// hence we automatically logout the user
this.doLogout();
}
this.settingsForm = this.settingsService.getForm()
}

@ViewChild('settingsmodal', { static: true }) settingsModal: ClrModal;
@ViewChild('logoutmodal', { static: true }) logoutModal: ClrModal;
@ViewChild('aboutmodal', { static: true }) aboutModal: ClrModal;

public logout() {
this.logoutModal.open();
}
Expand All @@ -86,4 +99,40 @@ export class HeaderComponent implements OnInit {
localStorage.removeItem('hobbyfarm_admin_token');
this.router.navigateByUrl('/login');
}

public openSettings() {
this.settingsForm.reset();
this.fetchingSettings = true;
this.settingsService.settings$
.pipe(first())
.subscribe(
({
terminal_theme = 'default',
hide_usernames_status = false,
}) => {
this.settingsForm.setValue({
terminal_theme,
hide_usernames_status
});

this.fetchingSettings = false;
},
);
this.settingsModal.open();
this.hide_usernames_status = this.settingsForm.get('hide_usernames_status')?.value
}

public doSaveSettings() {
this.isButtonDisabled = true;
this.settingsService.update(this.settingsForm.value).subscribe({
next: () => {
this.settingsModalOpened = false;
this.isButtonDisabled = false;

},
error: () => {
setTimeout(() => (this.settingsModalOpened = false), 2000);
},
});
}
}

0 comments on commit a4c563b

Please sign in to comment.