First step to add achievements to frontend #268_achievements
This commit is contained in:
parent
3db548fb86
commit
109bbf3729
@ -16,6 +16,9 @@ type Server implements TableWithHistoryQuery {
|
|||||||
userCount: Int
|
userCount: Int
|
||||||
users(filter: UserFilter, page: Page, sort: Sort): [User]
|
users(filter: UserFilter, page: Page, sort: Sort): [User]
|
||||||
|
|
||||||
|
achievementCount: Int
|
||||||
|
achievements(filter: AchievementFilter, page: Page, sort: Sort): [Achievement]
|
||||||
|
|
||||||
createdAt: String
|
createdAt: String
|
||||||
modifiedAt: String
|
modifiedAt: String
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
from cpl_core.database.context import DatabaseContextABC
|
from cpl_core.database.context import DatabaseContextABC
|
||||||
from cpl_discord.service import DiscordBotServiceABC
|
from cpl_discord.service import DiscordBotServiceABC
|
||||||
|
|
||||||
|
from bot_data.abc.achievement_repository_abc import AchievementRepositoryABC
|
||||||
from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC
|
from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC
|
||||||
from bot_data.abc.client_repository_abc import ClientRepositoryABC
|
from bot_data.abc.client_repository_abc import ClientRepositoryABC
|
||||||
from bot_data.abc.level_repository_abc import LevelRepositoryABC
|
from bot_data.abc.level_repository_abc import LevelRepositoryABC
|
||||||
@ -9,8 +10,8 @@ from bot_data.abc.user_joined_voice_channel_repository_abc import UserJoinedVoic
|
|||||||
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
||||||
from bot_data.model.server import Server
|
from bot_data.model.server import Server
|
||||||
from bot_data.model.server_history import ServerHistory
|
from bot_data.model.server_history import ServerHistory
|
||||||
from bot_graphql.abc.data_query_abc import DataQueryABC
|
|
||||||
from bot_graphql.abc.data_query_with_history_abc import DataQueryWithHistoryABC
|
from bot_graphql.abc.data_query_with_history_abc import DataQueryWithHistoryABC
|
||||||
|
from bot_graphql.filter.achievement_filter import AchievementFilter
|
||||||
from bot_graphql.filter.auto_role_filter import AutoRoleFilter
|
from bot_graphql.filter.auto_role_filter import AutoRoleFilter
|
||||||
from bot_graphql.filter.client_filter import ClientFilter
|
from bot_graphql.filter.client_filter import ClientFilter
|
||||||
from bot_graphql.filter.level_filter import LevelFilter
|
from bot_graphql.filter.level_filter import LevelFilter
|
||||||
@ -28,6 +29,7 @@ class ServerQuery(DataQueryWithHistoryABC):
|
|||||||
users: UserRepositoryABC,
|
users: UserRepositoryABC,
|
||||||
ujs: UserJoinedServerRepositoryABC,
|
ujs: UserJoinedServerRepositoryABC,
|
||||||
ujvs: UserJoinedVoiceChannelRepositoryABC,
|
ujvs: UserJoinedVoiceChannelRepositoryABC,
|
||||||
|
achievements: AchievementRepositoryABC,
|
||||||
):
|
):
|
||||||
DataQueryWithHistoryABC.__init__(self, "Server", "ServersHistory", ServerHistory, db)
|
DataQueryWithHistoryABC.__init__(self, "Server", "ServersHistory", ServerHistory, db)
|
||||||
|
|
||||||
@ -54,6 +56,9 @@ class ServerQuery(DataQueryWithHistoryABC):
|
|||||||
)
|
)
|
||||||
self.add_collection("level", lambda server, *_: self._levels.get_levels_by_server_id(server.id), LevelFilter)
|
self.add_collection("level", lambda server, *_: self._levels.get_levels_by_server_id(server.id), LevelFilter)
|
||||||
self.add_collection("user", lambda server, *_: self._users.get_users_by_server_id(server.id), UserFilter)
|
self.add_collection("user", lambda server, *_: self._users.get_users_by_server_id(server.id), UserFilter)
|
||||||
|
self.add_collection(
|
||||||
|
"achievement", lambda server, *_: achievements.get_achievements_by_server_id(server.id), AchievementFilter
|
||||||
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def resolve_id(server: Server, *_):
|
def resolve_id(server: Server, *_):
|
||||||
|
20
kdb-web/src/app/models/data/achievement.model.ts
Normal file
20
kdb-web/src/app/models/data/achievement.model.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { DataWithHistory } from "./data.model";
|
||||||
|
import { Server, ServerFilter } from "./server.model";
|
||||||
|
|
||||||
|
export interface Achievement extends DataWithHistory {
|
||||||
|
id?: number;
|
||||||
|
name?: string;
|
||||||
|
attribute?: string;
|
||||||
|
operator?: string;
|
||||||
|
value?: string;
|
||||||
|
server?: Server;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AchievementFilter {
|
||||||
|
id?: number;
|
||||||
|
name?: string;
|
||||||
|
attribute?: string;
|
||||||
|
operator?: string;
|
||||||
|
value?: string;
|
||||||
|
server?: ServerFilter;
|
||||||
|
}
|
@ -121,4 +121,46 @@ export class Mutations {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
static createAchievement = `
|
||||||
|
mutation createAchievement($name: String, $attribute: String, $operator: String, $value: String, $serverId: ID) {
|
||||||
|
level {
|
||||||
|
createAchievement(input: { name: $name, attribute: $attribute, operator: $operator, value: $value, serverId: $serverId}) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
attribute
|
||||||
|
operator
|
||||||
|
value
|
||||||
|
server {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
static updateAchievement = `
|
||||||
|
mutation updateAchievement($name: String, $attribute: String, $operator: String, $value: String, $serverId: ID) {
|
||||||
|
level {
|
||||||
|
updateAchievement(input: { name: $name, attribute: $attribute, operator: $operator, value: $value}) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
attribute
|
||||||
|
operator
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
static deleteAchievement = `
|
||||||
|
mutation deleteAchievement($id: ID) {
|
||||||
|
level {
|
||||||
|
deleteLevel(id: $id) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
@ -90,6 +90,50 @@ export class Queries {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
static achievementQuery = `
|
||||||
|
query AchievementList($serverId: ID, $filter: AchievementFilter, $page: Page, $sort: Sort) {
|
||||||
|
servers(filter: {id: $serverId}) {
|
||||||
|
achievementCount
|
||||||
|
achievements(filter: $filter, page: $page, sort: $sort) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
attribute
|
||||||
|
operator
|
||||||
|
value
|
||||||
|
server {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
createdAt
|
||||||
|
modifiedAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
static achievementWithHistoryQuery = `
|
||||||
|
query AchievementHistory($serverId: ID, $id: ID) {
|
||||||
|
servers(filter: {id: $serverId}) {
|
||||||
|
achievementCount
|
||||||
|
achievements(filter: {id: $id}) {
|
||||||
|
id
|
||||||
|
|
||||||
|
history {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
attribute
|
||||||
|
operator
|
||||||
|
value
|
||||||
|
server
|
||||||
|
deleted
|
||||||
|
dateFrom
|
||||||
|
dateTo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
static usersQuery = `
|
static usersQuery = `
|
||||||
query UsersList($serverId: ID, $filter: UserFilter, $page: Page, $sort: Sort) {
|
query UsersList($serverId: ID, $filter: UserFilter, $page: Page, $sort: Sort) {
|
||||||
servers(filter: {id: $serverId}) {
|
servers(filter: {id: $serverId}) {
|
||||||
|
@ -3,6 +3,7 @@ import { User } from "../data/user.model";
|
|||||||
import { AutoRole, AutoRoleRule } from "../data/auto_role.model";
|
import { AutoRole, AutoRoleRule } from "../data/auto_role.model";
|
||||||
import { Guild } from "../data/discord.model";
|
import { Guild } from "../data/discord.model";
|
||||||
import { Level } from "../data/level.model";
|
import { Level } from "../data/level.model";
|
||||||
|
import { Achievement } from "../data/achievement.model";
|
||||||
|
|
||||||
export interface Query {
|
export interface Query {
|
||||||
serverCount: number;
|
serverCount: number;
|
||||||
@ -23,6 +24,11 @@ export interface LevelListQuery {
|
|||||||
levels: Level[];
|
levels: Level[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AchievementListQuery {
|
||||||
|
achievementCount: number;
|
||||||
|
achievements: Achievement[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface AutoRoleQuery {
|
export interface AutoRoleQuery {
|
||||||
autoRoleCount: number;
|
autoRoleCount: number;
|
||||||
autoRoles: AutoRole[];
|
autoRoles: AutoRole[];
|
||||||
|
@ -2,6 +2,7 @@ import { User } from "../data/user.model";
|
|||||||
import { AutoRole, AutoRoleRule } from "../data/auto_role.model";
|
import { AutoRole, AutoRoleRule } from "../data/auto_role.model";
|
||||||
import { Level } from "../data/level.model";
|
import { Level } from "../data/level.model";
|
||||||
import { Server } from "../data/server.model";
|
import { Server } from "../data/server.model";
|
||||||
|
import { Achievement } from "../data/achievement.model";
|
||||||
|
|
||||||
export interface GraphQLResult {
|
export interface GraphQLResult {
|
||||||
data: {
|
data: {
|
||||||
@ -45,3 +46,11 @@ export interface LevelMutationResult {
|
|||||||
deleteLevel?: Level
|
deleteLevel?: Level
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AchievementMutationResult {
|
||||||
|
achievement: {
|
||||||
|
createAchievement?: Achievement
|
||||||
|
updateAchievement?: Achievement
|
||||||
|
deleteAchievement?: Achievement
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
import {NgModule} from "@angular/core";
|
||||||
|
import {RouterModule, Routes} from "@angular/router";
|
||||||
|
import { AchievementComponent } from "./components/achievement/achievement.component";
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
|
||||||
|
{path: '', component: AchievementComponent},
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forChild(routes)],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class AchievementsRoutingModule {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
import { NgModule } from "@angular/core";
|
||||||
|
import { CommonModule } from "@angular/common";
|
||||||
|
import { AchievementComponent } from "./components/achievement/achievement.component";
|
||||||
|
import { AchievementsRoutingModule } from "./achievements-routing.module";
|
||||||
|
import { SharedModule } from "../../../shared/shared.module";
|
||||||
|
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
AchievementComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
AchievementsRoutingModule,
|
||||||
|
SharedModule
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AchievementsModule { }
|
@ -0,0 +1,215 @@
|
|||||||
|
<h1>
|
||||||
|
{{'view.server.achievements.header' | translate}}
|
||||||
|
</h1>
|
||||||
|
<div class="content-wrapper">
|
||||||
|
<div class="content">
|
||||||
|
<p-table #dt [value]="achievements" dataKey="id" editMode="row" [rowHover]="true" [rows]="10"
|
||||||
|
[rowsPerPageOptions]="[10,25,50]" [paginator]="true" [loading]="loading" [totalRecords]="totalRecords"
|
||||||
|
[lazy]="true" (onLazyLoad)="nextPage($event)">
|
||||||
|
|
||||||
|
<ng-template pTemplate="caption">
|
||||||
|
<div class="table-caption">
|
||||||
|
<div class="table-caption-text">
|
||||||
|
<ng-container *ngIf="!loading">{{achievements.length}} {{'common.of' | translate}}
|
||||||
|
{{dt.totalRecords}}
|
||||||
|
</ng-container>
|
||||||
|
{{'view.server.achievements.achievements' | translate}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-caption-btn-wrapper btn-wrapper">
|
||||||
|
<button pButton label="{{'common.add' | translate}}" class="icon-btn btn"
|
||||||
|
icon="pi pi-user-plus" (click)="addAchievement(dt)" [disabled]="isEditingNew || user?.isModerator && !user?.isAdmin">
|
||||||
|
</button>
|
||||||
|
<button pButton label="{{'common.reset_filters' | translate}}" icon="pi pi-undo"
|
||||||
|
class="icon-btn btn" (click)="resetFilters()">
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<ng-template pTemplate="header">
|
||||||
|
<tr>
|
||||||
|
<th pSortableColumn="id">
|
||||||
|
<div class="table-header-label">
|
||||||
|
<div class="table-header-text">{{'common.id' | translate}}</div>
|
||||||
|
<p-sortIcon field="id" class="table-header-icon"></p-sortIcon>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th pSortableColumn="name">
|
||||||
|
<div class="table-header-label">
|
||||||
|
<div class="table-header-text">{{'view.server.achievements.headers.name' | translate}}</div>
|
||||||
|
<p-sortIcon field="name" class="table-header-icon"></p-sortIcon>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th pSortableColumn="attribute">
|
||||||
|
<div class="table-header-label">
|
||||||
|
<div class="table-header-text">{{'view.server.achievements.headers.attribute' | translate}}</div>
|
||||||
|
<p-sortIcon field="attribute" class="table-header-icon"></p-sortIcon>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th pSortableColumn="operator">
|
||||||
|
<div class="table-header-label">
|
||||||
|
<div class="table-header-text">{{'view.server.achievements.headers.operator' | translate}}</div>
|
||||||
|
<p-sortIcon field="operator" class="table-header-icon"></p-sortIcon>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th pSortableColumn="value">
|
||||||
|
<div class="table-header-label">
|
||||||
|
<div class="table-header-text">{{'view.server.achievements.headers.value' | translate}}</div>
|
||||||
|
<p-sortIcon field="value" class="table-header-icon"></p-sortIcon>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th>
|
||||||
|
<div class="table-header-label">
|
||||||
|
<div class="table-header-text">{{'common.created_at' | translate}}</div>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th>
|
||||||
|
<div class="table-header-label">
|
||||||
|
<div class="table-header-text">{{'common.modified_at' | translate}}</div>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th>
|
||||||
|
<div class="table-header-label">
|
||||||
|
<div class="table-header-text">{{'common.actions' | translate}}</div>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th class="table-header-small">
|
||||||
|
<form [formGroup]="filterForm">
|
||||||
|
<input type="text" pInputText formControlName="id"
|
||||||
|
placeholder="{{'common.id' | translate}}">
|
||||||
|
</form>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<form [formGroup]="filterForm">
|
||||||
|
<input type="text" pInputText formControlName="name"
|
||||||
|
placeholder="{{'view.server.achievements.headers.name' | translate}}">
|
||||||
|
</form>
|
||||||
|
</th>
|
||||||
|
<th></th>
|
||||||
|
<th></th>
|
||||||
|
<th></th>
|
||||||
|
<th class="table-header-small-dropdown"></th>
|
||||||
|
<th class="table-header-small-dropdown"></th>
|
||||||
|
<th class="table-header-actions"></th>
|
||||||
|
</tr>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<ng-template pTemplate="body" let-achievement let-editing="editing" let-ri="rowIndex">
|
||||||
|
<tr [pEditableRow]="achievement">
|
||||||
|
<td>
|
||||||
|
<p-cellEditor>
|
||||||
|
<ng-template pTemplate="input">
|
||||||
|
{{achievement.id}}
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="output">
|
||||||
|
{{achievement.id}}
|
||||||
|
</ng-template>
|
||||||
|
</p-cellEditor>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<p-cellEditor>
|
||||||
|
<ng-template pTemplate="input">
|
||||||
|
<input class="table-edit-input" pInputText type="text" [(ngModel)]="achievement.name">
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="output">
|
||||||
|
{{achievement.name}}
|
||||||
|
</ng-template>
|
||||||
|
</p-cellEditor>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<p-cellEditor>
|
||||||
|
<ng-template pTemplate="input">
|
||||||
|
<input class="table-edit-input" pInputText type="text" [(ngModel)]="achievement.attribute">
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="output">
|
||||||
|
{{achievement.attribute}}
|
||||||
|
</ng-template>
|
||||||
|
</p-cellEditor>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<p-cellEditor>
|
||||||
|
<ng-template pTemplate="input">
|
||||||
|
<input class="table-edit-input" pInputText min="0" type="number" [(ngModel)]="achievement.operator">
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="output">
|
||||||
|
{{achievement.operator}}
|
||||||
|
</ng-template>
|
||||||
|
</p-cellEditor>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<p-cellEditor>
|
||||||
|
<ng-template pTemplate="input">
|
||||||
|
<input class="table-edit-input" pInputText min="0" type="text" [(ngModel)]="achievement.value">
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="output">
|
||||||
|
{{achievement.value}}
|
||||||
|
</ng-template>
|
||||||
|
</p-cellEditor>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<p-cellEditor>
|
||||||
|
<ng-template pTemplate="input">
|
||||||
|
{{achievement.createdAt | date:'dd.MM.yy HH:mm'}}
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="output">
|
||||||
|
{{achievement.createdAt | date:'dd.MM.yy HH:mm'}}
|
||||||
|
</ng-template>
|
||||||
|
</p-cellEditor>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<p-cellEditor>
|
||||||
|
<ng-template pTemplate="input">
|
||||||
|
{{achievement.modifiedAt | date:'dd.MM.yy HH:mm'}}
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="output">
|
||||||
|
{{achievement.modifiedAt | date:'dd.MM.yy HH:mm'}}
|
||||||
|
</ng-template>
|
||||||
|
</p-cellEditor>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="btn-wrapper">
|
||||||
|
<app-history-btn *ngIf="!isEditingNew" [id]="achievement.id" [query]="query" translationKey="view.server.achievements.header"></app-history-btn>
|
||||||
|
<button *ngIf="!editing" pButton pInitEditableRow class="btn icon-btn" icon="pi pi-pencil"
|
||||||
|
(click)="onRowEditInit(dt, achievement, ri)" [disabled]="!user || user.isModerator && !user.isAdmin"></button>
|
||||||
|
<button *ngIf="!editing" pButton class="btn icon-btn danger-icon-btn" icon="pi pi-trash"
|
||||||
|
(click)="deleteAchievement(achievement)" [disabled]="!user || user.isModerator && !user.isAdmin"></button>
|
||||||
|
|
||||||
|
<button *ngIf="editing" pButton pSaveEditableRow class="btn icon-btn"
|
||||||
|
icon="pi pi-check-circle" (click)="onRowEditSave(dt, achievement, ri)" [disabled]="!user || user.isModerator && !user.isAdmin"></button>
|
||||||
|
<button *ngIf="editing" pButton pCancelEditableRow class="btn icon-btn danger-icon-btn"
|
||||||
|
icon="pi pi-times-circle" (click)="onRowEditCancel(ri)" [disabled]="!user || user.isModerator && !user.isAdmin"></button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<ng-template pTemplate="emptymessage">
|
||||||
|
<tr></tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="10">{{'common.no_entries_found' | translate}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr></tr>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<ng-template pTemplate="paginatorleft">
|
||||||
|
</ng-template>
|
||||||
|
</p-table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AchievementComponent } from './achievement.component';
|
||||||
|
|
||||||
|
describe('AchievementComponent', () => {
|
||||||
|
let component: AchievementComponent;
|
||||||
|
let fixture: ComponentFixture<AchievementComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ AchievementComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(AchievementComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,268 @@
|
|||||||
|
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||||
|
import { Achievement, AchievementFilter } from "../../../../../../models/data/achievement.model";
|
||||||
|
import { FormBuilder, FormControl, FormGroup } from "@angular/forms";
|
||||||
|
import { Page } from "../../../../../../models/graphql/filter/page.model";
|
||||||
|
import { Sort, SortDirection } from "../../../../../../models/graphql/filter/sort.model";
|
||||||
|
import { Subject, throwError } from "rxjs";
|
||||||
|
import { Server } from "../../../../../../models/data/server.model";
|
||||||
|
import { UserDTO } from "../../../../../../models/auth/auth-user.dto";
|
||||||
|
import { Queries } from "../../../../../../models/graphql/queries.model";
|
||||||
|
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 { 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 { AchievementListQuery, Query } from "../../../../../../models/graphql/query.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 { AchievementMutationResult, UpdateUserMutationResult } from "../../../../../../models/graphql/result.model";
|
||||||
|
import { Mutations } from "../../../../../../models/graphql/mutations.model";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: "app-achievement",
|
||||||
|
templateUrl: "./achievement.component.html",
|
||||||
|
styleUrls: ["./achievement.component.scss"]
|
||||||
|
})
|
||||||
|
export class AchievementComponent implements OnInit, OnDestroy {
|
||||||
|
public achievements: Achievement[] = [];
|
||||||
|
public loading = true;
|
||||||
|
|
||||||
|
public isEditingNew: boolean = false;
|
||||||
|
|
||||||
|
public filterForm!: FormGroup<{
|
||||||
|
id: FormControl<number | null>,
|
||||||
|
name: FormControl<string | null>,
|
||||||
|
color: FormControl<string | null>,
|
||||||
|
min_xp: FormControl<number | null>,
|
||||||
|
permissions: FormControl<string | null>,
|
||||||
|
}>;
|
||||||
|
|
||||||
|
public filter: AchievementFilter = {};
|
||||||
|
public page: Page = {
|
||||||
|
pageSize: undefined,
|
||||||
|
pageIndex: undefined
|
||||||
|
};
|
||||||
|
public sort: Sort = {
|
||||||
|
sortColumn: undefined,
|
||||||
|
sortDirection: undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
public totalRecords: number = 0;
|
||||||
|
|
||||||
|
public clonedAchievements: { [s: string]: Achievement; } = {};
|
||||||
|
|
||||||
|
private unsubscriber = new Subject<void>();
|
||||||
|
private server: Server = {};
|
||||||
|
public user: UserDTO | null = null;
|
||||||
|
|
||||||
|
query: string = Queries.achievementWithHistoryQuery;
|
||||||
|
|
||||||
|
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(async server => {
|
||||||
|
this.server = server;
|
||||||
|
this.loadNextPage();
|
||||||
|
let authUser = await this.authService.getLoggedInUser();
|
||||||
|
this.user = authUser?.users?.find(u => u.server == this.server.id) ?? null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public ngOnDestroy(): void {
|
||||||
|
this.unsubscriber.next();
|
||||||
|
this.unsubscriber.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public loadNextPage(): void {
|
||||||
|
this.loading = true;
|
||||||
|
this.data.query<AchievementListQuery>(Queries.achievementQuery, {
|
||||||
|
serverId: this.server.id, filter: this.filter, page: this.page, sort: this.sort
|
||||||
|
},
|
||||||
|
(data: Query) => {
|
||||||
|
return data.servers[0];
|
||||||
|
}
|
||||||
|
).subscribe(data => {
|
||||||
|
this.totalRecords = data.achievementCount;
|
||||||
|
this.achievements = data.achievements;
|
||||||
|
this.spinner.hideSpinner();
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public setFilterForm(): void {
|
||||||
|
this.filterForm = this.fb.group({
|
||||||
|
id: new FormControl<number | null>(null),
|
||||||
|
name: new FormControl<string | null>(null),
|
||||||
|
color: new FormControl<string | null>(null),
|
||||||
|
min_xp: new FormControl<number | null>(null),
|
||||||
|
permissions: new FormControl<string | null>(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 newAchievementTemplate: Achievement = {
|
||||||
|
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.clonedAchievements[index] = { ...user };
|
||||||
|
}
|
||||||
|
|
||||||
|
public onRowEditSave(table: Table, newAchievement: Achievement, index: number): void {
|
||||||
|
if (this.isEditingNew && JSON.stringify(newAchievement) === JSON.stringify(this.newAchievementTemplate)) {
|
||||||
|
this.isEditingNew = false;
|
||||||
|
this.achievements.splice(index, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newAchievement.id && !this.isEditingNew || !newAchievement.name && !newAchievement.attribute && !newAchievement?.operator && !newAchievement?.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isEditingNew) {
|
||||||
|
this.spinner.showSpinner();
|
||||||
|
this.data.mutation<AchievementMutationResult>(Mutations.createAchievement, {
|
||||||
|
name: newAchievement.name,
|
||||||
|
attribute: newAchievement.attribute,
|
||||||
|
operator: newAchievement.operator,
|
||||||
|
value: newAchievement.value,
|
||||||
|
serverId: this.server.id
|
||||||
|
}
|
||||||
|
).pipe(catchError(err => {
|
||||||
|
this.isEditingNew = false;
|
||||||
|
this.spinner.hideSpinner();
|
||||||
|
this.toastService.error(this.translate.instant("view.server.achievements.message.achievement_create_failed"), this.translate.instant("view.server.achievements.message.achievement_create_failed_d"));
|
||||||
|
return throwError(err);
|
||||||
|
})).subscribe(result => {
|
||||||
|
this.isEditingNew = false;
|
||||||
|
this.spinner.hideSpinner();
|
||||||
|
this.toastService.success(this.translate.instant("view.server.achievements.message.achievement_create"), this.translate.instant("view.server.achievements.message.achievement_create_d", { name: result.achievement.createAchievement?.name }));
|
||||||
|
this.loadNextPage();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.spinner.showSpinner();
|
||||||
|
this.data.mutation<AchievementMutationResult>(Mutations.updateAchievement, {
|
||||||
|
id: newAchievement.id,
|
||||||
|
name: newAchievement.name,
|
||||||
|
attribute: newAchievement.attribute,
|
||||||
|
operator: newAchievement.operator,
|
||||||
|
value: newAchievement.value
|
||||||
|
}
|
||||||
|
).pipe(catchError(err => {
|
||||||
|
this.spinner.hideSpinner();
|
||||||
|
this.toastService.error(this.translate.instant("view.server.achievements.message.achievement_update_failed"), this.translate.instant("view.server.achievements.message.achievement_update_failed_d", { name: newAchievement.name }));
|
||||||
|
return throwError(err);
|
||||||
|
})).subscribe(_ => {
|
||||||
|
this.spinner.hideSpinner();
|
||||||
|
this.toastService.success(this.translate.instant("view.server.achievements.message.achievement_update"), this.translate.instant("view.server.achievements.message.achievement_update_d", { name: newAchievement.name }));
|
||||||
|
this.loadNextPage();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public onRowEditCancel(index: number): void {
|
||||||
|
if (this.isEditingNew) {
|
||||||
|
this.achievements.splice(index, 1);
|
||||||
|
delete this.clonedAchievements[index];
|
||||||
|
this.isEditingNew = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.achievements[index] = this.clonedAchievements[index];
|
||||||
|
delete this.clonedAchievements[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public deleteAchievement(achievement: Achievement): void {
|
||||||
|
this.confirmDialog.confirmDialog(
|
||||||
|
this.translate.instant("view.server.achievements.message.achievement_delete"), this.translate.instant("view.server.achievements.message.achievement_delete_q", { name: achievement.name }),
|
||||||
|
() => {
|
||||||
|
this.spinner.showSpinner();
|
||||||
|
this.data.mutation<AchievementMutationResult>(Mutations.deleteAchievement, {
|
||||||
|
id: achievement.id
|
||||||
|
}
|
||||||
|
).pipe(catchError(err => {
|
||||||
|
this.spinner.hideSpinner();
|
||||||
|
this.toastService.error(this.translate.instant("view.server.achievements.message.achievement_delete_failed"), this.translate.instant("view.server.achievements.message.achievement_delete_failed_d", { name: achievement.name }));
|
||||||
|
return throwError(err);
|
||||||
|
})).subscribe(l => {
|
||||||
|
this.spinner.hideSpinner();
|
||||||
|
this.toastService.success(this.translate.instant("view.server.achievements.message.achievement_deleted"), this.translate.instant("view.server.achievements.message.achievement_deleted_d", { name: achievement.name }));
|
||||||
|
this.loadNextPage();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public addAchievement(table: Table): void {
|
||||||
|
const newAchievement = JSON.parse(JSON.stringify(this.newAchievementTemplate));
|
||||||
|
newAchievement.id = Math.max.apply(Math, this.achievements.map(l => {
|
||||||
|
return l.id ?? 0;
|
||||||
|
})) + 1;
|
||||||
|
|
||||||
|
this.achievements.push(newAchievement);
|
||||||
|
|
||||||
|
table.initRowEdit(newAchievement);
|
||||||
|
|
||||||
|
const index = this.achievements.findIndex(l => l.id == newAchievement.id);
|
||||||
|
this.onRowEditInit(table, newAchievement, index);
|
||||||
|
|
||||||
|
this.isEditingNew = true;
|
||||||
|
}
|
||||||
|
}
|
@ -9,7 +9,8 @@ const routes: Routes = [
|
|||||||
{ path: "members", component: MembersComponent },
|
{ path: "members", component: MembersComponent },
|
||||||
{ path: "members/:memberId", component: ProfileComponent },
|
{ path: "members/:memberId", component: ProfileComponent },
|
||||||
{ path: "auto-roles", loadChildren: () => import("./auto-role/auto-role.module").then(m => m.AutoRoleModule) },
|
{ 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) }
|
{ path: "levels", loadChildren: () => import("./levels/levels.module").then(m => m.LevelsModule) },
|
||||||
|
{ path: "achievements", loadChildren: () => import("./achievements/achievements.module").then(m => m.AchievementsModule) }
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@ -24,6 +24,7 @@ export class SidebarService {
|
|||||||
serverMembers: MenuItem = {};
|
serverMembers: MenuItem = {};
|
||||||
serverAutoRoles: MenuItem = {};
|
serverAutoRoles: MenuItem = {};
|
||||||
serverLevels: MenuItem = {};
|
serverLevels: MenuItem = {};
|
||||||
|
serverAchievements: MenuItem = {};
|
||||||
serverMenu: MenuItem = {};
|
serverMenu: MenuItem = {};
|
||||||
adminConfig: MenuItem = {};
|
adminConfig: MenuItem = {};
|
||||||
adminUsers: MenuItem = {};
|
adminUsers: MenuItem = {};
|
||||||
@ -102,12 +103,19 @@ export class SidebarService {
|
|||||||
routerLink: `server/${this.server$.value?.id}/levels`
|
routerLink: `server/${this.server$.value?.id}/levels`
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.serverAchievements = {
|
||||||
|
label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.achievements") : "",
|
||||||
|
icon: "pi pi-angle-double-up",
|
||||||
|
visible: true,
|
||||||
|
routerLink: `server/${this.server$.value?.id}/achievements`
|
||||||
|
};
|
||||||
|
|
||||||
this.serverMenu = {
|
this.serverMenu = {
|
||||||
label: this.isSidebarOpen ? this.server$.value?.name : "",
|
label: this.isSidebarOpen ? this.server$.value?.name : "",
|
||||||
icon: "pi pi-server",
|
icon: "pi pi-server",
|
||||||
visible: false,
|
visible: false,
|
||||||
expanded: true,
|
expanded: true,
|
||||||
items: [this.serverDashboard, this.serverProfile, this.serverMembers, this.serverAutoRoles, this.serverLevels]
|
items: [this.serverDashboard, this.serverProfile, this.serverMembers, this.serverAutoRoles, this.serverLevels, this.serverAchievements]
|
||||||
};
|
};
|
||||||
this.adminConfig = {
|
this.adminConfig = {
|
||||||
label: this.isSidebarOpen ? this.translateService.instant("sidebar.config") : "",
|
label: this.isSidebarOpen ? this.translateService.instant("sidebar.config") : "",
|
||||||
@ -142,6 +150,7 @@ export class SidebarService {
|
|||||||
this.serverMembers.visible = !!user?.isModerator;
|
this.serverMembers.visible = !!user?.isModerator;
|
||||||
this.serverAutoRoles.visible = !!user?.isModerator;
|
this.serverAutoRoles.visible = !!user?.isModerator;
|
||||||
this.serverLevels.visible = !!user?.isModerator;
|
this.serverLevels.visible = !!user?.isModerator;
|
||||||
|
this.serverAchievements.visible = !!user?.isModerator;
|
||||||
} else {
|
} else {
|
||||||
this.serverMenu.visible = false;
|
this.serverMenu.visible = false;
|
||||||
}
|
}
|
||||||
|
@ -397,6 +397,32 @@
|
|||||||
"level_update_failed_d": "Die Bearbeitung des Levels ist fehlgeschlagen!"
|
"level_update_failed_d": "Die Bearbeitung des Levels ist fehlgeschlagen!"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"achievements": {
|
||||||
|
"header": "Errungenschaften",
|
||||||
|
"headers": {
|
||||||
|
"name": "Name",
|
||||||
|
"attribute": "Attribut",
|
||||||
|
"operator": "Operator",
|
||||||
|
"value": "Wert"
|
||||||
|
},
|
||||||
|
"achievements": "Errungenschaften",
|
||||||
|
"message": {
|
||||||
|
"achievement_create": "Errungenschaft erstellt",
|
||||||
|
"achievement_create_d": "Errungenschaft {{name}} erfolgreich erstellt",
|
||||||
|
"achievement_create_failed": "Errungenschaft Erstellung fehlgeschlagen",
|
||||||
|
"achievement_create_failed_d": "Die Erstellung der Errungenschaft ist fehlgeschlagen!",
|
||||||
|
"achievement_delete": "Errungenschaft löschen",
|
||||||
|
"achievement_delete_failed": "Errungenschaft Löschung fehlgeschlagen",
|
||||||
|
"achievement_delete_failed_d": "Die Löschung der Errungenschaft {{name}} ist fehlgeschlagen!",
|
||||||
|
"achievement_delete_q": "Sind Sie sich sicher, dass Sie das Errungenschaft {{name}} löschen möchten?",
|
||||||
|
"achievement_deleted": "Errungenschaft gelöscht",
|
||||||
|
"achievement_deleted_d": "Errungenschaft {{name}} erfolgreich gelöscht",
|
||||||
|
"achievement_update": "Errungenschaft bearbeitet",
|
||||||
|
"achievement_update_d": "Errungenschaft {{name}} erfolgreich bearbeitet",
|
||||||
|
"achievement_update_failed": "Errungenschaft Bearbeitung fehlgeschlagen",
|
||||||
|
"achievement_update_failed_d": "Die Bearbeitung der Errungenschaft ist fehlgeschlagen!"
|
||||||
|
}
|
||||||
|
},
|
||||||
"members": {
|
"members": {
|
||||||
"header": "Mitglieder",
|
"header": "Mitglieder",
|
||||||
"headers": {
|
"headers": {
|
||||||
|
Loading…
Reference in New Issue
Block a user