Added pages to see, create, modify & delete redeemable actions. User card top right with disconnect & log out. Code clean up.

This commit is contained in:
Tom
2025-01-08 21:50:18 +00:00
parent 11dfde9a03
commit d595c3500e
41 changed files with 1228 additions and 321 deletions

View File

@ -2,15 +2,15 @@ import { NgModule } from '@angular/core';
import { LoginComponent } from './login/login.component';
import { TtsLoginComponent } from './tts-login/tts-login.component';
import { ImpersonationComponent } from './impersonation/impersonation.component';
import { UserCardComponent } from './user-card/user-card.component';
@NgModule({
declarations: [],
imports: [
LoginComponent,
TtsLoginComponent,
ImpersonationComponent
ImpersonationComponent,
UserCardComponent,
]
})
export class AuthModule { }

View File

@ -1,19 +1,13 @@
@if (isAdmin()) {
<mat-card appearance="outlined">
<mat-card-header>
<mat-card-title> Impersonation</mat-card-title>
<mat-card-subtitle>Impersonate as another user</mat-card-subtitle>
</mat-card-header>
<mat-card-actions>
<mat-form-field>
<mat-label>User to impersonate</mat-label>
<mat-select (selectionChange)="onChange($event)" [(value)]="impersonated">
<mat-option>{{getUsername()}}</mat-option>
@for (user of users; track user.id) {
<mat-option [value]="user.id">{{ user.name }}</mat-option>
}
</mat-select>
</mat-form-field>
</mat-card-actions>
</mat-card>
<main>
<mat-form-field>
<mat-label>User to impersonate</mat-label>
<mat-select (selectionChange)="onChange($event)" [(value)]="impersonated">
<mat-option>{{getUsername()}}</mat-option>
@for (user of users; track user.id) {
<mat-option [value]="user.id">{{ user.name }}</mat-option>
}
</mat-select>
</mat-form-field>
</main>
}

View File

@ -0,0 +1,6 @@
main {
display: flex;
justify-content: center;
align-items: center;
margin-top: 1em;
}

View File

