diff --git a/kdb-bot/src/bot_data/model/api_key.py b/kdb-bot/src/bot_data/model/api_key.py index 94ce7dfd..39f69677 100644 --- a/kdb-bot/src/bot_data/model/api_key.py +++ b/kdb-bot/src/bot_data/model/api_key.py @@ -69,11 +69,11 @@ class ApiKey(TableABC): return str( f""" INSERT INTO `ApiKeys` ( - `Identifier`, `Key`, {"" if self._creator is None else "`CreatorId`,"} `CreatedAt`, `LastModifiedAt` + `Identifier`, `Key`, `CreatorId`, `CreatedAt`, `LastModifiedAt` ) VALUES ( '{self._identifier}', '{self._key}', - {"" if self._creator is None else f"{self._creator.id},"} + {"NULL" if self._creator is None else f"'{self._creator.id}'"}, '{self._created_at}', '{self._modified_at}' ); @@ -87,7 +87,7 @@ class ApiKey(TableABC): UPDATE `ApiKeys` SET `Identifier` = '{self._identifier}', `Key` = '{self._key}', - {"" if self._creator is None else f"`CreatorId` = {self._creator.id},"} + `CreatorId` = {"NULL" if self._creator is None else f"'{self._creator.id}'"}, `LastModifiedAt` = '{self._modified_at}' WHERE `Id` = {self._id}; """ diff --git a/kdb-bot/src/bot_data/model/auth_user.py b/kdb-bot/src/bot_data/model/auth_user.py index 5ce5914e..9255bede 100644 --- a/kdb-bot/src/bot_data/model/auth_user.py +++ b/kdb-bot/src/bot_data/model/auth_user.py @@ -215,10 +215,10 @@ class AuthUser(TableABC): `EMail`, `Password`, `PasswordSalt`, - {"" if self._refresh_token is None else f"`RefreshToken`,"} - {"" if self._confirmation_id is None else f"`ConfirmationId`,"} - {"" if self._forgot_password_id is None else f"`ForgotPasswordId`,"} - {"" if self._oauth_id is None else f"`OAuthId`,"} + `RefreshToken`, + `ConfirmationId`, + `ForgotPasswordId`, + `OAuthId`, `RefreshTokenExpiryTime`, `AuthRole`, `CreatedAt`, @@ -230,10 +230,10 @@ class AuthUser(TableABC): '{self._email}', '{self._password}', '{self._password_salt}', - {"" if self._refresh_token is None else f"'{self._refresh_token}',"} - {"" if self._confirmation_id is None else f"'{self._confirmation_id}',"} - {"" if self._forgot_password_id is None else f"'{self._forgot_password_id}',"} - {"" if self._oauth_id is None else f"'{self._oauth_id}',"} + {"NULL" if self._refresh_token is None else f"'{self._refresh_token}'"}, + {"NULL" if self._confirmation_id is None else f"'{self._confirmation_id}'"}, + {"NULL" if self._forgot_password_id is None else f"'{self._forgot_password_id}'"}, + {"NULL" if self._oauth_id is None else f"'{self._oauth_id}'"}, '{self._refresh_token_expire_time.isoformat()}', {self._auth_role_id.value}, '{self._created_at}', @@ -252,10 +252,10 @@ class AuthUser(TableABC): `EMail` = '{self._email}', `Password` = '{self._password}', `PasswordSalt` = '{self._password_salt}', - {'' if self._refresh_token is None else f"`RefreshToken` = '{self._refresh_token}',"} - {'' if self._confirmation_id is None else f"'`ConfirmationId` = '{self._confirmation_id}',"} - {'' if self._forgot_password_id is None else f"`ForgotPasswordId` = '{self._forgot_password_id}',"} - {'' if self._oauth_id is None else f"`OAuthId` = '{self._oauth_id}',"} + `RefreshToken` = {"NULL" if self._refresh_token is None else f"'{self._refresh_token}'"}, + `ConfirmationId` = {"NULL" if self._confirmation_id is None else f"'{self._confirmation_id}'"}, + `ForgotPasswordId` = {"NULL" if self._forgot_password_id is None else f"'{self._forgot_password_id}'"}, + `OAuthId` = {"NULL" if self._oauth_id is None else f"'{self._oauth_id}'"}, `RefreshTokenExpiryTime` = '{self._refresh_token_expire_time.isoformat()}', `AuthRole` = {self._auth_role_id.value}, `LastModifiedAt` = '{self._modified_at}' diff --git a/kdb-bot/src/bot_data/model/user.py b/kdb-bot/src/bot_data/model/user.py index 908eff91..c153a979 100644 --- a/kdb-bot/src/bot_data/model/user.py +++ b/kdb-bot/src/bot_data/model/user.py @@ -150,11 +150,11 @@ class User(TableABC): return str( f""" INSERT INTO `Users` ( - `DiscordId`, `XP`, {"" if self._minecraft_id is None else "`MinecraftId`,"} `ServerId`, `CreatedAt`, `LastModifiedAt` + `DiscordId`, `XP`, `MinecraftId`, `ServerId`, `CreatedAt`, `LastModifiedAt` ) VALUES ( {self._discord_id}, {self._xp}, - {"" if self._minecraft_id is None else f"'{self._minecraft_id}',"} + {"NULL" if self._minecraft_id is None else f"'{self._minecraft_id}'"}, {self._server.id}, '{self._created_at}', '{self._modified_at}' @@ -168,7 +168,7 @@ class User(TableABC): f""" UPDATE `Users` SET `XP` = {self._xp}, - {"" if self._minecraft_id is None else f"`MinecraftId` = '{self._minecraft_id}',"} + `MinecraftId` = {"NULL" if self._minecraft_id is None else f"'{self._minecraft_id}'"}, `LastModifiedAt` = '{self._modified_at}' WHERE `UserId` = {self._user_id}; """ diff --git a/kdb-bot/src/bot_data/model/user_joined_game_server.py b/kdb-bot/src/bot_data/model/user_joined_game_server.py index 1a1186e5..e25d6b1d 100644 --- a/kdb-bot/src/bot_data/model/user_joined_game_server.py +++ b/kdb-bot/src/bot_data/model/user_joined_game_server.py @@ -101,12 +101,12 @@ class UserJoinedGameServer(TableABC): return str( f""" INSERT INTO `UserJoinedGameServer` ( - `UserId`, `GameServer`, `JoinedOn`, {"" if self._leaved_on is None else "`LeavedOn`,"} `CreatedAt`, `LastModifiedAt` + `UserId`, `GameServer`, `JoinedOn`, `LeavedOn`, `CreatedAt`, `LastModifiedAt` ) VALUES ( {self._user.id}, '{self._game_server}', '{self._joined_on}', - {"" if self._leaved_on is None else f"'{self._leaved_on}',"} + {"NULL" if self._leaved_on is None else f"'{self._leaved_on}'"}, '{self._created_at}', '{self._modified_at}' ); @@ -118,8 +118,7 @@ class UserJoinedGameServer(TableABC): return str( f""" UPDATE `UserJoinedGameServer` - SET - {"" if self._leaved_on is None else f"`LeavedOn` = '{self._leaved_on}',"} + SET `LeavedOn` = {"NULL" if self._leaved_on is None else f"'{self._leaved_on}'"}, `LastModifiedAt` = '{self._modified_at}' WHERE `Id` = {self._id}; """ diff --git a/kdb-bot/src/bot_data/model/user_joined_server.py b/kdb-bot/src/bot_data/model/user_joined_server.py index 9af3168a..5946104a 100644 --- a/kdb-bot/src/bot_data/model/user_joined_server.py +++ b/kdb-bot/src/bot_data/model/user_joined_server.py @@ -100,11 +100,11 @@ class UserJoinedServer(TableABC): return str( f""" INSERT INTO `UserJoinedServers` ( - `UserId`, `JoinedOn`, {"" if self._leaved_on is None else "`LeavedOn`,"} `CreatedAt`, `LastModifiedAt` + `UserId`, `JoinedOn`, `LeavedOn`, `CreatedAt`, `LastModifiedAt` ) VALUES ( {self._user.id}, '{self._joined_on}', - {"" if self._leaved_on is None else f"'{self._leaved_on}',"} + {"NULL" if self._leaved_on is None else f"'{self._leaved_on}'"}, '{self._created_at}', '{self._modified_at}' ); @@ -116,8 +116,7 @@ class UserJoinedServer(TableABC): return str( f""" UPDATE `UserJoinedServers` - SET - {"" if self._leaved_on is None else f"`LeavedOn` = '{self._leaved_on}',"} + SET `LeavedOn` = {"NULL" if self._leaved_on is None else f"'{self._leaved_on}'"}, `LastModifiedAt` = '{self._modified_at}' WHERE `UserId` = {self._user.id}; """ diff --git a/kdb-bot/src/bot_data/model/user_joined_voice_channel.py b/kdb-bot/src/bot_data/model/user_joined_voice_channel.py index bb69e7cb..928c0341 100644 --- a/kdb-bot/src/bot_data/model/user_joined_voice_channel.py +++ b/kdb-bot/src/bot_data/model/user_joined_voice_channel.py @@ -108,12 +108,12 @@ class UserJoinedVoiceChannel(TableABC): return str( f""" INSERT INTO `UserJoinedVoiceChannel` ( - `UserId`, `DiscordChannelId`, `JoinedOn`, {"" if self._leaved_on is None else "`LeavedOn`,"} `CreatedAt`, `LastModifiedAt` + `UserId`, `DiscordChannelId`, `JoinedOn`, `LeavedOn`, `CreatedAt`, `LastModifiedAt` ) VALUES ( {self._user.id}, {self._channel_id}, '{self._joined_on}', - {"" if self._leaved_on is None else f"'{self._leaved_on}',"} + {"NULL" if self._leaved_on is None else f"'{self._leaved_on}'"}, '{self._created_at}', '{self._modified_at}' ); @@ -125,8 +125,7 @@ class UserJoinedVoiceChannel(TableABC): return str( f""" UPDATE `UserJoinedVoiceChannel` - SET - {"" if self._leaved_on is None else f"`LeavedOn` = '{self._leaved_on}',"} + SET `LeavedOn` = {"NULL" if self._leaved_on is None else f"'{self._leaved_on}'"}, `LastModifiedAt` = '{self._modified_at}' WHERE `JoinId` = {self._join_id}; """ diff --git a/kdb-bot/src/bot_data/service/auth_user_repository_service.py b/kdb-bot/src/bot_data/service/auth_user_repository_service.py index 397c31f8..295e3c2f 100644 --- a/kdb-bot/src/bot_data/service/auth_user_repository_service.py +++ b/kdb-bot/src/bot_data/service/auth_user_repository_service.py @@ -28,7 +28,7 @@ class AuthUserRepositoryService(AuthUserRepositoryABC): @staticmethod def _get_value_from_result(value: any) -> Optional[any]: - if isinstance(value, str) and "null" in value: + if isinstance(value, str) and "NULL" in value: return None return value diff --git a/kdb-bot/src/bot_graphql/mutations/auto_role_mutation.py b/kdb-bot/src/bot_graphql/mutations/auto_role_mutation.py index 28bd9b2d..d936fc6e 100644 --- a/kdb-bot/src/bot_graphql/mutations/auto_role_mutation.py +++ b/kdb-bot/src/bot_graphql/mutations/auto_role_mutation.py @@ -33,9 +33,9 @@ class AutoRoleMutation(QueryABC): def get_new(x: AutoRole): return ( - x.server.id == input["serverId"] - and x.discord_channel_id == input["channelId"] - and x.discord_message_id == input["messageId"] + x.server.id == int(input["serverId"]) + and x.discord_channel_id == int(input["channelId"]) + and x.discord_message_id == int(input["messageId"]) ) return self._auto_roles.get_auto_roles_by_server_id(auto_role.server.id).where(get_new).last() diff --git a/kdb-web/package.json b/kdb-web/package.json index 13ddc1d0..630cd8ce 100644 --- a/kdb-web/package.json +++ b/kdb-web/package.json @@ -1,6 +1,6 @@ { "name": "kdb-web", - "version": "1.0.0", + "version": "1.0.dev220", "scripts": { "ng": "ng", "update-version": "ts-node-esm update-version.ts", 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/models/data/level.model.ts b/kdb-web/src/app/models/data/level.model.ts index 932070a7..f747628f 100644 --- a/kdb-web/src/app/models/data/level.model.ts +++ b/kdb-web/src/app/models/data/level.model.ts @@ -1,5 +1,5 @@ -import { Data } from "./data.model"; -import { Server, ServerFilter } from "./server.model"; +import {Data} from "./data.model"; +import {Server, ServerFilter} from "./server.model"; export interface Level extends Data { id?: number; @@ -12,6 +12,6 @@ export interface Level extends Data { export interface LevelFilter { id?: number; - name?: String; + name?: string; server?: ServerFilter; } diff --git a/kdb-web/src/app/models/graphql/mutations.model.ts b/kdb-web/src/app/models/graphql/mutations.model.ts index 4d10e87d..0cba6ef3 100644 --- a/kdb-web/src/app/models/graphql/mutations.model.ts +++ b/kdb-web/src/app/models/graphql/mutations.model.ts @@ -79,4 +79,46 @@ export class Mutations { } } `; + + static createLevel = ` + mutation createLevel($name: String, $color: String, $minXp: Int, $permissions: String, $serverId: ID) { + level { + createLevel(input: { name: $name, color: $color, minXp: $minXp, permissions: $permissions, serverId: $serverId}) { + id + name + color + minXp + permissions + server { + id + } + } + } + } + `; + + static updateLevel = ` + mutation updateLevel($id: ID, $name: String, $color: String, $minXp: Int, $permissions: String) { + level { + updateLevel(input: { id: $id, name: $name, color: $color, minXp: $minXp, permissions: $permissions }) { + id + name + color + minXp + permissions + } + } + } + `; + + static deleteLevel = ` + mutation deleteLevel($id: ID) { + level { + deleteLevel(id: $id) { + id + name + } + } + } + `; } diff --git a/kdb-web/src/app/models/graphql/queries.model.ts b/kdb-web/src/app/models/graphql/queries.model.ts index 82bb40af..799d88cb 100644 --- a/kdb-web/src/app/models/graphql/queries.model.ts +++ b/kdb-web/src/app/models/graphql/queries.model.ts @@ -26,6 +26,7 @@ export class Queries { static serversQuery = ` query ServerInfo($filter: ServerFilter, $page: Page, $sort: Sort) { + serverCount servers(filter: $filter, page: $page, sort: $sort) { id name @@ -46,112 +47,76 @@ export class Queries { `; static levelQuery = ` - query LevelsList($filter: LevelFilter, $page: Page, $sort: Sort) { - levelCount - levels(filter: $filter, page: $page, sort: $sort) { - id - name - color - minXp - permissions - server { + query LevelsList($serverId: ID, $filter: LevelFilter, $page: Page, $sort: Sort) { + servers(filter: {id: $serverId}) { + levelCount + levels(filter: $filter, page: $page, sort: $sort) { id name + color + minXp + permissions + server { + id + name + } + createdAt + modifiedAt } } } `; static usersQuery = ` - query UsersList($filter: UserFilter, $page: Page, $sort: Sort) { - userCount - users(filter: $filter, page: $page, sort: $sort) { - id - discordId - name - xp - ontime - level { + query UsersList($serverId: ID, $filter: UserFilter, $page: Page, $sort: Sort) { + servers(filter: {id: $serverId}) { + userCount + users(filter: $filter, page: $page, sort: $sort) { id + discordId name - } - server { - id - name - } - leftServer + xp + ontime + minecraftId + level { + id + name + } + leftServer + server { + id + name + } - joinedServerCount - joinedServers { - id - } + joinedServerCount + joinedServers { + id + joinedOn + leavedOn + } - joinedVoiceChannelCount - joinedVoiceChannels { - id - channelId - channelName - } + joinedVoiceChannelCount + joinedVoiceChannels { + id + channelId + channelName + time + joinedOn + leavedOn + } - userJoinedGameServerCount - userJoinedGameServers { - id - gameServer - } + userJoinedGameServerCount + userJoinedGameServers { + id + gameServer + time + joinedOn + leavedOn + } - createdAt - modifiedAt - } - } - `; - - static singleUserQuery = ` - query singleUserQuery($filter: UserFilter) { - users(filter: $filter) { - id - discordId - name - xp - ontime - minecraftId - level { - id - name + createdAt + modifiedAt } - leftServer - server { - id - name - } - - joinedServerCount - joinedServers { - id - joinedOn - leavedOn - } - - joinedVoiceChannelCount - joinedVoiceChannels { - id - channelId - channelName - time - joinedOn - leavedOn - } - - userJoinedGameServerCount - userJoinedGameServers { - id - gameServer - time - joinedOn - leavedOn - } - - createdAt - modifiedAt } } `; diff --git a/kdb-web/src/app/models/graphql/result.model.ts b/kdb-web/src/app/models/graphql/result.model.ts index 5ad5cd8a..d3d6e4a4 100644 --- a/kdb-web/src/app/models/graphql/result.model.ts +++ b/kdb-web/src/app/models/graphql/result.model.ts @@ -1,13 +1,19 @@ import { User } from "../data/user.model"; import { AutoRole, AutoRoleRule } from "../data/auto_role.model"; +import { Level } from "../data/level.model"; +import { Server } from "../data/server.model"; export interface GraphQLResult { - data: any; + data: { + servers?: Server[]; + }; errors?: []; } export interface QueryResult { - data: any; + data: { + servers?: Server[]; + }; } export interface UpdateUserMutationResult { @@ -31,3 +37,11 @@ export interface AutoRoleRuleMutationResult { deleteAutoRoleRule?: AutoRoleRule }; } + +export interface LevelMutationResult { + level: { + createLevel?: Level + updateLevel?: Level + deleteLevel?: Level + }; +} 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 2b6a0251..9254351f 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; @@ -42,7 +42,6 @@ export class AutoRolesRulesComponent implements OnInit { isEditingNew: boolean = false; newAutoRoleTemplate: AutoRoleRule = { - id: 0, createdAt: "", modifiedAt: "" }; @@ -63,7 +62,9 @@ export class AutoRolesRulesComponent implements OnInit { sortDirection: undefined }; - totalRecords!: number; + totalRecords: number = 0; + private unsubscriber = new Subject(); + private server: Server = {}; constructor( private authService: AuthService, @@ -87,7 +88,7 @@ export class AutoRolesRulesComponent implements OnInit { this.setFilterForm(); this.data.getServerFromRoute(this.route).then(server => { - + this.server = server; this.spinner.showSpinner(); if (!this.route.snapshot.params["autoRoleId"]) { this.spinner.hideSpinner(); @@ -121,7 +122,7 @@ export class AutoRolesRulesComponent implements OnInit { public loadNextPage(): void { this.loading = true; this.data.query(Queries.autoRoleRulesQuery, { - id: this.sidebar.server$.value?.id, filter: this.filter, page: this.page, sort: this.sort + serverId: this.server.id, autoRoleId: this.autoRoleId, filter: this.filter, page: this.page, sort: this.sort }, (x: { servers: Server[] }) => { if (!x.servers[0].autoRoles || x.servers[0].autoRoles?.length == 0) { @@ -145,6 +146,7 @@ export class AutoRolesRulesComponent implements OnInit { }); this.filterForm.valueChanges.pipe( + takeUntil(this.unsubscriber), debounceTime(600) ).subscribe(changes => { if (changes.id) { @@ -212,13 +214,14 @@ export class AutoRolesRulesComponent implements OnInit { roleId: newAutoRoleRule.roleId } ).pipe(catchError(err => { + this.isEditingNew = false; this.spinner.hideSpinner(); this.toastService.error(this.translate.instant("view.server.auto_roles.rules.message.auto_role_rule_create_failed"), this.translate.instant("view.server.auto_roles.rules.message.auto_role_rule_create_failed_d")); return throwError(err); })).subscribe(result => { + this.isEditingNew = false; this.spinner.hideSpinner(); this.toastService.success(this.translate.instant("view.server.auto_roles.rules.message.auto_role_rule_created"), this.translate.instant("view.server.auto_roles.rules.message.auto_role_rule_create_d", { id: result.autoRoleRule.createAutoRoleRule?.id })); - this.isEditingNew = false; this.loadNextPage(); }); return; 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 03d6b2f8..48ee380c 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,16 +29,15 @@ 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; } = {}; isEditingNew: boolean = false; newAutoRoleTemplate: AutoRole = { - id: 0, createdAt: "", modifiedAt: "" }; @@ -60,7 +59,9 @@ export class AutoRolesComponent implements OnInit { sortDirection: undefined }; - totalRecords!: number; + totalRecords: number = 0; + private unsubscriber = new Subject(); + private server: Server = {}; constructor( private authService: AuthService, @@ -79,6 +80,7 @@ export class AutoRolesComponent implements OnInit { this.setFilterForm(); this.data.getServerFromRoute(this.route).then(server => { + this.server = server; this.spinner.showSpinner(); this.data.query(Queries.guildsQuery, { filter: { @@ -101,7 +103,7 @@ export class AutoRolesComponent implements OnInit { public loadNextPage(): void { this.loading = true; this.data.query(Queries.autoRolesQuery, { - id: this.sidebar.server$.value?.id, filter: this.filter, page: this.page, sort: this.sort + serverId: this.server.id, filter: this.filter, page: this.page, sort: this.sort }, (x: { servers: Server[] }) => { return x.servers[0]; @@ -123,6 +125,7 @@ export class AutoRolesComponent implements OnInit { }); this.filterForm.valueChanges.pipe( + takeUntil(this.unsubscriber), debounceTime(600) ).subscribe(changes => { if (changes.id) { @@ -190,15 +193,17 @@ export class AutoRolesComponent implements OnInit { this.spinner.showSpinner(); this.data.mutation(Mutations.createAutoRole, { - serverId: this.sidebar.server$.value?.id, + serverId: this.server.id, channelId: newAutoRole.channelId, messageId: newAutoRole.messageId } ).pipe(catchError(err => { + this.isEditingNew = false; this.spinner.hideSpinner(); this.toastService.error(this.translate.instant("view.server.auto_roles.message.auto_role_create_failed"), this.translate.instant("view.server.auto_roles.message.auto_role_create_failed_d")); return throwError(err); })).subscribe(result => { + this.isEditingNew = false; this.spinner.hideSpinner(); this.toastService.success(this.translate.instant("view.server.auto_roles.message.auto_role_created"), this.translate.instant("view.server.auto_roles.message.auto_role_create_d", { id: result.autoRole.createAutoRole?.id })); this.loadNextPage(); 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 new file mode 100644 index 00000000..76d01eed --- /dev/null +++ b/kdb-web/src/app/modules/view/server/levels/components/levels/levels.component.html @@ -0,0 +1,214 @@ +

+ {{'view.server.levels.header' | translate}} +

+
+
+ + + +
+
+ {{levels.length}} {{'view.server.levels.of' | translate}} + {{dt.totalRecords}} + + {{'view.server.levels.levels' | translate}} +
+ +
+ + +
+
+
+ + + + +
+
{{'view.server.levels.headers.id' | translate}}
+ +
+ + + +
+
{{'view.server.levels.headers.name' | translate}}
+ +
+ + + +
+
{{'view.server.levels.headers.color' | translate}}
+ +
+ + + +
+
{{'view.server.levels.headers.min_xp' | translate}}
+ +
+ + + +
+
{{'view.server.levels.headers.permissions' | translate}}
+ +
+ + + +
+
{{'common.created_at' | translate}}
+
+ + + +
+
{{'common.modified_at' | translate}}
+
+ + + +
+
{{'view.server.levels.headers.actions' | translate}}
+
+ + + + + +
+ +
+ + +
+ +
+ + + + + + + + +
+ + + + + + + {{level.id}} + + + {{level.id}} + + + + + + + + + + + {{level.name}} + + + + + + + + + + + {{level.color}} + + + + + + + + + + + {{level.minXp}} + + + + + + + + + + + {{level.permissions}} + + + + + + + + {{level.createdAt | date:'dd.MM.yy HH:mm'}} + + + {{level.createdAt | date:'dd.MM.yy HH:mm'}} + + + + + + + {{level.modifiedAt | date:'dd.MM.yy HH:mm'}} + + + {{level.modifiedAt | date:'dd.MM.yy HH:mm'}} + + + + +
+ + + + + +
+ + +
+ + + + + {{'view.server.levels.no_entries_found' | translate}} + + + + + + +
+
+
+ diff --git a/kdb-web/src/app/modules/view/server/levels/components/levels/levels.component.scss b/kdb-web/src/app/modules/view/server/levels/components/levels/levels.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/kdb-web/src/app/modules/view/server/levels/components/levels/levels.component.spec.ts b/kdb-web/src/app/modules/view/server/levels/components/levels/levels.component.spec.ts new file mode 100644 index 00000000..30dc8eca --- /dev/null +++ b/kdb-web/src/app/modules/view/server/levels/components/levels/levels.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LevelsComponent } from './levels.component'; + +describe('LevelsComponent', () => { + let component: LevelsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ LevelsComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(LevelsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); 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 new file mode 100644 index 00000000..cf83aaf5 --- /dev/null +++ b/kdb-web/src/app/modules/view/server/levels/components/levels/levels.component.ts @@ -0,0 +1,272 @@ +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"; +import { ConfirmationDialogService } from "../../../../../../services/confirmation-dialog/confirmation-dialog.service"; +import { FormBuilder, FormControl, FormGroup } from "@angular/forms"; +import { TranslateService } from "@ngx-translate/core"; +import { DataService } from "../../../../../../services/data/data.service"; +import { SidebarService } from "../../../../../../services/sidebar/sidebar.service"; +import { ActivatedRoute } from "@angular/router"; +import { Page } from "../../../../../../models/graphql/filter/page.model"; +import { Sort, SortDirection } from "../../../../../../models/graphql/filter/sort.model"; +import { Level, LevelFilter } from "../../../../../../models/data/level.model"; +import { LevelListQuery, Query } from "../../../../../../models/graphql/query.model"; +import { Queries } from "../../../../../../models/graphql/queries.model"; +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 { Subject, throwError } from "rxjs"; +import { Server } from "../../../../../../models/data/server.model"; + +@Component({ + selector: "app-levels", + templateUrl: "./levels.component.html", + styleUrls: ["./levels.component.scss"] +}) +export class LevelsComponent implements OnInit, OnDestroy { + + public levels: Level[] = []; + public loading = true; + + public isEditingNew: boolean = false; + + public filterForm!: FormGroup<{ + id: FormControl, + name: FormControl, + color: FormControl, + min_xp: FormControl, + permissions: FormControl, + }>; + + public filter: LevelFilter = {}; + public page: Page = { + pageSize: undefined, + pageIndex: undefined + }; + public sort: Sort = { + sortColumn: undefined, + sortDirection: undefined + }; + + public totalRecords: number = 0; + + public clonedLevels: { [s: string]: Level; } = {}; + + private unsubscriber = new Subject(); + private server: Server = {}; + + public constructor( + private authService: AuthService, + private spinner: SpinnerService, + private toastService: ToastService, + private confirmDialog: ConfirmationDialogService, + private fb: FormBuilder, + private translate: TranslateService, + private data: DataService, + private sidebar: SidebarService, + private route: ActivatedRoute) { + } + + public ngOnInit(): void { + this.setFilterForm(); + this.data.getServerFromRoute(this.route).then(server => { + this.server = server; + this.loadNextPage(); + }); + } + + public ngOnDestroy(): void { + this.unsubscriber.next(); + this.unsubscriber.complete(); + } + + public loadNextPage(): void { + this.loading = true; + this.data.query(Queries.levelQuery, { + serverId: this.server.id, filter: this.filter, page: this.page, sort: this.sort + }, + (data: Query) => { + return data.servers[0]; + } + ).subscribe(data => { + this.totalRecords = data.levelCount; + this.levels = data.levels; + this.spinner.hideSpinner(); + this.loading = false; + }); + } + + public setFilterForm(): void { + this.filterForm = this.fb.group({ + id: new FormControl(null), + name: new FormControl(null), + color: new FormControl(null), + min_xp: new FormControl(null), + permissions: new FormControl(null) + }); + + this.filterForm.valueChanges.pipe( + takeUntil(this.unsubscriber), + debounceTime(600) + ).subscribe(changes => { + if (changes.id) { + this.filter.id = changes.id; + } else { + this.filter.id = undefined; + } + + if (changes.name) { + this.filter.name = changes.name; + } else { + this.filter.name = undefined; + } + + if (this.page.pageSize) + this.page.pageSize = 10; + + if (this.page.pageIndex) + this.page.pageIndex = 0; + + this.loadNextPage(); + }); + } + + public newLevelTemplate: Level = { + id: 0, + createdAt: "", + modifiedAt: "" + }; + + public nextPage(event: LazyLoadEvent): void { + this.page.pageSize = event.rows ?? 0; + if (event.first != null && event.rows != null) + this.page.pageIndex = event.first / event.rows; + this.sort.sortColumn = event.sortField ?? undefined; + this.sort.sortDirection = event.sortOrder === 1 ? SortDirection.ASC : event.sortOrder === -1 ? SortDirection.DESC : SortDirection.ASC; + + this.loadNextPage(); + } + + public resetFilters(): void { + this.filterForm.reset(); + } + + public onRowEditInit(table: Table, user: User, index: number): void { + this.clonedLevels[index] = { ...user }; + } + + public onRowEditSave(table: Table, newLevel: Level, index: number): void { + // const oldUser = this.clonedUsers[index]; + // delete this.clonedUsers[index]; + + // if (JSON.stringify(oldUser) === JSON.stringify(newUser) && !this.isEditingNew) { + // console.log(1, oldUser, newUser, JSON.stringify(oldUser) === JSON.stringify(newUser), !this.isEditingNew); + // return; + // } + + if (this.isEditingNew && JSON.stringify(newLevel) === JSON.stringify(this.newLevelTemplate)) { + this.isEditingNew = false; + this.levels.splice(index, 1); + return; + } + + if (!newLevel.id && !this.isEditingNew || !newLevel.minXp && !newLevel?.name && !newLevel?.permissions) { + return; + } + + if (this.isEditingNew) { + this.spinner.showSpinner(); + this.data.mutation(Mutations.createLevel, { + name: newLevel.name, + color: newLevel.color, + minXp: newLevel.minXp, + permissions: newLevel.permissions, + serverId: this.server.id + } + ).pipe(catchError(err => { + this.isEditingNew = false; + this.spinner.hideSpinner(); + this.toastService.error(this.translate.instant("view.server.levels.message.level_create_failed"), this.translate.instant("view.server.levels.message.level_create_failed_d")); + return throwError(err); + })).subscribe(result => { + this.isEditingNew = false; + this.spinner.hideSpinner(); + this.toastService.success(this.translate.instant("view.server.levels.message.level_create"), this.translate.instant("view.server.levels.message.level_create_d", { name: result.level.createLevel?.name })); + this.loadNextPage(); + }); + return; + } + + this.spinner.showSpinner(); + this.data.mutation(Mutations.updateLevel, { + id: newLevel.id, + name: newLevel.name, + color: newLevel.color, + minXp: newLevel.minXp, + permissions: newLevel.permissions + } + ).pipe(catchError(err => { + this.spinner.hideSpinner(); + this.toastService.error(this.translate.instant("view.server.levels.message.level_update_failed"), this.translate.instant("view.server.levels.message.level_update_failed_d", { name: newLevel.name })); + return throwError(err); + })).subscribe(_ => { + this.spinner.hideSpinner(); + this.toastService.success(this.translate.instant("view.server.levels.message.level_update"), this.translate.instant("view.server.levels.message.level_update_d", { name: newLevel.name })); + this.loadNextPage(); + }); + + } + + public onRowEditCancel(index: number): void { + if (this.isEditingNew) { + this.levels.splice(index, 1); + delete this.clonedLevels[index]; + this.isEditingNew = false; + return; + } + + this.levels[index] = this.clonedLevels[index]; + delete this.clonedLevels[index]; + } + + public deleteLevel(level: Level): void { + this.confirmDialog.confirmDialog( + this.translate.instant("view.server.levels.message.level_delete"), this.translate.instant("view.server.levels.message.level_delete_q", { name: level.name }), + () => { + this.spinner.showSpinner(); + this.data.mutation(Mutations.deleteLevel, { + id: level.id + } + ).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_failed_d", { name: level.name })); + return throwError(err); + })).subscribe(l => { + this.spinner.hideSpinner(); + this.toastService.success(this.translate.instant("view.server.levels.message.level_deleted"), this.translate.instant("view.server.levels.message.level_deleted_d", { name: level.name })); + this.loadNextPage(); + }); + }); + } + + public addLevel(table: Table): void { + const newLevel = JSON.parse(JSON.stringify(this.newLevelTemplate)); + newLevel.id = Math.max.apply(Math, this.levels.map(l => { + return l.id ?? 0; + })) + 1; + + this.levels.push(newLevel); + + table.initRowEdit(newLevel); + + const index = this.levels.findIndex(l => l.id == newLevel.id); + this.onRowEditInit(table, newLevel, index); + + this.isEditingNew = true; + } + +} diff --git a/kdb-web/src/app/modules/view/server/levels/levels-routing.module.ts b/kdb-web/src/app/modules/view/server/levels/levels-routing.module.ts new file mode 100644 index 00000000..76c42715 --- /dev/null +++ b/kdb-web/src/app/modules/view/server/levels/levels-routing.module.ts @@ -0,0 +1,16 @@ +import {NgModule} from "@angular/core"; +import {RouterModule, Routes} from "@angular/router"; +import {LevelsComponent} from "./components/levels/levels.component"; + +const routes: Routes = [ + + {path: '', component: LevelsComponent}, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class LevelsRoutingModule { + +} diff --git a/kdb-web/src/app/modules/view/server/levels/levels.module.ts b/kdb-web/src/app/modules/view/server/levels/levels.module.ts new file mode 100644 index 00000000..a9d0ba8e --- /dev/null +++ b/kdb-web/src/app/modules/view/server/levels/levels.module.ts @@ -0,0 +1,18 @@ +import {NgModule} from '@angular/core'; +import {CommonModule} from '@angular/common'; +import {LevelsComponent} from './components/levels/levels.component' +import {SharedModule} from "../../../shared/shared.module"; +import {LevelsRoutingModule} from "./levels-routing.module"; + +@NgModule({ + declarations: [ + LevelsComponent + ], + imports: [ + CommonModule, + LevelsRoutingModule, + SharedModule + ] +}) +export class LevelsModule { +} diff --git a/kdb-web/src/app/modules/view/server/members/members.component.html b/kdb-web/src/app/modules/view/server/members/members.component.html index 1c120f02..ab005b5f 100644 --- a/kdb-web/src/app/modules/view/server/members/members.component.html +++ b/kdb-web/src/app/modules/view/server/members/members.component.html @@ -164,7 +164,8 @@ + inputId="minmax-buttons"> + {{member.xp}} @@ -225,12 +226,13 @@
- + + icon="pi pi-times-circle" (click)="onRowEditCancel(ri)">
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 19ddeebe..8b3e7e27 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,19 +5,21 @@ 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"; import { Queries } from "../../../../models/graphql/queries.model"; -import { LevelListQuery, UserListQuery } from "../../../../models/graphql/query.model"; +import { LevelListQuery, Query, UserListQuery } from "../../../../models/graphql/query.model"; 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"; +import { Server } from "../../../../models/data/server.model"; @Component({ selector: "app-members", @@ -26,7 +28,6 @@ import { ActivatedRoute } from "@angular/router"; }) export class MembersComponent implements OnInit { members!: User[]; - // levelsFilter!: MenuItem[]; levels!: MenuItem[]; leftServerOptions = [ { label: this.translate.instant("common.bool_as_string.true"), value: false }, @@ -64,7 +65,7 @@ export class MembersComponent implements OnInit { discordId: FormControl, name: FormControl, leftServer: FormControl, - level: FormControl + level: FormControl }>; filter: UserFilter = {}; @@ -78,6 +79,8 @@ export class MembersComponent implements OnInit { }; totalRecords!: number; + private unsubscriber = new Subject(); + private server: Server = {}; constructor( private authService: AuthService, @@ -95,11 +98,13 @@ export class MembersComponent implements OnInit { this.setFilterForm(); this.data.getServerFromRoute(this.route).then(server => { + this.server = server; this.spinner.showSpinner(); this.data.query(Queries.levelQuery, { - filter: { - server: { id: server.id } - } + serverId: server.id + }, + (data: Query) => { + return data.servers[0]; } ).subscribe(data => { this.levels = data.levels.map(level => { @@ -114,7 +119,10 @@ export class MembersComponent implements OnInit { this.spinner.showSpinner(); this.loading = true; this.data.query(Queries.usersQuery, { - filter: this.filter, page: this.page, sort: this.sort + serverId: this.server.id, filter: this.filter, page: this.page, sort: this.sort + }, + (x: { servers: Server[] }) => { + return x.servers[0]; } ).subscribe(data => { this.totalRecords = data.userCount; @@ -130,10 +138,11 @@ export class MembersComponent implements OnInit { discordId: new FormControl(null), name: [""], leftServer: new FormControl(null), - level: new FormControl(null) + level: new FormControl(null) }); this.filterForm.valueChanges.pipe( + takeUntil(this.unsubscriber), debounceTime(600) ).subscribe(changes => { if (changes.id) { @@ -162,7 +171,7 @@ export class MembersComponent implements OnInit { if (changes.level) { this.filter.level = { - id: changes.level + id: changes.level.id }; } else { this.filter.level = undefined; @@ -233,7 +242,7 @@ export class MembersComponent implements OnInit { } - onRowEditCancel(user: User, index: number) { + onRowEditCancel(index: number) { if (this.isEditingNew) { this.members.splice(index, 1); delete this.clonedUsers[index]; diff --git a/kdb-web/src/app/modules/view/server/profile/profile.component.ts b/kdb-web/src/app/modules/view/server/profile/profile.component.ts index 80909967..6e3e81a1 100644 --- a/kdb-web/src/app/modules/view/server/profile/profile.component.ts +++ b/kdb-web/src/app/modules/view/server/profile/profile.component.ts @@ -9,6 +9,7 @@ import { UserDTO } from "../../../../models/auth/auth-user.dto"; import { AuthService } from "src/app/services/auth/auth.service"; import { ToastService } from "src/app/services/toast/toast.service"; import { TranslateService } from "@ngx-translate/core"; +import { Server } from "../../../../models/data/server.model"; @Component({ selector: "app-profile", @@ -18,6 +19,7 @@ import { TranslateService } from "@ngx-translate/core"; export class ProfileComponent implements OnInit { user: User = { createdAt: "", modifiedAt: "" }; + private server: Server = {}; constructor( private route: ActivatedRoute, @@ -36,6 +38,7 @@ export class ProfileComponent implements OnInit { this.router.navigate([`/server/${server.id}`]); return; } + this.server = server; let authUser = await this.auth.getLoggedInUser(); this.spinner.showSpinner(); @@ -47,16 +50,20 @@ export class ProfileComponent implements OnInit { return; } - this.data.query(Queries.singleUserQuery, { + this.data.query(Queries.usersQuery, { + serverId: this.server.id, filter: { id: this.route.snapshot.params["memberId"] } }, - function(data: UserListQuery) { - return data.users.length > 0 ? data.users[0] : null; + (x: { servers: Server[] }) => { + return x.servers[0]; } - ).subscribe(user => { - this.user = user; + ).subscribe(users => { + if (!users.users[0]) { + this.router.navigate([`/server/${server.id}`]); + } + this.user = users.users[0]; this.spinner.hideSpinner(); }); }); diff --git a/kdb-web/src/app/modules/view/server/server-routing.module.ts b/kdb-web/src/app/modules/view/server/server-routing.module.ts index b390b0b8..147c40ea 100644 --- a/kdb-web/src/app/modules/view/server/server-routing.module.ts +++ b/kdb-web/src/app/modules/view/server/server-routing.module.ts @@ -5,14 +5,16 @@ import { ProfileComponent } from "./profile/profile.component"; import { MembersComponent } from "./members/members.component"; const routes: Routes = [ - { path: '', component: ServerDashboardComponent }, - { path: 'members', component: MembersComponent }, - { path: 'members/:memberId', component: ProfileComponent }, - { path: 'auto-roles', loadChildren: () => import('./auto-role/auto-role.module').then(m => m.AutoRoleModule)}, + { path: "", component: ServerDashboardComponent }, + { path: "members", component: MembersComponent }, + { path: "members/:memberId", component: ProfileComponent }, + { path: "auto-roles", loadChildren: () => import("./auto-role/auto-role.module").then(m => m.AutoRoleModule) }, + { path: "levels", loadChildren: () => import("./levels/levels.module").then(m => m.LevelsModule) } ]; @NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule] }) -export class ServerRoutingModule { } +export class ServerRoutingModule { +} 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 021f434f..925e6887 100644 --- a/kdb-web/src/app/services/sidebar/sidebar.service.ts +++ b/kdb-web/src/app/services/sidebar/sidebar.service.ts @@ -18,16 +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; - 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, @@ -66,7 +66,11 @@ export class SidebarService { } async buildMenu(user: UserDTO | null, hasPermission: boolean) { - this.dashboard = { label: this.isSidebarOpen ? this.translateService.instant("sidebar.dashboard") : "", icon: "pi pi-th-large", routerLink: "dashboard" }; + this.dashboard = { + label: this.isSidebarOpen ? this.translateService.instant("sidebar.dashboard") : "", + icon: "pi pi-th-large", + routerLink: "dashboard" + }; this.serverDashboard = { label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.dashboard") : "", icon: "pi pi-th-large", @@ -74,7 +78,7 @@ export class SidebarService { }; this.serverProfile = { label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.profile") : "", - icon: "pi pi-user", + icon: "pi pi-id-card", routerLink: `server/${this.server$.value?.id}/members/${user?.id}` }; this.serverMembers = { @@ -91,14 +95,25 @@ export class SidebarService { routerLink: `server/${this.server$.value?.id}/auto-roles` }; + this.serverLevels = { + label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.levels") : "", + icon: "pi pi-book", + visible: true, + routerLink: `server/${this.server$.value?.id}/levels` + }; + this.serverMenu = { label: this.isSidebarOpen ? this.server$.value?.name : "", icon: "pi pi-server", visible: false, expanded: true, - items: [this.serverDashboard, this.serverProfile, this.serverMembers, this.serverAutoRoles] + items: [this.serverDashboard, this.serverProfile, this.serverMembers, this.serverAutoRoles, this.serverLevels] + }; + this.adminConfig = { + label: this.isSidebarOpen ? this.translateService.instant("sidebar.config") : "", + icon: "pi pi-cog", + routerLink: "/admin/settings" }; - this.adminConfig = { label: this.isSidebarOpen ? this.translateService.instant("sidebar.config") : "", icon: "pi pi-cog", routerLink: "/admin/settings" }; this.adminUsers = { label: this.isSidebarOpen ? this.translateService.instant("sidebar.auth_user_list") : "", icon: "pi pi-user-edit", @@ -126,6 +141,7 @@ export class SidebarService { this.serverMenu.visible = true; this.serverMembers.visible = !!user?.isModerator; this.serverAutoRoles.visible = !!user?.isAdmin; + this.serverLevels.visible = !!user?.isAdmin; } else { this.serverMenu.visible = false; } 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/config.json b/kdb-web/src/assets/config.json index c055d5cb..c3479190 100644 --- a/kdb-web/src/assets/config.json +++ b/kdb-web/src/assets/config.json @@ -3,7 +3,7 @@ "WebVersion": { "Major": "1", "Minor": "0", - "Micro": "0" + "Micro": "dev220" }, "Themes": [ { diff --git a/kdb-web/src/assets/i18n/de.json b/kdb-web/src/assets/i18n/de.json index 53632ad2..840727b6 100644 --- a/kdb-web/src/assets/i18n/de.json +++ b/kdb-web/src/assets/i18n/de.json @@ -11,6 +11,7 @@ "dashboard": "Dashboard", "profile": "Dein Profil", "members": "Mitglieder", + "levels": "Level", "auto_roles": "Auto Rollen" }, "server_empty": "Kein Server ausgewählt", @@ -220,7 +221,7 @@ "message": { "user_changed": "Benutzer geändert", "user_changed_d": "Benutzer {{name}} erfolgreich geändert", - "user_change_failed": "Benutzer änderung fehlgeschlagen", + "user_change_failed": "Benutzer Änderung fehlgeschlagen", "user_change_failed_d": "Benutzer {{name}} konnte nicht geändert werden!" } }, @@ -281,6 +282,38 @@ "auto_role_rule_delete_failed_d": "Die Löschung der Auto Rollen Regel {{id}} ist fehlgeschlagen!" } } + }, + "levels": { + "header": "Level", + "reset_filters": "Filter zurücksetzen", + "of": "von", + "add": "Hinzufügen", + "levels": "Level", + "headers": { + "id": "Id", + "name": "Name", + "color": "Farbe", + "min_xp": "Min. XP", + "permissions": "Rechte", + "actions": "Aktionen" + }, + "no_entries_found": "Keine Einträge gefunden", + "message": { + "level_create": "Level erstellt", + "level_create_d": "Level {{name}} erfolgreich erstellt", + "level_create_failed": "Level Erstellung fehlgeschlagen", + "level_create_failed_d": "Die Erstellung des Levels ist fehlgeschlagen!", + "level_update": "Level bearbeitet", + "level_update_d": "Level {{name}} erfolgreich bearbeitet", + "level_update_failed": "Level Bearbeitung fehlgeschlagen", + "level_update_failed_d": "Die Bearbeitung des Levels ist fehlgeschlagen!", + "level_delete": "Level löschen", + "level_delete_q": "Sind Sie sich sicher, dass Sie das Level {{name}} löschen möchten?", + "level_deleted": "Level gelöscht", + "level_deleted_d": "Level {{name}} erfolgreich gelöscht", + "level_delete_failed": "Level Löschung fehlgeschlagen", + "level_delete_failed_d": "Die Löschung des Levels {{name}} ist fehlgeschlagen!" + } } }, "user-list": {},