Improved data validation for import
This commit is contained in:
parent
2d358188af
commit
84fedfaa0b
@ -41,6 +41,9 @@ class LevelMutation(QueryABC):
|
|||||||
int(input["permissions"]),
|
int(input["permissions"]),
|
||||||
server,
|
server,
|
||||||
)
|
)
|
||||||
|
levels = self._levels.get_levels_by_server_id(server.id)
|
||||||
|
if levels.where(lambda x: x.name == level.name).count() > 0:
|
||||||
|
raise ValueError(f"Level with name {level.name} already exists")
|
||||||
self._levels.add_level(level)
|
self._levels.add_level(level)
|
||||||
self._db.save_changes()
|
self._db.save_changes()
|
||||||
|
|
||||||
|
@ -1,58 +1,65 @@
|
|||||||
import { Level } from "../models/data/level.model";
|
|
||||||
|
|
||||||
export interface Column {
|
export interface Column {
|
||||||
key: string;
|
key: string;
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ComponentWithTable {
|
export class ComponentWithTable {
|
||||||
private _hiddenColumns: Column[] = [];
|
private _hiddenColumns: Column[] = [];
|
||||||
set hiddenColumns(value: Column[]) {
|
set hiddenColumns(value: Column[]) {
|
||||||
this._hiddenColumns = value;
|
this._hiddenColumns = value;
|
||||||
localStorage.setItem("hiddenColumns", JSON.stringify(value));
|
localStorage.setItem("hiddenColumns", JSON.stringify(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
get hiddenColumns(): Column[] {
|
||||||
|
return this._hiddenColumns;
|
||||||
|
}
|
||||||
|
|
||||||
|
public name: string = "";
|
||||||
|
public columns: Column[] = [];
|
||||||
|
public isEditingNew: boolean = false;
|
||||||
|
|
||||||
|
public callback = (data: any[], isNew: boolean) => {
|
||||||
|
this.save(data, isNew);
|
||||||
|
};
|
||||||
|
public validator: (oldElement: any, newElement: any) => boolean = (oldElement: any, newElement: any) => {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
name: string,
|
||||||
|
columns: string[],
|
||||||
|
validator?: (oldElement: any, newElement: any) => boolean
|
||||||
|
) {
|
||||||
|
this.name = name;
|
||||||
|
this.columns = columns.map(column => {
|
||||||
|
return { key: this.getKey(column), name: column };
|
||||||
|
});
|
||||||
|
let hiddenColumns = localStorage.getItem("hiddenColumns");
|
||||||
|
if (!hiddenColumns) {
|
||||||
|
localStorage.setItem("hiddenColumns", JSON.stringify([{}]));
|
||||||
|
hiddenColumns = localStorage.getItem("hiddenColumns") ?? JSON.stringify([{}]);
|
||||||
}
|
}
|
||||||
|
this._hiddenColumns = JSON.parse(hiddenColumns);
|
||||||
get hiddenColumns(): Column[] {
|
if (validator) {
|
||||||
return this._hiddenColumns;
|
this.validator = validator;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public name: string = "";
|
private getKey(column: string): string {
|
||||||
public columns: Column[] = [];
|
return `${this.name}_${column}`;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(
|
public isColumnVisible(column: string): boolean {
|
||||||
name: string,
|
return !this._hiddenColumns.map(column => column.key).includes(this.getKey(column));
|
||||||
columns: string[]
|
}
|
||||||
) {
|
|
||||||
this.name = name;
|
public onRowEditSave(newLevel: any, index: number) {
|
||||||
this.columns = columns.map(column => {
|
}
|
||||||
return { key: this.getKey(column), name: column };
|
|
||||||
});
|
public save(data: any[], isNew: boolean) {
|
||||||
let hiddenColumns = localStorage.getItem("hiddenColumns");
|
for (let i = 0; i < data.length; i++) {
|
||||||
if (!hiddenColumns) {
|
this.isEditingNew = isNew;
|
||||||
localStorage.setItem("hiddenColumns", JSON.stringify([{}]));
|
this.onRowEditSave(data[i], i);
|
||||||
hiddenColumns = localStorage.getItem("hiddenColumns") ?? JSON.stringify([{}]);
|
|
||||||
}
|
|
||||||
this._hiddenColumns = JSON.parse(hiddenColumns);
|
|
||||||
}
|
|
||||||
|
|
||||||
private getKey(column: string): string {
|
|
||||||
return `${this.name}_${column}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
public isColumnVisible(column: string): boolean {
|
|
||||||
return !this._hiddenColumns.map(column => column.key).includes(this.getKey(column));
|
|
||||||
}
|
|
||||||
|
|
||||||
public callback = (data: any[]) => {
|
|
||||||
this.save(data);
|
|
||||||
};
|
|
||||||
|
|
||||||
public onRowEditSave(newLevel: any, index: number) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public save(data: any[]) {
|
|
||||||
for (let i = 0; i < data.length; i++) {
|
|
||||||
this.onRowEditSave(data[i], i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,6 @@ export class AuthUserComponent extends ComponentWithTable implements OnInit, OnD
|
|||||||
activityValues: number[] = [0, 100];
|
activityValues: number[] = [0, 100];
|
||||||
|
|
||||||
clonedUsers: { [s: string]: AuthUserDTO; } = {};
|
clonedUsers: { [s: string]: AuthUserDTO; } = {};
|
||||||
isEditingNew: boolean = false;
|
|
||||||
|
|
||||||
authRoles = [
|
authRoles = [
|
||||||
{ label: AuthRoles[AuthRoles.Normal].toString(), value: AuthRoles.Normal },
|
{ label: AuthRoles[AuthRoles.Normal].toString(), value: AuthRoles.Normal },
|
||||||
|
@ -1,66 +1,86 @@
|
|||||||
import { Component, EventEmitter, Input, Output, ViewChild } from "@angular/core";
|
import { Component, EventEmitter, Input, Output, ViewChild } from "@angular/core";
|
||||||
import { ToastService } from "../../../../services/toast/toast.service";
|
import { ToastService } from "../../../../services/toast/toast.service";
|
||||||
import { TranslateService } from "@ngx-translate/core";
|
import { TranslateService } from "@ngx-translate/core";
|
||||||
|
import { elementAt } from "rxjs";
|
||||||
|
|
||||||
interface UploadEvent {
|
interface UploadEvent {
|
||||||
originalEvent: Event;
|
originalEvent: Event;
|
||||||
files: File[];
|
files: File[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-data-import-and-export",
|
selector: "app-data-import-and-export",
|
||||||
templateUrl: "./data-import-and-export.component.html",
|
templateUrl: "./data-import-and-export.component.html",
|
||||||
styleUrls: ["./data-import-and-export.component.scss"]
|
styleUrls: ["./data-import-and-export.component.scss"]
|
||||||
})
|
})
|
||||||
export class DataImportAndExportComponent {
|
export class DataImportAndExportComponent {
|
||||||
|
|
||||||
@ViewChild("upload") upload: any;
|
@ViewChild("upload") upload: any;
|
||||||
|
|
||||||
private _data: any[] = [];
|
private _data: any[] = [];
|
||||||
|
|
||||||
@Input() name: string = "";
|
@Input() name: string = "";
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
set data(data: any[]) {
|
set data(data: any[]) {
|
||||||
this._data = data;
|
this._data = data;
|
||||||
this.dataChange.emit(data);
|
this.dataChange.emit(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
get data(): any[] {
|
get data(): any[] {
|
||||||
return this._data;
|
return this._data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Output() dataChange: EventEmitter<any[]> = new EventEmitter<any[]>();
|
@Output() dataChange: EventEmitter<any[]> = new EventEmitter<any[]>();
|
||||||
@Input() callback!: (data: any[]) => void;
|
@Input() callback!: (data: any[], isNew: boolean) => void;
|
||||||
|
@Input() validator: (oldElement: any, newElement: any) => boolean = (oldElement: any, newElement: any) => {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
private toastService: ToastService,
|
private toastService: ToastService,
|
||||||
private translate: TranslateService
|
private translate: TranslateService
|
||||||
) {
|
) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public export() {
|
public export() {
|
||||||
const json = JSON.stringify(this.data);
|
const json = JSON.stringify(this.data);
|
||||||
const element = document.createElement("a");
|
const element = document.createElement("a");
|
||||||
element.setAttribute("href", "data:application/json;charset=UTF-8," + encodeURIComponent(json));
|
element.setAttribute("href", "data:application/json;charset=UTF-8," + encodeURIComponent(json));
|
||||||
element.setAttribute("download", `${this.name}.json`);
|
element.setAttribute("download", `${this.name}.json`);
|
||||||
element.style.display = "none";
|
element.style.display = "none";
|
||||||
document.body.appendChild(element);
|
document.body.appendChild(element);
|
||||||
element.click(); // simulate click
|
element.click(); // simulate click
|
||||||
document.body.removeChild(element);
|
document.body.removeChild(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
public import(event: { files: File[] }) {
|
public import(event: { files: File[] }) {
|
||||||
const file = event.files[0];
|
const file = event.files[0];
|
||||||
const fileReader = new FileReader();
|
const fileReader = new FileReader();
|
||||||
fileReader.onload = () => {
|
fileReader.onload = () => {
|
||||||
if (!fileReader.result) return;
|
if (!fileReader.result) return;
|
||||||
this.data = JSON.parse(fileReader.result.toString());
|
const newData: any[] = JSON.parse(fileReader.result.toString());
|
||||||
this.upload.clear();
|
this.upload.clear();
|
||||||
this.callback(this.data);
|
newData.forEach(element => {
|
||||||
this.toastService.success(this.translate.instant("common.file.uploaded"), this.translate.instant("common.file.uploaded"));
|
element.id = 0;
|
||||||
};
|
});
|
||||||
fileReader.readAsText(file, "UTF-8");
|
this.data.forEach(element => {
|
||||||
}
|
const existingElement = newData.find(x => this.validator(x, element));
|
||||||
|
if (existingElement) {
|
||||||
|
const index = this.data.indexOf(element);
|
||||||
|
const oldId = element.id;
|
||||||
|
element = existingElement;
|
||||||
|
element.id = oldId;
|
||||||
|
this.data[index] = element;
|
||||||
|
newData.splice(newData.indexOf(existingElement), 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.callback(this.data, false);
|
||||||
|
this.callback(newData, true);
|
||||||
|
this.data.push(...newData);
|
||||||
|
this.toastService.success(this.translate.instant("common.file.uploaded"), this.translate.instant("common.file.uploaded"));
|
||||||
|
};
|
||||||
|
fileReader.readAsText(file, "UTF-8");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
class="icon-btn btn" (click)="resetFilters()">
|
class="icon-btn btn" (click)="resetFilters()">
|
||||||
</button>
|
</button>
|
||||||
<app-data-import-and-export name="achievements" [(data)]="achievements"
|
<app-data-import-and-export name="achievements" [(data)]="achievements"
|
||||||
[callback]="callback"></app-data-import-and-export>
|
[callback]="callback" [validator]="validator"></app-data-import-and-export>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -15,7 +15,13 @@ import { TranslateService } from "@ngx-translate/core";
|
|||||||
import { DataService } from "../../../../../../services/data/data.service";
|
import { DataService } from "../../../../../../services/data/data.service";
|
||||||
import { SidebarService } from "../../../../../../services/sidebar/sidebar.service";
|
import { SidebarService } from "../../../../../../services/sidebar/sidebar.service";
|
||||||
import { ActivatedRoute } from "@angular/router";
|
import { ActivatedRoute } from "@angular/router";
|
||||||
import { AchievementListQuery, AchievementTypeQuery, GameServerListQuery, LevelListQuery, Query } from "../../../../../../models/graphql/query.model";
|
import {
|
||||||
|
AchievementListQuery,
|
||||||
|
AchievementTypeQuery,
|
||||||
|
GameServerListQuery,
|
||||||
|
LevelListQuery,
|
||||||
|
Query
|
||||||
|
} from "../../../../../../models/graphql/query.model";
|
||||||
import { catchError, debounceTime, takeUntil } from "rxjs/operators";
|
import { catchError, debounceTime, takeUntil } from "rxjs/operators";
|
||||||
import { LazyLoadEvent, MenuItem } from "primeng/api";
|
import { LazyLoadEvent, MenuItem } from "primeng/api";
|
||||||
import { Table } from "primeng/table";
|
import { Table } from "primeng/table";
|
||||||
@ -33,8 +39,6 @@ export class AchievementComponent extends ComponentWithTable implements OnInit,
|
|||||||
public achievements: Achievement[] = [];
|
public achievements: Achievement[] = [];
|
||||||
public loading = true;
|
public loading = true;
|
||||||
|
|
||||||
public isEditingNew: boolean = false;
|
|
||||||
|
|
||||||
public filterForm!: FormGroup<{
|
public filterForm!: FormGroup<{
|
||||||
id: FormControl<number | null>,
|
id: FormControl<number | null>,
|
||||||
name: FormControl<string | null>,
|
name: FormControl<string | null>,
|
||||||
@ -81,7 +85,10 @@ export class AchievementComponent extends ComponentWithTable implements OnInit,
|
|||||||
private data: DataService,
|
private data: DataService,
|
||||||
private sidebar: SidebarService,
|
private sidebar: SidebarService,
|
||||||
private route: ActivatedRoute) {
|
private route: ActivatedRoute) {
|
||||||
super("achievement", ["id", "name", "description", "attribute", "operator", "value"]);
|
super("achievement", ["id", "name", "description", "attribute", "operator", "value"],
|
||||||
|
(oldElement: Achievement, newElement: Achievement) => {
|
||||||
|
return oldElement.name === newElement.name;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ngOnInit(): void {
|
public ngOnInit(): void {
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
class="icon-btn btn" (click)="resetFilters()">
|
class="icon-btn btn" (click)="resetFilters()">
|
||||||
</button>
|
</button>
|
||||||
<app-data-import-and-export name="achievements" [(data)]="rules"
|
<app-data-import-and-export name="achievements" [(data)]="rules"
|
||||||
[callback]="callback"></app-data-import-and-export>
|
[callback]="callback" [validator]="validator"></app-data-import-and-export>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||||
import { DataService } from "../../../../../../services/data/data.service";
|
import { DataService } from "../../../../../../services/data/data.service";
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
import { AutoRoleRule, AutoRoleRuleFilter } from "../../../../../../models/data/auto_role.model";
|
import { AutoRole, AutoRoleRule, AutoRoleRuleFilter } from "../../../../../../models/data/auto_role.model";
|
||||||
import { Guild } from "../../../../../../models/data/discord.model";
|
import { Guild } from "../../../../../../models/data/discord.model";
|
||||||
import { LazyLoadEvent, MenuItem } from "primeng/api";
|
import { LazyLoadEvent, MenuItem } from "primeng/api";
|
||||||
import { User } from "../../../../../../models/data/user.model";
|
import { User } from "../../../../../../models/data/user.model";
|
||||||
@ -40,7 +40,6 @@ export class AutoRolesRulesComponent extends ComponentWithTable implements OnIni
|
|||||||
autoRoleId!: number;
|
autoRoleId!: number;
|
||||||
|
|
||||||
clonedUsers: { [s: string]: User; } = {};
|
clonedUsers: { [s: string]: User; } = {};
|
||||||
isEditingNew: boolean = false;
|
|
||||||
|
|
||||||
newAutoRoleTemplate: AutoRoleRule = {
|
newAutoRoleTemplate: AutoRoleRule = {
|
||||||
createdAt: "",
|
createdAt: "",
|
||||||
@ -81,7 +80,10 @@ export class AutoRolesRulesComponent extends ComponentWithTable implements OnIni
|
|||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private router: Router
|
private router: Router
|
||||||
) {
|
) {
|
||||||
super("auto-role-rules", ["id", "role", "emoji"]);
|
super("auto-role-rules", ["id", "role", "emoji"], (oldElement: AutoRoleRule, newElement: AutoRoleRule) => {
|
||||||
|
return oldElement.autoRole?.id === newElement.autoRole?.id &&
|
||||||
|
oldElement.roleId === newElement.roleId;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public getEmojiUrl(name: string): string {
|
public getEmojiUrl(name: string): string {
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
class="icon-btn btn" (click)="resetFilters()">
|
class="icon-btn btn" (click)="resetFilters()">
|
||||||
</button>
|
</button>
|
||||||
<app-data-import-and-export name="achievements" [(data)]="auto_roles"
|
<app-data-import-and-export name="achievements" [(data)]="auto_roles"
|
||||||
[callback]="callback"></app-data-import-and-export>
|
[callback]="callback" [validator]="validator"></app-data-import-and-export>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -36,7 +36,6 @@ export class AutoRolesComponent extends ComponentWithTable implements OnInit, On
|
|||||||
loading = true;
|
loading = true;
|
||||||
|
|
||||||
clonedUsers: { [s: string]: User; } = {};
|
clonedUsers: { [s: string]: User; } = {};
|
||||||
isEditingNew: boolean = false;
|
|
||||||
|
|
||||||
newAutoRoleTemplate: AutoRole = {
|
newAutoRoleTemplate: AutoRole = {
|
||||||
createdAt: "",
|
createdAt: "",
|
||||||
@ -77,7 +76,10 @@ export class AutoRolesComponent extends ComponentWithTable implements OnInit, On
|
|||||||
private sidebar: SidebarService,
|
private sidebar: SidebarService,
|
||||||
private route: ActivatedRoute
|
private route: ActivatedRoute
|
||||||
) {
|
) {
|
||||||
super("auto-role", ["id", "channel_id", "channel_name", "message_id", "rule_count"]);
|
super("auto-role", ["id", "channel_id", "channel_name", "message_id", "rule_count"], (oldElement: AutoRole, newElement: AutoRole) => {
|
||||||
|
return oldElement.channelId === newElement.channelId &&
|
||||||
|
oldElement.messageId === newElement.messageId;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ngOnInit(): void {
|
public ngOnInit(): void {
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
class="icon-btn btn" (click)="resetFilters()">
|
class="icon-btn btn" (click)="resetFilters()">
|
||||||
</button>
|
</button>
|
||||||
<app-data-import-and-export name="levels" [(data)]="levels"
|
<app-data-import-and-export name="levels" [(data)]="levels"
|
||||||
[callback]="callback"></app-data-import-and-export>
|
[callback]="callback" [validator]="validator"></app-data-import-and-export>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -19,247 +19,247 @@ import { Table } from "primeng/table";
|
|||||||
import { User } from "../../../../../../models/data/user.model";
|
import { User } from "../../../../../../models/data/user.model";
|
||||||
import { LevelMutationResult, UpdateUserMutationResult } from "../../../../../../models/graphql/result.model";
|
import { LevelMutationResult, UpdateUserMutationResult } from "../../../../../../models/graphql/result.model";
|
||||||
import { Mutations } from "../../../../../../models/graphql/mutations.model";
|
import { Mutations } from "../../../../../../models/graphql/mutations.model";
|
||||||
import { Subject, throwError } from "rxjs";
|
import { forkJoin, Subject, throwError } from "rxjs";
|
||||||
import { Server } from "../../../../../../models/data/server.model";
|
import { Server } from "../../../../../../models/data/server.model";
|
||||||
import { UserDTO } from "../../../../../../models/auth/auth-user.dto";
|
import { UserDTO } from "../../../../../../models/auth/auth-user.dto";
|
||||||
import { ComponentWithTable } from "../../../../../../base/component-with-table";
|
import { ComponentWithTable } from "../../../../../../base/component-with-table";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-levels",
|
selector: "app-levels",
|
||||||
templateUrl: "./levels.component.html",
|
templateUrl: "./levels.component.html",
|
||||||
styleUrls: ["./levels.component.scss"]
|
styleUrls: ["./levels.component.scss"]
|
||||||
})
|
})
|
||||||
export class LevelsComponent extends ComponentWithTable implements OnInit, OnDestroy {
|
export class LevelsComponent extends ComponentWithTable implements OnInit, OnDestroy {
|
||||||
public levels: Level[] = [];
|
public levels: Level[] = [];
|
||||||
public loading = true;
|
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 filterForm!: FormGroup<{
|
public filter: LevelFilter = {};
|
||||||
id: FormControl<number | null>,
|
public page: Page = {
|
||||||
name: FormControl<string | null>,
|
pageSize: undefined,
|
||||||
color: FormControl<string | null>,
|
pageIndex: undefined
|
||||||
min_xp: FormControl<number | null>,
|
};
|
||||||
permissions: FormControl<string | null>,
|
public sort: Sort = {
|
||||||
}>;
|
sortColumn: undefined,
|
||||||
|
sortDirection: undefined
|
||||||
|
};
|
||||||
|
|
||||||
public filter: LevelFilter = {};
|
public totalRecords: number = 0;
|
||||||
public page: Page = {
|
|
||||||
pageSize: undefined,
|
|
||||||
pageIndex: undefined
|
|
||||||
};
|
|
||||||
public sort: Sort = {
|
|
||||||
sortColumn: undefined,
|
|
||||||
sortDirection: undefined
|
|
||||||
};
|
|
||||||
|
|
||||||
public totalRecords: number = 0;
|
public clonedLevels: { [s: string]: Level; } = {};
|
||||||
|
|
||||||
public clonedLevels: { [s: string]: Level; } = {};
|
private unsubscriber = new Subject<void>();
|
||||||
|
private server: Server = {};
|
||||||
|
public user: UserDTO | null = null;
|
||||||
|
|
||||||
private unsubscriber = new Subject<void>();
|
query: string = Queries.levelWithHistoryQuery;
|
||||||
private server: Server = {};
|
|
||||||
public user: UserDTO | null = null;
|
|
||||||
|
|
||||||
query: string = Queries.levelWithHistoryQuery;
|
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
|
||||||
|
) {
|
||||||
|
super("level", ["id", "name", "color", "min_xp", "permissions"], (oldElement: Level, newElement: Level) => {
|
||||||
|
return oldElement.name === newElement.name;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public constructor(
|
public ngOnInit(): void {
|
||||||
private authService: AuthService,
|
this.setFilterForm();
|
||||||
private spinner: SpinnerService,
|
this.data.getServerFromRoute(this.route).then(async server => {
|
||||||
private toastService: ToastService,
|
this.server = server;
|
||||||
private confirmDialog: ConfirmationDialogService,
|
this.loadNextPage();
|
||||||
private fb: FormBuilder,
|
let authUser = await this.authService.getLoggedInUser();
|
||||||
private translate: TranslateService,
|
this.user = authUser?.users?.find(u => u.server == this.server.id) ?? null;
|
||||||
private data: DataService,
|
});
|
||||||
private sidebar: SidebarService,
|
}
|
||||||
private route: ActivatedRoute
|
|
||||||
) {
|
public ngOnDestroy(): void {
|
||||||
super("level", ["id", "name", "color", "min_xp", "permissions"]);
|
this.unsubscriber.next();
|
||||||
|
this.unsubscriber.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public loadNextPage(): void {
|
||||||
|
this.loading = true;
|
||||||
|
this.data.query<LevelListQuery>(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<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 newLevelTemplate: Level = {
|
||||||
|
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 override onRowEditSave(newLevel: Level, index: number): void {
|
||||||
|
if (this.isEditingNew && JSON.stringify(newLevel) === JSON.stringify(this.newLevelTemplate)) {
|
||||||
|
this.isEditingNew = false;
|
||||||
|
this.levels.splice(index, 1);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ngOnInit(): void {
|
if (!newLevel.id && !this.isEditingNew || !newLevel.minXp && !newLevel?.name && !newLevel?.permissions) {
|
||||||
this.setFilterForm();
|
return;
|
||||||
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 {
|
if (this.isEditingNew) {
|
||||||
this.unsubscriber.next();
|
this.spinner.showSpinner();
|
||||||
this.unsubscriber.complete();
|
this.data.mutation<LevelMutationResult>(Mutations.createLevel, {
|
||||||
}
|
name: newLevel.name,
|
||||||
|
color: newLevel.color,
|
||||||
public loadNextPage(): void {
|
minXp: newLevel.minXp,
|
||||||
this.loading = true;
|
permissions: newLevel.permissions,
|
||||||
this.data.query<LevelListQuery>(Queries.levelQuery, {
|
serverId: this.server.id
|
||||||
serverId: this.server.id, filter: this.filter, page: this.page, sort: this.sort
|
}
|
||||||
},
|
).pipe(catchError(err => {
|
||||||
(data: Query) => {
|
this.isEditingNew = false;
|
||||||
return data.servers[0];
|
this.spinner.hideSpinner();
|
||||||
}
|
return throwError(err);
|
||||||
).subscribe(data => {
|
})).subscribe(result => {
|
||||||
this.totalRecords = data.levelCount;
|
this.isEditingNew = false;
|
||||||
this.levels = data.levels;
|
this.spinner.hideSpinner();
|
||||||
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.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 newLevelTemplate: Level = {
|
|
||||||
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();
|
this.loadNextPage();
|
||||||
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
public resetFilters(): void {
|
this.spinner.showSpinner();
|
||||||
this.filterForm.reset();
|
this.data.mutation<UpdateUserMutationResult>(Mutations.updateLevel, {
|
||||||
|
id: newLevel.id,
|
||||||
|
name: newLevel.name,
|
||||||
|
color: newLevel.color,
|
||||||
|
minXp: newLevel.minXp,
|
||||||
|
permissions: newLevel.permissions
|
||||||
|
}
|
||||||
|
).pipe(catchError(err => {
|
||||||
|
this.spinner.hideSpinner();
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
public onRowEditInit(table: Table, user: User, index: number): void {
|
this.levels[index] = this.clonedLevels[index];
|
||||||
this.clonedLevels[index] = { ...user };
|
delete this.clonedLevels[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
public override onRowEditSave(newLevel: Level, index: number): void {
|
|
||||||
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<LevelMutationResult>(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();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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.spinner.showSpinner();
|
||||||
this.data.mutation<UpdateUserMutationResult>(Mutations.updateLevel, {
|
this.data.mutation<LevelMutationResult>(Mutations.deleteLevel, {
|
||||||
id: newLevel.id,
|
id: level.id
|
||||||
name: newLevel.name,
|
}
|
||||||
color: newLevel.color,
|
|
||||||
minXp: newLevel.minXp,
|
|
||||||
permissions: newLevel.permissions
|
|
||||||
}
|
|
||||||
).pipe(catchError(err => {
|
).pipe(catchError(err => {
|
||||||
this.spinner.hideSpinner();
|
this.spinner.hideSpinner();
|
||||||
return throwError(err);
|
return throwError(err);
|
||||||
})).subscribe(_ => {
|
})).subscribe(l => {
|
||||||
this.spinner.hideSpinner();
|
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.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();
|
this.loadNextPage();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
public addLevel(table: Table): void {
|
||||||
|
const newLevel = JSON.parse(JSON.stringify(this.newLevelTemplate));
|
||||||
|
|
||||||
public onRowEditCancel(index: number): void {
|
this.levels = [newLevel, ...this.levels];
|
||||||
if (this.isEditingNew) {
|
|
||||||
this.levels.splice(index, 1);
|
|
||||||
delete this.clonedLevels[index];
|
|
||||||
this.isEditingNew = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.levels[index] = this.clonedLevels[index];
|
table.initRowEdit(newLevel);
|
||||||
delete this.clonedLevels[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
public deleteLevel(level: Level): void {
|
const index = this.levels.findIndex(l => l.id == newLevel.id);
|
||||||
this.confirmDialog.confirmDialog(
|
this.onRowEditInit(table, newLevel, index);
|
||||||
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<LevelMutationResult>(Mutations.deleteLevel, {
|
|
||||||
id: level.id
|
|
||||||
}
|
|
||||||
).pipe(catchError(err => {
|
|
||||||
this.spinner.hideSpinner();
|
|
||||||
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 {
|
this.isEditingNew = true;
|
||||||
const newLevel = JSON.parse(JSON.stringify(this.newLevelTemplate));
|
}
|
||||||
|
|
||||||
this.levels = [newLevel, ...this.levels];
|
|
||||||
|
|
||||||
table.initRowEdit(newLevel);
|
|
||||||
|
|
||||||
const index = this.levels.findIndex(l => l.id == newLevel.id);
|
|
||||||
this.onRowEditInit(table, newLevel, index);
|
|
||||||
|
|
||||||
this.isEditingNew = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,6 @@ export class MembersComponent extends ComponentWithTable implements OnInit, OnDe
|
|||||||
loading = true;
|
loading = true;
|
||||||
|
|
||||||
clonedUsers: { [s: string]: User; } = {};
|
clonedUsers: { [s: string]: User; } = {};
|
||||||
isEditingNew: boolean = false;
|
|
||||||
|
|
||||||
newUserTemplate: User = {
|
newUserTemplate: User = {
|
||||||
discordId: 0,
|
discordId: 0,
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
class="icon-btn btn" (click)="resetFilters()">
|
class="icon-btn btn" (click)="resetFilters()">
|
||||||
</button>
|
</button>
|
||||||
<app-data-import-and-export name="achievements" [(data)]="shortRoleNames"
|
<app-data-import-and-export name="achievements" [(data)]="shortRoleNames"
|
||||||
[callback]="callback"></app-data-import-and-export>
|
[callback]="callback" [validator]="validator"></app-data-import-and-export>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -33,8 +33,6 @@ export class ShortRoleNamesComponent extends ComponentWithTable implements OnIni
|
|||||||
public shortRoleNames: ShortRoleName[] = [];
|
public shortRoleNames: ShortRoleName[] = [];
|
||||||
public loading = true;
|
public loading = true;
|
||||||
|
|
||||||
public isEditingNew: boolean = false;
|
|
||||||
|
|
||||||
public filterForm!: FormGroup<{
|
public filterForm!: FormGroup<{
|
||||||
id: FormControl<number | null>,
|
id: FormControl<number | null>,
|
||||||
shortName: FormControl<string | null>,
|
shortName: FormControl<string | null>,
|
||||||
@ -75,7 +73,10 @@ export class ShortRoleNamesComponent extends ComponentWithTable implements OnIni
|
|||||||
private sidebar: SidebarService,
|
private sidebar: SidebarService,
|
||||||
private route: ActivatedRoute
|
private route: ActivatedRoute
|
||||||
) {
|
) {
|
||||||
super("short-role-names", ["id", "name", "role", "position"]);
|
super("short-role-names", ["id", "name", "role", "position"], (oldElement: ShortRoleName, newElement: ShortRoleName) => {
|
||||||
|
return oldElement.shortName === newElement.shortName &&
|
||||||
|
oldElement.roleId === newElement.roleId;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ngOnInit(): void {
|
public ngOnInit(): void {
|
||||||
|
Loading…
Reference in New Issue
Block a user