@ -51,7 +51,6 @@ export class ImpersonationComponent implements OnInit {
}
public onChange(e: any) {
console.log('impersonate befre', e.value);
if (!e.value) {
this.http.delete(environment.API_HOST + '/admin/impersonate', {
headers: {

View File

@ -1,14 +1,23 @@
<h4>TTS Login</h4>
<div class="main-div">
<mat-card class="main-card">
<mat-form-field>
<mat-label>API Key</mat-label>
<mat-select [(value)]="selected_api_key">
@for (key of api_keys; track key.id) {
<mat-option [value]="key.id">{{key.label}}</mat-option>
}
</mat-select>
</mat-form-field>
<button mat-raised-button (click)="login()">Log In</button>
</mat-card>
</div>
<main>
<mat-card class="main-card">
<mat-card-header class="header">
<mat-card-title-group>
<mat-card-title>TTS Login</mat-card-title>
<mat-card-subtitle>Web Access to Tom-to-Speech</mat-card-subtitle>
</mat-card-title-group>
</mat-card-header>
<mat-card-content class="content">
<mat-form-field>
<mat-label>API Key</mat-label>
<mat-select [(value)]="selected_api_key">
@for (key of api_keys; track key.id) {
<mat-option [value]="key.id">{{key.label}}</mat-option>
}
</mat-select>
</mat-form-field>
</mat-card-content>
<mat-card-actions align="end">
<button mat-raised-button (click)="login()">Log In</button>
</mat-card-actions>
</mat-card>
</main>

View File

@ -1,14 +1,7 @@
.main-div {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
h4 {
text-align: center;
}
.main-card {
width: 20%;
main {
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}

View File

@ -10,61 +10,59 @@ import { Router } from '@angular/router';
import { Subscription } from 'rxjs';
import { environment } from '../../../environments/environment';
import { HermesClientService } from '../../hermes-client.service';
import { MatCard } from '@angular/material/card';
import { MatCard, MatCardModule } from '@angular/material/card';
@Component({
selector: 'tts-login',
standalone: true,
imports: [MatButtonModule, MatCard, MatFormFieldModule, MatSelectModule, MatInputModule, FormsModule],
templateUrl: './tts-login.component.html',
styleUrl: './tts-login.component.scss'
selector: 'tts-login',
standalone: true,
imports: [MatButtonModule, MatCardModule, MatFormFieldModule, MatSelectModule, MatInputModule, FormsModule],
templateUrl: './tts-login.component.html',
styleUrl: './tts-login.component.scss'
})
export class TtsLoginComponent implements OnInit, OnDestroy {
api_keys: { id: string, label: string }[];
selected_api_key: string|undefined;
api_keys: { id: string, label: string }[];
selected_api_key: string | undefined;
private subscription: Subscription|undefined;
private subscription: Subscription | undefined;
constructor(private hermes: HermesClientService, private events: EventService, private http: HttpClient, private router: Router) {
this.api_keys = [];
}
constructor(private hermes: HermesClientService, private events: EventService, private http: HttpClient, private router: Router) {
this.api_keys = [];
}
ngOnInit(): void {
this.http.get(environment.API_HOST + '/keys', {
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('jwt')
}
}).subscribe((data: any) => this.api_keys = data);
ngOnInit(): void {
this.http.get(environment.API_HOST + '/keys', {
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('jwt')
}
}).subscribe((data: any) => this.api_keys = data);
this.subscription = this.events.listen('tts_login_ack', _ => {
if (document.location.href.includes('/tts-login')) {
this.router.navigate(['/policies'])
}
});
this.events.listen('tts_logoff', _ => {
this.selected_api_key = undefined;
});
this.events.listen('impersonation', _ => {
this.selected_api_key = undefined;
this.subscription = this.events.listen('tts_login_ack', _ => {
this.router.navigate(['/policies'])
});
this.events.listen('tts_logoff', _ => {
this.selected_api_key = undefined;
this.router.navigate(['/tts-login'])
});
this.events.listen('impersonation', _ => {
this.selected_api_key = undefined;
this.http.get(environment.API_HOST + '/keys', {
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('jwt')
}
}).subscribe((data: any) => this.api_keys = data);
});
}
this.http.get(environment.API_HOST + '/keys', {
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('jwt')
}
}).subscribe((data: any) => this.api_keys = data);
});
}
ngOnDestroy(): void {
if (this.subscription)
this.subscription.unsubscribe();
}
ngOnDestroy(): void {
if (this.subscription)
this.subscription.unsubscribe();
}
login() {
console.log('api key for login', this.selected_api_key)
if (!this.selected_api_key)
return;
login() {
if (!this.selected_api_key)
return;
this.hermes.login(this.selected_api_key);
}
this.hermes.login(this.selected_api_key);
}
}

View File

@ -0,0 +1,20 @@
@if (auth.isAuthenticated()) {
<main>
<mat-card appearance="outlined" class="card">
<mat-card-header>
<mat-card-title>{{username}}</mat-card-title>
</mat-card-header>
<mat-card-content>
<impersonation />
</mat-card-content>
<mat-card-actions class="actions">
<div>
@if (isTTSLoggedIn) {
<button mat-raised-button (click)="client.disconnect()"><span class="disconnect">Disconnect</span></button>
}
<button mat-raised-button (click)="auth.logout()"><span class="logoff">Log Off</span></button>
</div>
</mat-card-actions>
</mat-card>
</main>
}

View File

@ -0,0 +1,23 @@
main {
display: flex;
justify-content: center;
padding: 0.5em 0;
}
.card {
padding: 0 0 0.5em;
}
.actions {
display: flex;
flex-direction: row;
justify-content: center;
}
.disconnect, .logoff {
color: red;
}
.mdc-button ~ .mdc-button {
margin-left: 1em;
}

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { UserCardComponent } from './user-card.component';
describe('UserCardComponent', () => {
let component: UserCardComponent;
let fixture: ComponentFixture<UserCardComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [UserCardComponent]
})
.compileComponents();
fixture = TestBed.createComponent(UserCardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,26 @@
import { Component, inject } from '@angular/core';
import { ImpersonationComponent } from '../impersonation/impersonation.component';
import { MatCardModule } from '@angular/material/card';
import { ApiAuthenticationService } from '../../shared/services/api/api-authentication.service';
import { MatButtonModule } from '@angular/material/button';
import { HermesClientService } from '../../hermes-client.service';
@Component({
selector: 'user-card',
standalone: true,
imports: [ImpersonationComponent, MatButtonModule, MatCardModule],
templateUrl: './user-card.component.html',
styleUrl: './user-card.component.scss'
})
export class UserCardComponent {
auth = inject(ApiAuthenticationService);
client = inject(HermesClientService);
get isTTSLoggedIn() {
return this.client.logged_in;
}
get username() {
return this.auth.getUsername();
}
}