diff --git a/kdb-web/src/app/app.component.ts b/kdb-web/src/app/app.component.ts index 8b919479..ce1e4bb1 100644 --- a/kdb-web/src/app/app.component.ts +++ b/kdb-web/src/app/app.component.ts @@ -1,29 +1,27 @@ -import { Component, OnInit } from "@angular/core"; +import { Component, OnDestroy, OnInit } from "@angular/core"; import { TranslateService } from "@ngx-translate/core"; import { PrimeNGConfig } from "primeng/api"; import { AuthService } from "./services/auth/auth.service"; import { SocketService } from "./services/socket/socket.service"; import { ThemeService } from "./services/theme/theme.service"; -import { ActivatedRoute, Router } from "@angular/router"; -import { SpinnerService } from "./services/spinner/spinner.service"; -import { DataService } from "./services/data/data.service"; -import { SidebarService } from "./services/sidebar/sidebar.service"; -import { Server } from "./models/data/server.model"; -import { Queries } from "./models/graphql/queries.model"; -import { Query } from "./models/graphql/query.model"; +import { Subject } from "rxjs"; +import { Themes } from "./models/view/themes.enum"; +import { takeUntil } from "rxjs/operators"; @Component({ selector: "app-root", templateUrl: "./app.component.html", styleUrls: ["./app.component.scss"] }) -export class AppComponent implements OnInit { +export class AppComponent implements OnInit, OnDestroy { - themeName!: string; - sidebarWidth!: string; + themeName: string = Themes.Default; + sidebarWidth: string = '175px'; isLoggedIn: boolean = false; + private unsubscriber = new Subject(); + constructor( private authService: AuthService, private themeService: ThemeService, @@ -31,13 +29,19 @@ export class AppComponent implements OnInit { private translateService: TranslateService, private config: PrimeNGConfig, ) { - this.themeService.sidebarWidth$.subscribe(value => { + this.themeService.sidebarWidth$.pipe( + takeUntil(this.unsubscriber) + ).subscribe(value => { this.sidebarWidth = value; }); - this.themeService.themeName$.subscribe(value => { + this.themeService.themeName$.pipe( + takeUntil(this.unsubscriber) + ).subscribe(value => { this.themeName = value; }); - this.authService.isLoggedIn$.subscribe(value => { + this.authService.isLoggedIn$.pipe( + takeUntil(this.unsubscriber) + ).subscribe(value => { this.isLoggedIn = value; }); } @@ -49,6 +53,11 @@ export class AppComponent implements OnInit { this.socket.startSocket(); } + ngOnDestroy() { + this.unsubscriber.next(); + this.unsubscriber.unsubscribe(); + } + loadLang(): void { let lang = localStorage.getItem(`default_lang`); if (!lang) { diff --git a/kdb-web/src/app/components/sidebar/sidebar.component.ts b/kdb-web/src/app/components/sidebar/sidebar.component.ts index 955bec11..82df2511 100644 --- a/kdb-web/src/app/components/sidebar/sidebar.component.ts +++ b/kdb-web/src/app/components/sidebar/sidebar.component.ts @@ -1,19 +1,21 @@ -import { Component, OnInit } from "@angular/core"; +import { Component, OnDestroy, OnInit } from "@angular/core"; import { TranslateService } from "@ngx-translate/core"; import { MenuItem } from "primeng/api"; import { AuthService } from "src/app/services/auth/auth.service"; import { ThemeService } from "src/app/services/theme/theme.service"; import { SidebarService } from "../../services/sidebar/sidebar.service"; +import { Subject } from "rxjs"; +import { takeUntil } from "rxjs/operators"; @Component({ selector: "app-sidebar", templateUrl: "./sidebar.component.html", styleUrls: ["./sidebar.component.scss"] }) -export class SidebarComponent implements OnInit { +export class SidebarComponent implements OnInit, OnDestroy { - isSidebarOpen!: boolean; - menuItems!: MenuItem[]; + menuItems: MenuItem[]= []; + private unsubscriber = new Subject(); constructor( private authService: AuthService, @@ -21,7 +23,9 @@ export class SidebarComponent implements OnInit { private themeService: ThemeService, private sidebar: SidebarService ) { - this.sidebar.menuItems$.subscribe(value => { + this.sidebar.menuItems$.pipe( + takeUntil(this.unsubscriber) + ).subscribe(value => { this.menuItems = value; }); } @@ -30,4 +34,9 @@ export class SidebarComponent implements OnInit { this.themeService.loadMenu(); } + ngOnDestroy() { + this.unsubscriber.next(); + this.unsubscriber.complete(); + } + } diff --git a/kdb-web/src/app/models/data/data.model.ts b/kdb-web/src/app/models/data/data.model.ts index 2a6a82b8..dcd3c42c 100644 --- a/kdb-web/src/app/models/data/data.model.ts +++ b/kdb-web/src/app/models/data/data.model.ts @@ -1,4 +1,4 @@ export interface Data { - createdAt: string; - modifiedAt: string; + createdAt?: string; + modifiedAt?: string; } diff --git a/kdb-web/src/app/models/data/discord.model.ts b/kdb-web/src/app/models/data/discord.model.ts index 6e8bc0b0..680225ef 100644 --- a/kdb-web/src/app/models/data/discord.model.ts +++ b/kdb-web/src/app/models/data/discord.model.ts @@ -2,9 +2,9 @@ export interface Guild { id?: string; name?: string; - channels: [Channel] - roles: [Role] - emojis: [Emoji] + channels: Channel[]; + roles: Role[]; + emojis: Emoji[]; } export interface Channel { diff --git a/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.ts b/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.ts index b4ac6706..390b4531 100644 --- a/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.ts +++ b/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from "@angular/core"; -import { catchError, debounceTime } from "rxjs/operators"; +import { catchError, debounceTime, takeUntil } from "rxjs/operators"; import { AuthRoles } from "src/app/models/auth/auth-roles.enum"; import { AuthUserDTO } from "src/app/models/auth/auth-user.dto"; import { AuthService } from "src/app/services/auth/auth.service"; @@ -13,7 +13,7 @@ import { ErrorDTO } from "src/app/models/error/error-dto"; import { FormBuilder, FormControl, FormGroup } from "@angular/forms"; import { AuthUserSelectCriterion } from "src/app/models/selection/auth-user/auth-user-select-criterion.dto"; import { LazyLoadEvent } from "primeng/api"; -import { throwError } from "rxjs"; +import { Subject, throwError } from "rxjs"; import { TranslateService } from "@ngx-translate/core"; @@ -62,6 +62,8 @@ export class AuthUserComponent implements OnInit { searchCriterions!: AuthUserSelectCriterion; totalRecords!: number; + private unsubscriber = new Subject(); + constructor( private authService: AuthService, private spinnerService: SpinnerService, @@ -97,6 +99,7 @@ export class AuthUserComponent implements OnInit { }); this.filterForm.valueChanges.pipe( + takeUntil(this.unsubscriber), debounceTime(600) ).subscribe(changes => { if (changes.firstName) { diff --git a/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.ts b/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.ts index 5d266fd8..e44b0902 100644 --- a/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.ts +++ b/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.ts @@ -1,30 +1,30 @@ -import {Component, OnInit} from "@angular/core"; -import {FormBuilder, FormControl, FormGroup} from "@angular/forms"; -import {Router} from "@angular/router"; -import {TranslateService} from "@ngx-translate/core"; -import {debounceTime, throwError} from "rxjs"; -import {ConfirmationDialogService} from "src/app/services/confirmation-dialog/confirmation-dialog.service"; -import {DataService} from "src/app/services/data/data.service"; -import {SpinnerService} from "src/app/services/spinner/spinner.service"; -import {ToastService} from "src/app/services/toast/toast.service"; -import {Server, ServerFilter} from "../../../../../models/data/server.model"; -import {catchError} from "rxjs/operators"; -import {Queries} from "../../../../../models/graphql/queries.model"; -import {Page} from "../../../../../models/graphql/filter/page.model"; -import {Sort} from "../../../../../models/graphql/filter/sort.model"; -import {Query} from "../../../../../models/graphql/query.model"; -import {SidebarService} from "../../../../../services/sidebar/sidebar.service"; +import { Component, OnDestroy, OnInit } from "@angular/core"; +import { FormBuilder, FormControl, FormGroup } from "@angular/forms"; +import { Router } from "@angular/router"; +import { TranslateService } from "@ngx-translate/core"; +import { debounceTime, Subject, throwError } from "rxjs"; +import { ConfirmationDialogService } from "src/app/services/confirmation-dialog/confirmation-dialog.service"; +import { DataService } from "src/app/services/data/data.service"; +import { SpinnerService } from "src/app/services/spinner/spinner.service"; +import { ToastService } from "src/app/services/toast/toast.service"; +import { Server, ServerFilter } from "../../../../../models/data/server.model"; +import { catchError, takeUntil } from "rxjs/operators"; +import { Queries } from "../../../../../models/graphql/queries.model"; +import { Page } from "../../../../../models/graphql/filter/page.model"; +import { Sort } from "../../../../../models/graphql/filter/sort.model"; +import { Query } from "../../../../../models/graphql/query.model"; +import { SidebarService } from "../../../../../services/sidebar/sidebar.service"; @Component({ selector: "app-dashboard", templateUrl: "./dashboard.component.html", styleUrls: ["./dashboard.component.scss"] }) -export class DashboardComponent implements OnInit { +export class DashboardComponent implements OnInit, OnDestroy { servers: Server[] = []; - totalRecords!: number; + totalRecords: number = 0; filter: ServerFilter = {}; @@ -33,12 +33,14 @@ export class DashboardComponent implements OnInit { pageSize: 10 }; - sort!: Sort; + sort: Sort = {}; filterForm!: FormGroup<{ name: FormControl, }>; + private unsubscriber = new Subject(); + constructor( private data: DataService, private spinnerService: SpinnerService, @@ -58,12 +60,18 @@ export class DashboardComponent implements OnInit { this.loadNextPage(); } + public ngOnDestroy() { + this.unsubscriber.next(); + this.unsubscriber.complete(); + } + setFilterForm() { this.filterForm = this.fb.group({ name: new FormControl(null) }); this.filterForm.valueChanges.pipe( + takeUntil(this.unsubscriber), debounceTime(600) ).subscribe(async changes => { if (changes.name == "") { diff --git a/kdb-web/src/app/modules/view/server/auto-role/components/auto-roles-rules/auto-roles-rules.component.ts b/kdb-web/src/app/modules/view/server/auto-role/components/auto-roles-rules/auto-roles-rules.component.ts index 2c351051..62a5de17 100644 --- a/kdb-web/src/app/modules/view/server/auto-role/components/auto-roles-rules/auto-roles-rules.component.ts +++ b/kdb-web/src/app/modules/view/server/auto-role/components/auto-roles-rules/auto-roles-rules.component.ts @@ -17,11 +17,11 @@ import { SidebarService } from "../../../../../../services/sidebar/sidebar.servi import { AutoRoleRuleQuery, SingleDiscordQuery } from "../../../../../../models/graphql/query.model"; import { Queries } from "../../../../../../models/graphql/queries.model"; import { Server } from "../../../../../../models/data/server.model"; -import { catchError, debounceTime } from "rxjs/operators"; +import { catchError, debounceTime, takeUntil } from "rxjs/operators"; import { Table } from "primeng/table"; import { AutoRoleMutationResult, AutoRoleRuleMutationResult } from "../../../../../../models/graphql/result.model"; import { Mutations } from "../../../../../../models/graphql/mutations.model"; -import { throwError } from "rxjs"; +import { Subject, throwError } from "rxjs"; @Component({ selector: "app-auto-roles-rules", @@ -30,8 +30,8 @@ import { throwError } from "rxjs"; }) export class AutoRolesRulesComponent implements OnInit { - rules!: AutoRoleRule[]; - guild!: Guild; + rules: AutoRoleRule[] = []; + guild: Guild = { channels: [], emojis: [], roles: [] }; emojis: MenuItem[] = []; roles: MenuItem[] = []; loading = true; @@ -63,7 +63,8 @@ export class AutoRolesRulesComponent implements OnInit { sortDirection: undefined }; - totalRecords!: number; + totalRecords: number = 0; + private unsubscriber = new Subject(); constructor( private authService: AuthService, @@ -145,6 +146,7 @@ export class AutoRolesRulesComponent implements OnInit { }); this.filterForm.valueChanges.pipe( + takeUntil(this.unsubscriber), debounceTime(600) ).subscribe(changes => { if (changes.id) { diff --git a/kdb-web/src/app/modules/view/server/auto-role/components/auto-roles/auto-roles.component.ts b/kdb-web/src/app/modules/view/server/auto-role/components/auto-roles/auto-roles.component.ts index 838a8c59..1631a811 100644 --- a/kdb-web/src/app/modules/view/server/auto-role/components/auto-roles/auto-roles.component.ts +++ b/kdb-web/src/app/modules/view/server/auto-role/components/auto-roles/auto-roles.component.ts @@ -14,11 +14,11 @@ import { SidebarService } from "../../../../../../services/sidebar/sidebar.servi import { ActivatedRoute } from "@angular/router"; import { AutoRoleQuery, SingleDiscordQuery } from "../../../../../../models/graphql/query.model"; import { Queries } from "../../../../../../models/graphql/queries.model"; -import { catchError, debounceTime } from "rxjs/operators"; +import { catchError, debounceTime, takeUntil } from "rxjs/operators"; import { Table } from "primeng/table"; import { AutoRoleMutationResult } from "../../../../../../models/graphql/result.model"; import { Mutations } from "../../../../../../models/graphql/mutations.model"; -import { throwError } from "rxjs"; +import { Subject, throwError } from "rxjs"; import { AutoRole, AutoRoleFilter } from "../../../../../../models/data/auto_role.model"; import { ChannelType, Guild } from "../../../../../../models/data/discord.model"; import { Server } from "../../../../../../models/data/server.model"; @@ -29,9 +29,9 @@ import { Server } from "../../../../../../models/data/server.model"; styleUrls: ["./auto-roles.component.scss"] }) export class AutoRolesComponent implements OnInit { - auto_roles!: AutoRole[]; - guild!: Guild; - channels!: MenuItem[]; + auto_roles: AutoRole[] = []; + guild: Guild = { channels: [], emojis: [], roles: [] }; + channels: MenuItem[] = []; loading = true; clonedUsers: { [s: string]: User; } = {}; @@ -61,6 +61,7 @@ export class AutoRolesComponent implements OnInit { }; totalRecords!: number; + private unsubscriber = new Subject(); constructor( private authService: AuthService, @@ -123,6 +124,7 @@ export class AutoRolesComponent implements OnInit { }); this.filterForm.valueChanges.pipe( + takeUntil(this.unsubscriber), debounceTime(600) ).subscribe(changes => { if (changes.id) { diff --git a/kdb-web/src/app/modules/view/server/levels/components/levels/levels.component.html b/kdb-web/src/app/modules/view/server/levels/components/levels/levels.component.html index 8e42c31c..76d01eed 100644 --- a/kdb-web/src/app/modules/view/server/levels/components/levels/levels.component.html +++ b/kdb-web/src/app/modules/view/server/levels/components/levels/levels.component.html @@ -78,7 +78,7 @@
-
{{'view.server.members.headers.actions' | translate}}
+
{{'view.server.levels.headers.actions' | translate}}
diff --git a/kdb-web/src/app/modules/view/server/levels/components/levels/levels.component.ts b/kdb-web/src/app/modules/view/server/levels/components/levels/levels.component.ts index 9ab6b264..e9cead67 100644 --- a/kdb-web/src/app/modules/view/server/levels/components/levels/levels.component.ts +++ b/kdb-web/src/app/modules/view/server/levels/components/levels/levels.component.ts @@ -1,4 +1,4 @@ -import { Component } from "@angular/core"; +import { Component, OnDestroy, OnInit } from "@angular/core"; import { AuthService } from "../../../../../../services/auth/auth.service"; import { SpinnerService } from "../../../../../../services/spinner/spinner.service"; import { ToastService } from "../../../../../../services/toast/toast.service"; @@ -13,20 +13,20 @@ import { Sort, SortDirection } from "../../../../../../models/graphql/filter/sor import { Level, LevelFilter } from "../../../../../../models/data/level.model"; import { LevelListQuery } from "../../../../../../models/graphql/query.model"; import { Queries } from "../../../../../../models/graphql/queries.model"; -import { catchError, debounceTime } from "rxjs/operators"; +import { catchError, debounceTime, takeUntil } from "rxjs/operators"; import { LazyLoadEvent } from "primeng/api"; import { Table } from "primeng/table"; import { User } from "../../../../../../models/data/user.model"; import { LevelMutationResult, UpdateUserMutationResult } from "../../../../../../models/graphql/result.model"; import { Mutations } from "../../../../../../models/graphql/mutations.model"; -import { throwError } from "rxjs"; +import { Subject, throwError } from "rxjs"; @Component({ selector: "app-levels", templateUrl: "./levels.component.html", styleUrls: ["./levels.component.scss"] }) -export class LevelsComponent { +export class LevelsComponent implements OnInit, OnDestroy { public levels!: Level[]; public loading = true; @@ -38,7 +38,7 @@ export class LevelsComponent { name: FormControl, color: FormControl, min_xp: FormControl, - permissions: FormControl, + permissions: FormControl, }>; public filter: LevelFilter = {}; @@ -55,6 +55,8 @@ export class LevelsComponent { public clonedLevels: { [s: string]: Level; } = {}; + private unsubscriber = new Subject(); + public constructor( private authService: AuthService, private spinner: SpinnerService, @@ -74,6 +76,11 @@ export class LevelsComponent { }); } + public ngOnDestroy(): void { + this.unsubscriber.next(); + this.unsubscriber.complete(); + } + public loadNextPage(): void { this.loading = true; this.data.query(Queries.levelQuery, { @@ -93,10 +100,11 @@ export class LevelsComponent { name: new FormControl(null), color: new FormControl(null), min_xp: new FormControl(null), - permissions: new FormControl(null) + permissions: new FormControl(null) }); this.filterForm.valueChanges.pipe( + takeUntil(this.unsubscriber), debounceTime(600) ).subscribe(changes => { if (changes.id) { @@ -229,7 +237,7 @@ export class LevelsComponent { } ).pipe(catchError(err => { this.spinner.hideSpinner(); - this.toastService.error(this.translate.instant("view.server.levels.message.level_delete_failed"), this.translate.instant("view.server.levels.message.level_delete_failedd", { name: level.name })); + this.toastService.error(this.translate.instant("view.server.levels.message.level_delete_failed"), this.translate.instant("view.server.levels.message.level_delete_failed_d", { name: level.name })); return throwError(err); })).subscribe(l => { this.spinner.hideSpinner(); diff --git a/kdb-web/src/app/modules/view/server/members/members.component.ts b/kdb-web/src/app/modules/view/server/members/members.component.ts index a684cb33..a4f3e004 100644 --- a/kdb-web/src/app/modules/view/server/members/members.component.ts +++ b/kdb-web/src/app/modules/view/server/members/members.component.ts @@ -5,7 +5,7 @@ import { SpinnerService } from "../../../../services/spinner/spinner.service"; import { ToastService } from "../../../../services/toast/toast.service"; import { ConfirmationDialogService } from "../../../../services/confirmation-dialog/confirmation-dialog.service"; import { TranslateService } from "@ngx-translate/core"; -import { catchError, debounceTime } from "rxjs/operators"; +import { catchError, debounceTime, takeUntil } from "rxjs/operators"; import { LazyLoadEvent, MenuItem } from "primeng/api"; import { Table } from "primeng/table"; import { User, UserFilter } from "../../../../models/data/user.model"; @@ -15,7 +15,7 @@ import { DataService } from "../../../../services/data/data.service"; import { Page } from "../../../../models/graphql/filter/page.model"; import { Sort, SortDirection } from "../../../../models/graphql/filter/sort.model"; import { Mutations } from "../../../../models/graphql/mutations.model"; -import { throwError } from "rxjs"; +import { Subject, throwError } from "rxjs"; import { UpdateUserMutationResult } from "../../../../models/graphql/result.model"; import { ActivatedRoute } from "@angular/router"; import { Level } from "../../../../models/data/level.model"; @@ -79,6 +79,7 @@ export class MembersComponent implements OnInit { }; totalRecords!: number; + private unsubscriber = new Subject(); constructor( private authService: AuthService, @@ -135,6 +136,7 @@ export class MembersComponent implements OnInit { }); this.filterForm.valueChanges.pipe( + takeUntil(this.unsubscriber), debounceTime(600) ).subscribe(changes => { if (changes.id) { diff --git a/kdb-web/src/app/services/data/data.service.ts b/kdb-web/src/app/services/data/data.service.ts index 6112d96e..54d13057 100644 --- a/kdb-web/src/app/services/data/data.service.ts +++ b/kdb-web/src/app/services/data/data.service.ts @@ -28,7 +28,7 @@ export class DataService { public getServerFromRoute(route: ActivatedRoute): Promise { return new Promise((resolve, reject) => { this.spinner.showSpinner(); - if (!route.snapshot.params["serverId"]) { + if (!route.snapshot.params["serverId"] || route.snapshot.params["serverId"] == "undefined") { this.spinner.hideSpinner(); this.router.navigate(["/dashboard"]); reject(); diff --git a/kdb-web/src/app/services/sidebar/sidebar.service.ts b/kdb-web/src/app/services/sidebar/sidebar.service.ts index de11122f..925e6887 100644 --- a/kdb-web/src/app/services/sidebar/sidebar.service.ts +++ b/kdb-web/src/app/services/sidebar/sidebar.service.ts @@ -18,17 +18,16 @@ export class SidebarService { menuItems$ = new BehaviorSubject(new Array()); server$ = new BehaviorSubject(null); - dashboard!: MenuItem; - serverDashboard!: MenuItem; - serverProfile!: MenuItem; - serverMembers!: MenuItem; - serverAutoRoles!: MenuItem; - serverAutoRoleRules!: MenuItem; - serverLevels!: MenuItem; - serverMenu!: MenuItem; - adminConfig!: MenuItem; - adminUsers!: MenuItem; - adminMenu!: MenuItem; + dashboard: MenuItem = {}; + serverDashboard: MenuItem = {}; + serverProfile: MenuItem = {}; + serverMembers: MenuItem = {}; + serverAutoRoles: MenuItem = {}; + serverLevels: MenuItem = {}; + serverMenu: MenuItem = {}; + adminConfig: MenuItem = {}; + adminUsers: MenuItem = {}; + adminMenu: MenuItem = {}; constructor( private themeService: ThemeService, diff --git a/kdb-web/src/app/services/theme/theme.service.ts b/kdb-web/src/app/services/theme/theme.service.ts index 32d56f4c..c226dd98 100644 --- a/kdb-web/src/app/services/theme/theme.service.ts +++ b/kdb-web/src/app/services/theme/theme.service.ts @@ -12,7 +12,6 @@ export class ThemeService { sidebarWidth = '150px'; isSidebarOpen = false; - hasLangChanged = false; themeName$ = new BehaviorSubject(Themes.Default); isSidebarOpen$ = new BehaviorSubject(true); diff --git a/kdb-web/src/assets/i18n/de.json b/kdb-web/src/assets/i18n/de.json index 26ceea96..840727b6 100644 --- a/kdb-web/src/assets/i18n/de.json +++ b/kdb-web/src/assets/i18n/de.json @@ -294,7 +294,8 @@ "name": "Name", "color": "Farbe", "min_xp": "Min. XP", - "permissions": "Rechte" + "permissions": "Rechte", + "actions": "Aktionen" }, "no_entries_found": "Keine Einträge gefunden", "message": {