Added TTS chat filters.
This commit is contained in:
parent
0afa2138b4
commit
275069697f
@ -1,19 +1,20 @@
|
|||||||
import { CommonModule, DatePipe, isPlatformBrowser } from '@angular/common';
|
import { CommonModule, isPlatformBrowser } from '@angular/common';
|
||||||
import { Component, OnInit, Inject, PLATFORM_ID, NgZone, OnDestroy } from '@angular/core';
|
import { Component, OnInit, Inject, PLATFORM_ID, NgZone, OnDestroy } from '@angular/core';
|
||||||
import { Router, RouterOutlet } from '@angular/router';
|
import { Router, RouterOutlet } from '@angular/router';
|
||||||
import { FormsModule } from '@angular/forms'
|
import { FormsModule } from '@angular/forms'
|
||||||
import { HermesClientService } from './hermes-client.service';
|
import { HermesClientService } from './hermes-client.service';
|
||||||
import { AuthUserGuard } from './shared/auth/auth.user.guard'
|
import { AuthUserGuard } from './shared/auth/auth.user.guard'
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { PolicyComponent } from "./policies/policy/policy.component";
|
|
||||||
import { NavigationComponent } from "./navigation/navigation.component";
|
import { NavigationComponent } from "./navigation/navigation.component";
|
||||||
import EventService from './shared/services/EventService';
|
import EventService from './shared/services/EventService';
|
||||||
import { ApiAuthenticationService } from './shared/services/api/api-authentication.service';
|
import { ApiAuthenticationService } from './shared/services/api/api-authentication.service';
|
||||||
|
import { PoliciesModule } from './policies/policies.module';
|
||||||
|
import { TtsFiltersModule } from './tts-filters/tts-filters.module';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [RouterOutlet, CommonModule, FormsModule, PolicyComponent, NavigationComponent],
|
imports: [RouterOutlet, CommonModule, FormsModule, PoliciesModule, TtsFiltersModule, NavigationComponent],
|
||||||
providers: [AuthUserGuard],
|
providers: [AuthUserGuard],
|
||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
styleUrl: './app.component.scss'
|
styleUrl: './app.component.scss'
|
||||||
@ -22,7 +23,6 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
private isBrowser: boolean;
|
private isBrowser: boolean;
|
||||||
private ngZone: NgZone;
|
private ngZone: NgZone;
|
||||||
private subscriptions: Subscription[];
|
private subscriptions: Subscription[];
|
||||||
pipe = new DatePipe('en-US')
|
|
||||||
|
|
||||||
|
|
||||||
constructor(private auth: ApiAuthenticationService, private client: HermesClientService, private events: EventService, private router: Router, ngZone: NgZone, @Inject(PLATFORM_ID) private platformId: Object) {
|
constructor(private auth: ApiAuthenticationService, private client: HermesClientService, private events: EventService, private router: Router, ngZone: NgZone, @Inject(PLATFORM_ID) private platformId: Object) {
|
||||||
|
@ -4,6 +4,7 @@ import { AuthUserGuard } from './shared/auth/auth.user.guard';
|
|||||||
import { LoginComponent } from './login/login.component';
|
import { LoginComponent } from './login/login.component';
|
||||||
import { TtsLoginComponent } from './tts-login/tts-login.component';
|
import { TtsLoginComponent } from './tts-login/tts-login.component';
|
||||||
import { TwitchAuthCallbackComponent } from './twitch-auth-callback/twitch-auth-callback.component';
|
import { TwitchAuthCallbackComponent } from './twitch-auth-callback/twitch-auth-callback.component';
|
||||||
|
import { FiltersComponent } from './tts-filters/filters/filters.component';
|
||||||
|
|
||||||
export const routes: Routes = [
|
export const routes: Routes = [
|
||||||
{
|
{
|
||||||
@ -11,6 +12,11 @@ export const routes: Routes = [
|
|||||||
component: PolicyComponent,
|
component: PolicyComponent,
|
||||||
canActivate: [AuthUserGuard],
|
canActivate: [AuthUserGuard],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'filters',
|
||||||
|
component: FiltersComponent,
|
||||||
|
canActivate: [AuthUserGuard],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'login',
|
path: 'login',
|
||||||
component: LoginComponent,
|
component: LoginComponent,
|
||||||
|
@ -2,176 +2,236 @@ import { Injectable } from '@angular/core';
|
|||||||
import { DatePipe } from '@angular/common';
|
import { DatePipe } from '@angular/common';
|
||||||
import { HermesSocketService } from './hermes-socket.service';
|
import { HermesSocketService } from './hermes-socket.service';
|
||||||
import EventService from './shared/services/EventService';
|
import EventService from './shared/services/EventService';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
export interface Message {
|
export interface Message {
|
||||||
d: object,
|
d: object,
|
||||||
t: object,
|
t: object,
|
||||||
o: object
|
o: object
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class HermesClientService {
|
export class HermesClientService {
|
||||||
pipe = new DatePipe('en-US')
|
pipe = new DatePipe('en-US');
|
||||||
connected: boolean;
|
session_id: string|undefined;
|
||||||
logged_in: boolean;
|
connected: boolean;
|
||||||
|
logged_in: boolean;
|
||||||
private subscriptions: { [key: number]: ((data: any) => void)[] }
|
|
||||||
|
|
||||||
constructor(private socket: HermesSocketService, private events: EventService) {
|
private subscriptions: { [key: number]: ((data: any) => void)[] }
|
||||||
this.subscriptions = {};
|
|
||||||
this.connected = false;
|
|
||||||
this.logged_in = false;
|
|
||||||
|
|
||||||
this.events.listen('tts_login', (payload) => {
|
constructor(private socket: HermesSocketService, private events: EventService) {
|
||||||
this.login(payload);
|
this.subscriptions = {};
|
||||||
});
|
this.connected = false;
|
||||||
}
|
this.logged_in = false;
|
||||||
|
|
||||||
public connect() {
|
this.events.listen('tts_login', (payload) => {
|
||||||
if (this.connected)
|
this.login(payload);
|
||||||
return;
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.socket.connect();
|
public connect() {
|
||||||
this.connected = true;
|
if (this.connected)
|
||||||
return this.listen();
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
public disconnect() {
|
this.socket.connect();
|
||||||
if (!this.connected)
|
this.connected = true;
|
||||||
return;
|
return this.listen();
|
||||||
|
}
|
||||||
|
|
||||||
this.connected = false;
|
public disconnect() {
|
||||||
this.logged_in = false;
|
if (!this.connected)
|
||||||
this.socket.close();
|
return;
|
||||||
this.events.emit('tts_logoff', null);
|
|
||||||
|
this.connected = false;
|
||||||
|
this.logged_in = false;
|
||||||
|
this.session_id = undefined;
|
||||||
|
this.socket.close();
|
||||||
|
this.events.emit('tts_logoff', null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public first(predicate: (data: any) => boolean): Observable<any> | null {
|
||||||
|
return this.socket.first(predicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private send(op: number, data: any) {
|
||||||
|
if (op != 0)
|
||||||
|
console.log("TX:", data);
|
||||||
|
|
||||||
|
this.socket.sendMessage({
|
||||||
|
d: data,
|
||||||
|
op
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public login(api_key: string) {
|
||||||
|
if (!this.connected)
|
||||||
|
this.connect();
|
||||||
|
if (this.logged_in)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.send(1, {
|
||||||
|
api_key,
|
||||||
|
web_login: true,
|
||||||
|
major_version: 0,
|
||||||
|
minor_version: 1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public createPolicy(groupId: string, path: string, usage: number, timespan: number) {
|
||||||
|
if (!this.logged_in)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.send(3, {
|
||||||
|
request_id: null,
|
||||||
|
type: "create_policy",
|
||||||
|
data: {
|
||||||
|
groupId, path, count: usage, span: timespan
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public createTTSFilter(search: string, replace: string) {
|
||||||
|
if (!this.logged_in)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.send(3, {
|
||||||
|
request_id: null,
|
||||||
|
type: "create_tts_filter",
|
||||||
|
data: { search, replace },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public deletePolicy(id: string) {
|
||||||
|
if (!this.logged_in)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.send(3, {
|
||||||
|
request_id: null,
|
||||||
|
type: "delete_policy",
|
||||||
|
data: { id },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public deleteTTSFilter(id: string) {
|
||||||
|
if (!this.logged_in)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.send(3, {
|
||||||
|
request_id: null,
|
||||||
|
type: "delete_tts_filter",
|
||||||
|
data: { id },
|
||||||
|
nounce: this.session_id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public fetchFilters() {
|
||||||
|
if (!this.logged_in)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.send(3, {
|
||||||
|
request_id: null,
|
||||||
|
type: "get_tts_word_filters",
|
||||||
|
data: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public fetchPermissionsAndGroups() {
|
||||||
|
if (!this.logged_in)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.send(3, {
|
||||||
|
request_id: null,
|
||||||
|
type: "get_permissions",
|
||||||
|
data: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public fetchPolicies() {
|
||||||
|
if (!this.logged_in)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.send(3, {
|
||||||
|
request_id: null,
|
||||||
|
type: "get_policies",
|
||||||
|
data: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public heartbeat() {
|
||||||
|
const date = new Date()
|
||||||
|
this.send(0, {
|
||||||
|
date_time: this.pipe.transform(date.getTime() + date.getUTCDate(), "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'SSS'Z'")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public subscribe(code: number, action: (data: any) => void) {
|
||||||
|
if (!(code in this.subscriptions)) {
|
||||||
|
this.subscriptions[code] = []
|
||||||
}
|
}
|
||||||
|
this.subscriptions[code].push(action);
|
||||||
|
}
|
||||||
|
|
||||||
private send(op: number, data: any) {
|
public updatePolicy(id: string, groupId: string, path: string, usage: number, timespan: number) {
|
||||||
if (op != 0)
|
if (!this.logged_in)
|
||||||
console.log("TX:", data);
|
return;
|
||||||
|
|
||||||
this.socket.sendMessage({
|
this.send(3, {
|
||||||
d: data,
|
request_id: null,
|
||||||
op
|
type: "update_policy",
|
||||||
});
|
data: {
|
||||||
}
|
id, groupId, path, count: usage, span: timespan
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public login(api_key: string) {
|
public updateTTSFilter(id: string, search: string, replace: string) {
|
||||||
if (!this.connected)
|
if (!this.logged_in)
|
||||||
this.connect();
|
return;
|
||||||
if (this.logged_in)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.send(1, {
|
|
||||||
api_key,
|
|
||||||
web_login: true,
|
|
||||||
major_version: 0,
|
|
||||||
minor_version: 1
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public createPolicy(groupId: string, path: string, usage: number, timespan: number) {
|
this.send(3, {
|
||||||
if (!this.logged_in)
|
request_id: null,
|
||||||
return;
|
type: "update_tts_filter",
|
||||||
|
data: { id, search, replace },
|
||||||
this.send(3, {
|
nounce: this.session_id,
|
||||||
request_id: null,
|
});
|
||||||
type: "create_policy",
|
}
|
||||||
data: {
|
|
||||||
groupId, path, count: usage, span: timespan
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public deletePolicy(id: string) {
|
private listen() {
|
||||||
if (!this.logged_in)
|
return this.socket.subscribe({
|
||||||
return;
|
next: (message: any) => {
|
||||||
|
console.log("RX:", message);
|
||||||
this.send(3, {
|
switch (message.op) {
|
||||||
request_id: null,
|
case 0: // Heartbeat
|
||||||
type: "delete_policy",
|
console.log("Heartbeat received. Potential connection problem?");
|
||||||
data: {
|
break;
|
||||||
id
|
case 2: // Login Ack
|
||||||
},
|
console.log("Login successful.", message.d.session_id);
|
||||||
});
|
this.logged_in = true;
|
||||||
}
|
this.session_id = message.d.session_id;
|
||||||
|
this.events.emit('tts_login_ack', null);
|
||||||
public fetchPolicies() {
|
break;
|
||||||
if (!this.logged_in)
|
case 4: // Request Ack
|
||||||
return;
|
console.log("Request ack received.");
|
||||||
|
break;
|
||||||
this.send(3, {
|
}
|
||||||
request_id: null,
|
if (message.op in this.subscriptions) {
|
||||||
type: "get_policies",
|
console.log('found #' + message.op + ' subscription for ' + message.op);
|
||||||
data: null,
|
for (let action of this.subscriptions[message.op])
|
||||||
});
|
action(message.d);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
public fetchPermissionsAndGroups() {
|
error: (err: any) => {
|
||||||
if (!this.logged_in)
|
console.error('Websocket error', err);
|
||||||
return;
|
if (err.type == 'close') {
|
||||||
|
this.connected = false;
|
||||||
this.send(3, {
|
this.logged_in = false;
|
||||||
request_id: null,
|
this.socket.close();
|
||||||
type: "get_permissions",
|
this.events.emit('tts_logoff', null);
|
||||||
data: null,
|
}
|
||||||
});
|
},
|
||||||
}
|
complete: () => console.log('Websocket disconnected.')
|
||||||
|
});
|
||||||
public heartbeat() {
|
}
|
||||||
const date = new Date()
|
|
||||||
this.send(0, {
|
|
||||||
date_time: this.pipe.transform(date.getTime() + date.getUTCDate(), "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'SSS'Z'")
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public subscribe(code: number, action: (data: any) => void) {
|
|
||||||
if (!(code in this.subscriptions)) {
|
|
||||||
this.subscriptions[code] = []
|
|
||||||
}
|
|
||||||
this.subscriptions[code].push(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
public updatePolicy(id: string, groupId: string, path: string, usage: number, timespan: number) {
|
|
||||||
if (!this.logged_in)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.send(3, {
|
|
||||||
request_id: null,
|
|
||||||
type: "update_policy",
|
|
||||||
data: {
|
|
||||||
id, groupId, path, count: usage, span: timespan
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private listen() {
|
|
||||||
return this.socket.subscribe({
|
|
||||||
next: (message: any) => {
|
|
||||||
console.log("RX:", message);
|
|
||||||
switch (message.op) {
|
|
||||||
case 0: // Heartbeat
|
|
||||||
console.log("Heartbeat received. Potential connection problem?");
|
|
||||||
break;
|
|
||||||
case 2: // Login Ack
|
|
||||||
console.log("Login successful.");
|
|
||||||
this.logged_in = true;
|
|
||||||
this.events.emit('tts_login_ack', null);
|
|
||||||
break;
|
|
||||||
case 4: // Request Ack
|
|
||||||
console.log("Request received.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (message.op in this.subscriptions) {
|
|
||||||
console.log('found #' + message.op + ' subscription for ' + message.op);
|
|
||||||
for (let action of this.subscriptions[message.op])
|
|
||||||
action(message.d);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error: (err: any) => console.error('Websocket error', err),
|
|
||||||
complete: () => console.log('Websocket disconnected.')
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
import { Component, OnInit, Injectable } from '@angular/core';
|
import { OnInit, Injectable } from '@angular/core';
|
||||||
import { webSocket, WebSocketSubject } from 'rxjs/webSocket';
|
import { webSocket, WebSocketSubject } from 'rxjs/webSocket';
|
||||||
import { catchError, tap, switchAll } from 'rxjs/operators';
|
import { catchError, filter, first, timeout } from 'rxjs/operators';
|
||||||
import { EMPTY, Observer, Subject } from 'rxjs';
|
|
||||||
import { environment } from '../environments/environment';
|
import { environment } from '../environments/environment';
|
||||||
|
import { Observable, throwError } from 'rxjs';
|
||||||
|
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class HermesSocketService implements OnInit {
|
export class HermesSocketService implements OnInit {
|
||||||
private WS_ENDPOINT = environment.WSS_ENDPOINT;
|
|
||||||
private socket: WebSocketSubject<any> | undefined = undefined
|
private socket: WebSocketSubject<any> | undefined = undefined
|
||||||
|
|
||||||
constructor() { }
|
constructor() { }
|
||||||
@ -23,6 +22,13 @@ export class HermesSocketService implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public first(predicate: (data: any) => boolean): Observable<any>|null {
|
||||||
|
if (!this.socket || this.socket.closed)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return this.socket.pipe(timeout(3000), catchError((e) => throwError(() => 'No response after 3 seconds.')), first(predicate));
|
||||||
|
}
|
||||||
|
|
||||||
private getNewWebSocket() {
|
private getNewWebSocket() {
|
||||||
return webSocket({
|
return webSocket({
|
||||||
url: environment.WSS_ENDPOINT
|
url: environment.WSS_ENDPOINT
|
||||||
@ -31,21 +37,21 @@ export class HermesSocketService implements OnInit {
|
|||||||
|
|
||||||
public sendMessage(msg: any) {
|
public sendMessage(msg: any) {
|
||||||
if (!this.socket || this.socket.closed)
|
if (!this.socket || this.socket.closed)
|
||||||
return
|
return;
|
||||||
|
|
||||||
this.socket.next(msg);
|
this.socket.next(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public subscribe(subscriptions: any) {
|
public subscribe(subscriptions: any) {
|
||||||
if (!this.socket || this.socket.closed)
|
if (!this.socket || this.socket.closed)
|
||||||
return
|
return;
|
||||||
|
|
||||||
return this.socket.subscribe(subscriptions);
|
return this.socket.subscribe(subscriptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public close() {
|
public close() {
|
||||||
if (!this.socket || this.socket.closed)
|
if (!this.socket || this.socket.closed)
|
||||||
return
|
return;
|
||||||
|
|
||||||
this.socket.complete();
|
this.socket.complete();
|
||||||
}
|
}
|
||||||
|
@ -25,5 +25,13 @@
|
|||||||
Policies
|
Policies
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
routerLink="/filters"
|
||||||
|
routerLinkActive="active"
|
||||||
|
*ngIf="isLoggedIn() && isTTSLoggedIn()">
|
||||||
|
Filters
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
@ -29,7 +29,7 @@ a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
a:hover {
|
a:hover {
|
||||||
background-color: #FCFCFC;
|
background-color: #FAFAFA;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.active {
|
a.active {
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { PolicyComponent } from './policy/policy.component';
|
||||||
|
import { PolicyTableComponent } from './policy-table/policy-table.component';
|
||||||
|
import { PolicyAddFormComponent } from './policy-add-form/policy-add-form.component';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [],
|
declarations: [],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule
|
PolicyComponent, PolicyTableComponent, PolicyAddFormComponent
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class PoliciesModule { }
|
export class PoliciesModule { }
|
@ -1,10 +1,9 @@
|
|||||||
import { AsyncPipe } from '@angular/common';
|
import { AsyncPipe } from '@angular/common';
|
||||||
import { Component, OnInit, Output, EventEmitter } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'
|
import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'
|
||||||
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { Policy } from '../../shared/models/policy';
|
|
||||||
import EventService from '../../shared/services/EventService';
|
import EventService from '../../shared/services/EventService';
|
||||||
import { map, Observable, startWith } from 'rxjs';
|
import { map, Observable, startWith } from 'rxjs';
|
||||||
import { HermesClientService } from '../../hermes-client.service';
|
import { HermesClientService } from '../../hermes-client.service';
|
||||||
@ -15,7 +14,7 @@ const Policies = [
|
|||||||
{ path: "tts.chat.bits.read", description: "To read chat messages with bits via TTS" },
|
{ path: "tts.chat.bits.read", description: "To read chat messages with bits via TTS" },
|
||||||
{ path: "tts.chat.messages.read", description: "To read chat messages via TTS" },
|
{ path: "tts.chat.messages.read", description: "To read chat messages via TTS" },
|
||||||
{ path: "tts.chat.redemptions.read", description: "To read channel point redemption messages via TTS" },
|
{ path: "tts.chat.redemptions.read", description: "To read channel point redemption messages via TTS" },
|
||||||
//{ path: "tts.chat.subscriptions.read", description: "To read chat messages from subscriptions via TTS" },
|
{ path: "tts.chat.subscriptions.read", description: "To read chat messages from subscriptions via TTS" },
|
||||||
{ path: "tts.commands", description: "To execute commands for TTS" },
|
{ path: "tts.commands", description: "To execute commands for TTS" },
|
||||||
{ path: "tts.commands.nightbot", description: "To use !nightbot command" },
|
{ path: "tts.commands.nightbot", description: "To use !nightbot command" },
|
||||||
{ path: "tts.commands.obs", description: "To use !obs command" },
|
{ path: "tts.commands.obs", description: "To use !obs command" },
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="usage">
|
<ng-container matColumnDef="usage">
|
||||||
<th mat-header-cell *matHeaderCellDef>Usage per span</th>
|
<th mat-header-cell *matHeaderCellDef>Usage Rate</th>
|
||||||
<td mat-cell *matCellDef="let policy">
|
<td mat-cell *matCellDef="let policy">
|
||||||
@if (policy.editing) {
|
@if (policy.editing) {
|
||||||
<input type="number" [(ngModel)]="policy.usage" (keypress)="($event.charCode >= 48 && $event.charCode < 58)" />
|
<input type="number" [(ngModel)]="policy.usage" (keypress)="($event.charCode >= 48 && $event.charCode < 58)" />
|
||||||
|
@ -1,7 +1,3 @@
|
|||||||
div {
|
|
||||||
background-color: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
h4 {
|
h4 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
@ -1,10 +1,8 @@
|
|||||||
import { Component, Inject, NgZone, OnDestroy, OnInit, PLATFORM_ID } from '@angular/core';
|
import { Component, Inject, OnDestroy, OnInit, PLATFORM_ID } from '@angular/core';
|
||||||
import { PolicyAddFormComponent } from "../policy-add-form/policy-add-form.component";
|
import { PolicyAddFormComponent } from "../policy-add-form/policy-add-form.component";
|
||||||
import { PolicyTableComponent } from "../policy-table/policy-table.component";
|
import { PolicyTableComponent } from "../policy-table/policy-table.component";
|
||||||
import { Policy, PolicyScope } from '../../shared/models/policy';
|
import { Policy, PolicyScope } from '../../shared/models/policy';
|
||||||
import { DatePipe, isPlatformBrowser } from '@angular/common';
|
import { isPlatformBrowser } from '@angular/common';
|
||||||
import { OAuthService } from 'angular-oauth2-oidc';
|
|
||||||
import { Subscription } from 'rxjs';
|
|
||||||
import { HermesClientService } from '../../hermes-client.service';
|
import { HermesClientService } from '../../hermes-client.service';
|
||||||
import { Router, RouterModule } from '@angular/router';
|
import { Router, RouterModule } from '@angular/router';
|
||||||
|
|
||||||
@ -17,14 +15,10 @@ import { Router, RouterModule } from '@angular/router';
|
|||||||
})
|
})
|
||||||
export class PolicyComponent implements OnInit, OnDestroy {
|
export class PolicyComponent implements OnInit, OnDestroy {
|
||||||
private isBrowser: boolean;
|
private isBrowser: boolean;
|
||||||
private ngZone: NgZone;
|
|
||||||
private subscription: Subscription | undefined;
|
|
||||||
items: Policy[];
|
items: Policy[];
|
||||||
pipe = new DatePipe('en-US')
|
|
||||||
|
|
||||||
|
|
||||||
constructor(private client: HermesClientService, private oauthService: OAuthService, private router: Router, ngZone: NgZone, @Inject(PLATFORM_ID) private platformId: Object) {
|
constructor(private client: HermesClientService, private router: Router, @Inject(PLATFORM_ID) private platformId: Object) {
|
||||||
this.ngZone = ngZone;
|
|
||||||
this.isBrowser = isPlatformBrowser(this.platformId)
|
this.isBrowser = isPlatformBrowser(this.platformId)
|
||||||
|
|
||||||
this.items = []
|
this.items = []
|
||||||
@ -42,12 +36,8 @@ export class PolicyComponent implements OnInit, OnDestroy {
|
|||||||
this.router.navigate(["/tts-login"]);
|
this.router.navigate(["/tts-login"]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.subscription = this.client.connect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
if (this.subscription)
|
|
||||||
this.subscription.unsubscribe()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
13
src/app/shared/models/filter.ts
Normal file
13
src/app/shared/models/filter.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
export enum FilterFlag {
|
||||||
|
None = 0,
|
||||||
|
IgnoreCase = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Filter {
|
||||||
|
id: string;
|
||||||
|
search: string;
|
||||||
|
replace: string;
|
||||||
|
user_id: string;
|
||||||
|
flag: FilterFlag;
|
||||||
|
is_regex: boolean;
|
||||||
|
}
|
@ -25,7 +25,7 @@ export class ApiAuthenticationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getImpersonatedId() {
|
getImpersonatedId() {
|
||||||
return this.user.impersonation?.id;
|
return this.user?.impersonation?.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
getUsername() {
|
getUsername() {
|
||||||
@ -45,7 +45,6 @@ export class ApiAuthenticationService {
|
|||||||
'Authorization': 'Bearer ' + jwt
|
'Authorization': 'Bearer ' + jwt
|
||||||
}
|
}
|
||||||
}).subscribe((data: any) => {
|
}).subscribe((data: any) => {
|
||||||
console.log('jwt validation', data);
|
|
||||||
this.updateAuthenticated(data?.authenticated, data?.user);
|
this.updateAuthenticated(data?.authenticated, data?.user);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
<h2 mat-dialog-title>TTS Filter</h2>
|
||||||
|
<mat-dialog-content>
|
||||||
|
<mat-form-field>
|
||||||
|
<mat-label>Search</mat-label>
|
||||||
|
<input matInput [(ngModel)]="search" />
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field>
|
||||||
|
<mat-label>Replace</mat-label>
|
||||||
|
<input matInput [(ngModel)]="replace" />
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-dialog-content>
|
||||||
|
<mat-dialog-actions>
|
||||||
|
<button mat-button (click)="onCancelClick()">Cancel</button>
|
||||||
|
<button mat-button [mat-dialog-close]="onSaveClick()" cdkFocusInitial>Save</button>
|
||||||
|
</mat-dialog-actions>
|
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { FilterItemEditComponent } from './filter-item-edit.component';
|
||||||
|
|
||||||
|
describe('FilterItemEditComponent', () => {
|
||||||
|
let component: FilterItemEditComponent;
|
||||||
|
let fixture: ComponentFixture<FilterItemEditComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [FilterItemEditComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(FilterItemEditComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,42 @@
|
|||||||
|
import { Component, inject, model } from '@angular/core';
|
||||||
|
import { MatDialogRef, MAT_DIALOG_DATA, MatDialogActions, MatDialogClose, MatDialogTitle, MatDialogContent } from '@angular/material/dialog';
|
||||||
|
import { Filter } from '../../shared/models/filter';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
|
import { MatInputModule } from '@angular/material/input';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'tts-filter-item-edit',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
FormsModule,
|
||||||
|
MatButtonModule,
|
||||||
|
MatDialogActions,
|
||||||
|
MatDialogClose,
|
||||||
|
MatDialogContent,
|
||||||
|
MatDialogTitle,
|
||||||
|
MatFormFieldModule,
|
||||||
|
MatInputModule,
|
||||||
|
],
|
||||||
|
templateUrl: './filter-item-edit.component.html',
|
||||||
|
styleUrl: './filter-item-edit.component.scss'
|
||||||
|
})
|
||||||
|
export class FilterItemEditComponent {
|
||||||
|
readonly dialogRef = inject(MatDialogRef<FilterItemEditComponent>);
|
||||||
|
readonly data = inject<Filter>(MAT_DIALOG_DATA);
|
||||||
|
readonly search = model(this.data.search);
|
||||||
|
readonly replace = model(this.data.replace);
|
||||||
|
readonly flag = model(this.data.flag);
|
||||||
|
|
||||||
|
onSaveClick(): Filter {
|
||||||
|
this.data.search = this.search();
|
||||||
|
this.data.replace = this.replace();
|
||||||
|
this.data.flag = this.flag();
|
||||||
|
return this.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancelClick(): void {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
18
src/app/tts-filters/filter-item/filter-item.component.html
Normal file
18
src/app/tts-filters/filter-item/filter-item.component.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
{{item.search}}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{{item.replace}}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<mat-menu #filterMenu>
|
||||||
|
<button mat-menu-item (click)="openDialog()">Edit</button>
|
||||||
|
<button mat-menu-item (click)="onDelete.emit(item)">Delete</button>
|
||||||
|
</mat-menu>
|
||||||
|
|
||||||
|
<button mat-icon-button [matMenuTriggerFor]="filterMenu">
|
||||||
|
<mat-icon>more_vert</mat-icon>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
33
src/app/tts-filters/filter-item/filter-item.component.scss
Normal file
33
src/app/tts-filters/filter-item/filter-item.component.scss
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
input {
|
||||||
|
display: inline;
|
||||||
|
font-size: large;
|
||||||
|
row-gap: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
|
||||||
|
li {
|
||||||
|
list-style-type: none;
|
||||||
|
white-space: pre;
|
||||||
|
text-align: justify;
|
||||||
|
text-wrap: wrap;
|
||||||
|
|
||||||
|
> button {
|
||||||
|
background: #dddddd;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
:hover {
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
li:nth-child(1),
|
||||||
|
li:nth-child(2) {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { FilterItemComponent } from './filter-item.component';
|
||||||
|
|
||||||
|
describe('FilterItemComponent', () => {
|
||||||
|
let component: FilterItemComponent;
|
||||||
|
let fixture: ComponentFixture<FilterItemComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [FilterItemComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(FilterItemComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
50
src/app/tts-filters/filter-item/filter-item.component.ts
Normal file
50
src/app/tts-filters/filter-item/filter-item.component.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import { Component, EventEmitter, inject, Input, OnInit, Output, signal } from '@angular/core';
|
||||||
|
import { Filter, FilterFlag } from '../../shared/models/filter';
|
||||||
|
import { MatCardModule } from '@angular/material/card';
|
||||||
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import { FilterItemEditComponent } from '../filter-item-edit/filter-item-edit.component';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { HermesClientService } from '../../hermes-client.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'tts-filter-item',
|
||||||
|
standalone: true,
|
||||||
|
imports: [MatButtonModule, MatCardModule, MatMenuModule, MatIconModule],
|
||||||
|
templateUrl: './filter-item.component.html',
|
||||||
|
styleUrl: './filter-item.component.scss'
|
||||||
|
})
|
||||||
|
export class FilterItemComponent implements OnInit {
|
||||||
|
@Input() item: Filter = { id: "", user_id: "", search: "", replace: "", flag: FilterFlag.None, is_regex: false };
|
||||||
|
@Output() onDelete = new EventEmitter<Filter>();
|
||||||
|
readonly client = inject(HermesClientService);
|
||||||
|
readonly dialog = inject(MatDialog);
|
||||||
|
private loaded = false;
|
||||||
|
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.loaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
openDialog(): void {
|
||||||
|
if (!this.loaded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const dialogRef = this.dialog.open(FilterItemEditComponent, {
|
||||||
|
data: { id: this.item.id, search: this.item.search, replace: this.item.replace },
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef.afterClosed().subscribe(result => {
|
||||||
|
if (result !== undefined) {
|
||||||
|
console.log('update filter', result);
|
||||||
|
this.client.first(d => d.op == 4 && d.d.request.type == 'update_tts_filter' && d.d.data.id == this.item.id)
|
||||||
|
?.subscribe(_ => {
|
||||||
|
this.item.search = result.search;
|
||||||
|
this.item.replace = result.replace;
|
||||||
|
});
|
||||||
|
this.client.updateTTSFilter(this.item.id, result.search, result.replace);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
18
src/app/tts-filters/filter-list/filter-list.component.html
Normal file
18
src/app/tts-filters/filter-list/filter-list.component.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<div>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<ul class="header">
|
||||||
|
<li>Search</li>
|
||||||
|
<li>Replace</li>
|
||||||
|
<li></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
@for (filter of filters; track $index) {
|
||||||
|
<li>
|
||||||
|
<tts-filter-item
|
||||||
|
[item]="filter"
|
||||||
|
(onDelete)="deleteFilter($event)" />
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</div>
|
40
src/app/tts-filters/filter-list/filter-list.component.scss
Normal file
40
src/app/tts-filters/filter-list/filter-list.component.scss
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
ul {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: block;
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 0.75em 1em;
|
||||||
|
border-bottom: 1px solid #aaaaaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
li:first-child {
|
||||||
|
padding: 0 1em;
|
||||||
|
border-bottom: 0 solid #aaaaaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
li:last-child {
|
||||||
|
border-bottom: 0 solid #aaaaaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
|
||||||
|
li {
|
||||||
|
border-bottom: 0 solid #aaaaaa;
|
||||||
|
font-weight: 500;
|
||||||
|
list-style-type: none;
|
||||||
|
white-space: pre;
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
|
||||||
|
li:nth-child(1),
|
||||||
|
li:nth-child(2) {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { FilterListComponent } from './filter-list.component';
|
||||||
|
|
||||||
|
describe('FilterListComponent', () => {
|
||||||
|
let component: FilterListComponent;
|
||||||
|
let fixture: ComponentFixture<FilterListComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [FilterListComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(FilterListComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
22
src/app/tts-filters/filter-list/filter-list.component.ts
Normal file
22
src/app/tts-filters/filter-list/filter-list.component.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { Component, EventEmitter, inject, Input, Output } from '@angular/core';
|
||||||
|
import { FilterItemComponent } from '../filter-item/filter-item.component';
|
||||||
|
import { Filter, FilterFlag } from '../../shared/models/filter';
|
||||||
|
import { HermesClientService } from '../../hermes-client.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'tts-filter-list',
|
||||||
|
standalone: true,
|
||||||
|
imports: [FilterItemComponent],
|
||||||
|
templateUrl: './filter-list.component.html',
|
||||||
|
styleUrl: './filter-list.component.scss'
|
||||||
|
})
|
||||||
|
export class FilterListComponent {
|
||||||
|
@Input() filters: Filter[] = [];
|
||||||
|
client = inject(HermesClientService);
|
||||||
|
|
||||||
|
deleteFilter(e: any): void {
|
||||||
|
console.log('deleting', e);
|
||||||
|
this.client.deleteTTSFilter(e.id);
|
||||||
|
this.filters = this.filters.filter(f => f.id != e.id);
|
||||||
|
}
|
||||||
|
}
|
14
src/app/tts-filters/filters/filters.component.html
Normal file
14
src/app/tts-filters/filters/filters.component.html
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<main>
|
||||||
|
<article>
|
||||||
|
<h3>Filters</h3>
|
||||||
|
<div>
|
||||||
|
<button mat-fab aria-label="Add a filter" (click)="openDialog()">
|
||||||
|
<mat-icon>add</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<div>
|
||||||
|
<tts-filter-list
|
||||||
|
[filters]="items" />
|
||||||
|
</div>
|
||||||
|
</main>
|
5
src/app/tts-filters/filters/filters.component.scss
Normal file
5
src/app/tts-filters/filters/filters.component.scss
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
article {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 70%;
|
||||||
|
}
|
23
src/app/tts-filters/filters/filters.component.spec.ts
Normal file
23
src/app/tts-filters/filters/filters.component.spec.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { FiltersComponent } from './filters.component';
|
||||||
|
|
||||||
|
describe('FiltersComponent', () => {
|
||||||
|
let component: FiltersComponent;
|
||||||
|
let fixture: ComponentFixture<FiltersComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [FiltersComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(FiltersComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
91
src/app/tts-filters/filters/filters.component.ts
Normal file
91
src/app/tts-filters/filters/filters.component.ts
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
import { Component, inject, Inject, Input, OnDestroy, OnInit, PLATFORM_ID, signal } from '@angular/core';
|
||||||
|
import { FilterListComponent } from "../filter-list/filter-list.component";
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import { HermesClientService } from '../../hermes-client.service';
|
||||||
|
import { Filter } from '../../shared/models/filter';
|
||||||
|
import { isPlatformBrowser } from '@angular/common';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { FilterItemEditComponent } from '../filter-item-edit/filter-item-edit.component';
|
||||||
|
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'filters',
|
||||||
|
standalone: true,
|
||||||
|
imports: [FilterListComponent, MatButtonModule, MatIconModule],
|
||||||
|
templateUrl: './filters.component.html',
|
||||||
|
styleUrl: './filters.component.scss'
|
||||||
|
})
|
||||||
|
export class FiltersComponent implements OnInit, OnDestroy {
|
||||||
|
private isBrowser: boolean;
|
||||||
|
readonly dialog = inject(MatDialog);
|
||||||
|
items: Filter[];
|
||||||
|
|
||||||
|
|
||||||
|
constructor(private client: HermesClientService, private router: Router, @Inject(PLATFORM_ID) private platformId: Object) {
|
||||||
|
this.isBrowser = isPlatformBrowser(this.platformId);
|
||||||
|
|
||||||
|
this.items = []
|
||||||
|
this.client.subscribe(4, d => {
|
||||||
|
const type = d.request.type;
|
||||||
|
console.log('filters', type, d.data);
|
||||||
|
|
||||||
|
if (type == 'get_tts_word_filters') {
|
||||||
|
this.items = d.data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (d.request.nounce == client.session_id) {
|
||||||
|
console.log('from us. ignore.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (type == 'create_tts_filter') {
|
||||||
|
console.log('create filter', d.data);
|
||||||
|
this.items = [d.data, ...this.items];
|
||||||
|
} else if (type == 'delete_tts_filter') {
|
||||||
|
console.log('delete filter', d.data);
|
||||||
|
this.items = this.items.filter(i => i.id != d.data.id);
|
||||||
|
} else if (type == 'update_tts_filter') {
|
||||||
|
console.log('update filter', d.data);
|
||||||
|
const filter = this.items.find(f => f.id == d.data.id);
|
||||||
|
if (filter == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
filter.search = d.data.search;
|
||||||
|
filter.replace = d.data.replace;
|
||||||
|
filter.flag = d.data.flag || 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.client.fetchFilters();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
if (!this.isBrowser)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!this.client.logged_in) {
|
||||||
|
this.router.navigate(["/tts-login"]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
}
|
||||||
|
|
||||||
|
openDialog(): void {
|
||||||
|
const dialogRef = this.dialog.open(FilterItemEditComponent, {
|
||||||
|
data: { search: '', replace: '' },
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef.afterClosed().subscribe((result: any) => {
|
||||||
|
if (result !== undefined) {
|
||||||
|
console.log('filters create result', result);
|
||||||
|
this.client.first(d => d.op == 4 && d.d.request.type == 'create_tts_filter' && d.d.data.search == result.search && d.d.data.replace == result.replace)
|
||||||
|
?.subscribe(d => {
|
||||||
|
console.log('adding filter', d.d.data);
|
||||||
|
this.items = [d.d.data, ...this.items];
|
||||||
|
});
|
||||||
|
this.client.createTTSFilter(result.search, result.replace);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
12
src/app/tts-filters/tts-filters.module.ts
Normal file
12
src/app/tts-filters/tts-filters.module.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { FiltersComponent } from './filters/filters.component';
|
||||||
|
import { FilterListComponent } from './filter-list/filter-list.component';
|
||||||
|
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [],
|
||||||
|
imports: [
|
||||||
|
FiltersComponent, FilterListComponent
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class TtsFiltersModule { }
|
Loading…
x
Reference in New Issue
Block a user