From 33006e3d01f33f87de269ab34b839056401577b0 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Tue, 24 Oct 2023 19:13:47 +0200 Subject: [PATCH] Added data import & export #407 --- web/package.json | 2 +- web/src/app/base/component-with-table.ts | 86 ++-- .../auth-user/auth-user.component.html | 2 +- .../auth-user/auth-user.component.ts | 4 +- .../data-import-and-export.component.html | 10 + .../data-import-and-export.component.scss | 5 + .../data-import-and-export.component.spec.ts | 23 + .../data-import-and-export.component.ts | 66 +++ web/src/app/modules/shared/shared.module.ts | 5 + .../achievement/achievement.component.html | 4 +- .../achievement/achievement.component.ts | 2 +- .../auto-roles-rules.component.html | 4 +- .../auto-roles-rules.component.ts | 2 +- .../auto-roles/auto-roles.component.html | 4 +- .../auto-roles/auto-roles.component.ts | 2 +- .../components/levels/levels.component.html | 412 ++++++++-------- .../components/levels/levels.component.ts | 444 +++++++++--------- .../server/members/members.component.html | 2 +- .../view/server/members/members.component.ts | 10 +- .../short-role-names.component.html | 4 +- .../short-role-names.component.ts | 2 +- web/src/assets/i18n/de.json | 3 + web/src/assets/i18n/en.json | 3 + web/src/assets/version.json | 2 +- 24 files changed, 617 insertions(+), 486 deletions(-) create mode 100644 web/src/app/modules/shared/components/data-import-and-export/data-import-and-export.component.html create mode 100644 web/src/app/modules/shared/components/data-import-and-export/data-import-and-export.component.scss create mode 100644 web/src/app/modules/shared/components/data-import-and-export/data-import-and-export.component.spec.ts create mode 100644 web/src/app/modules/shared/components/data-import-and-export/data-import-and-export.component.ts diff --git a/web/package.json b/web/package.json index c01deb92..a37690f6 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "web", - "version": "1.2.0", + "version": "1.2.dev407", "scripts": { "ng": "ng", "update-version": "ts-node update-version.ts", diff --git a/web/src/app/base/component-with-table.ts b/web/src/app/base/component-with-table.ts index 9386a28f..d38e09c9 100644 --- a/web/src/app/base/component-with-table.ts +++ b/web/src/app/base/component-with-table.ts @@ -1,44 +1,58 @@ +import { Level } from "../models/data/level.model"; + export interface Column { - key: string; - name: string; + key: string; + name: string; } export class ComponentWithTable { - - private _hiddenColumns: Column[] = []; - set hiddenColumns(value: Column[]) { - this._hiddenColumns = value; - localStorage.setItem("hiddenColumns", JSON.stringify(value)); - } - - get hiddenColumns(): Column[] { - return this._hiddenColumns; - } - - public name: string = ""; - public columns: Column[] = []; - - constructor( - name: string, - columns: string[] - ) { - 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([{}]); + private _hiddenColumns: Column[] = []; + set hiddenColumns(value: Column[]) { + this._hiddenColumns = value; + localStorage.setItem("hiddenColumns", JSON.stringify(value)); } - this._hiddenColumns = JSON.parse(hiddenColumns); - } - private getKey(column: string): string { - return `${this.name}_${column}`; - } + get hiddenColumns(): Column[] { + return this._hiddenColumns; + } - public isColumnVisible(column: string): boolean { - return !this._hiddenColumns.map(column => column.key).includes(this.getKey(column)); - } + public name: string = ""; + public columns: Column[] = []; + + constructor( + name: string, + columns: string[] + ) { + 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); + } + + 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); + } + } } diff --git a/web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.html b/web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.html index a61ff338..a8d34658 100644 --- a/web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.html +++ b/web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.html @@ -225,7 +225,7 @@ (click)="deleteUser(user)"> + icon="pi pi-check-circle" (click)="onRowEditSave(user, ri)"> diff --git a/web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.ts b/web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.ts index e0df3efb..cb69d8c2 100644 --- a/web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.ts +++ b/web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.ts @@ -193,7 +193,7 @@ export class AuthUserComponent extends ComponentWithTable implements OnInit, OnD this.clonedUsers[index] = { ...user }; } - onRowEditSave(table: Table, newUser: AuthUserDTO, index: number) { + public override onRowEditSave(newUser: AuthUserDTO, index: number) { const oldUser = this.clonedUsers[index]; delete this.clonedUsers[index]; @@ -219,7 +219,6 @@ export class AuthUserComponent extends ComponentWithTable implements OnInit, OnD newUser.email == "" ) ) { - table.initRowEdit(newUser); return; } @@ -239,7 +238,6 @@ export class AuthUserComponent extends ComponentWithTable implements OnInit, OnD this.toastService.error(this.translate.instant("admin.auth_users.message.user_already_exists"), this.translate.instant("admin.auth_users.message.user_already_exists_d", { email: newUser.email })); } error.error = null; - table.initRowEdit(newUser); } this.spinnerService.hideSpinner(); diff --git a/web/src/app/modules/shared/components/data-import-and-export/data-import-and-export.component.html b/web/src/app/modules/shared/components/data-import-and-export/data-import-and-export.component.html new file mode 100644 index 00000000..4dc66234 --- /dev/null +++ b/web/src/app/modules/shared/components/data-import-and-export/data-import-and-export.component.html @@ -0,0 +1,10 @@ + + + + diff --git a/web/src/app/modules/shared/components/data-import-and-export/data-import-and-export.component.scss b/web/src/app/modules/shared/components/data-import-and-export/data-import-and-export.component.scss new file mode 100644 index 00000000..f22d5334 --- /dev/null +++ b/web/src/app/modules/shared/components/data-import-and-export/data-import-and-export.component.scss @@ -0,0 +1,5 @@ +:host { + display: flex; + flex-direction: row; +} + diff --git a/web/src/app/modules/shared/components/data-import-and-export/data-import-and-export.component.spec.ts b/web/src/app/modules/shared/components/data-import-and-export/data-import-and-export.component.spec.ts new file mode 100644 index 00000000..6c059443 --- /dev/null +++ b/web/src/app/modules/shared/components/data-import-and-export/data-import-and-export.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DataImportAndExportComponent } from './data-import-and-export.component'; + +describe('DataImportAndExportComponent', () => { + let component: DataImportAndExportComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ DataImportAndExportComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(DataImportAndExportComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/web/src/app/modules/shared/components/data-import-and-export/data-import-and-export.component.ts b/web/src/app/modules/shared/components/data-import-and-export/data-import-and-export.component.ts new file mode 100644 index 00000000..1a4ef75c --- /dev/null +++ b/web/src/app/modules/shared/components/data-import-and-export/data-import-and-export.component.ts @@ -0,0 +1,66 @@ +import { Component, EventEmitter, Input, Output, ViewChild } from "@angular/core"; +import { ToastService } from "../../../../services/toast/toast.service"; +import { TranslateService } from "@ngx-translate/core"; + +interface UploadEvent { + originalEvent: Event; + files: File[]; +} + +@Component({ + selector: "app-data-import-and-export", + templateUrl: "./data-import-and-export.component.html", + styleUrls: ["./data-import-and-export.component.scss"] +}) +export class DataImportAndExportComponent { + + @ViewChild("upload") upload: any; + + private _data: any[] = []; + + @Input() name: string = ""; + + @Input() + set data(data: any[]) { + this._data = data; + this.dataChange.emit(data); + } + + get data(): any[] { + return this._data; + } + + @Output() dataChange: EventEmitter = new EventEmitter(); + @Input() callback!: (data: any[]) => void; + + public constructor( + private toastService: ToastService, + private translate: TranslateService + ) { + + } + + public export() { + const json = JSON.stringify(this.data); + const element = document.createElement("a"); + element.setAttribute("href", "data:application/json;charset=UTF-8," + encodeURIComponent(json)); + element.setAttribute("download", `${this.name}.json`); + element.style.display = "none"; + document.body.appendChild(element); + element.click(); // simulate click + document.body.removeChild(element); + } + + public import(event: { files: File[] }) { + const file = event.files[0]; + const fileReader = new FileReader(); + fileReader.onload = () => { + if (!fileReader.result) return; + this.data = JSON.parse(fileReader.result.toString()); + this.upload.clear(); + this.callback(this.data); + this.toastService.success(this.translate.instant("common.file.uploaded"), this.translate.instant("common.file.uploaded")); + }; + fileReader.readAsText(file, "UTF-8"); + } +} diff --git a/web/src/app/modules/shared/shared.module.ts b/web/src/app/modules/shared/shared.module.ts index f05452c0..d4ce44bf 100644 --- a/web/src/app/modules/shared/shared.module.ts +++ b/web/src/app/modules/shared/shared.module.ts @@ -33,6 +33,8 @@ import { MultiSelectColumnsComponent } from './base/multi-select-columns/multi-s import { FeatureFlagListComponent } from './components/feature-flag-list/feature-flag-list.component'; import { InputSwitchModule } from "primeng/inputswitch"; import { CalendarModule } from "primeng/calendar"; +import { DataImportAndExportComponent } from './components/data-import-and-export/data-import-and-export.component'; +import { FileUploadModule } from "primeng/fileupload"; const PrimeNGModules = [ @@ -61,6 +63,7 @@ const PrimeNGModules = [ MultiSelectModule, InputSwitchModule, CalendarModule, + FileUploadModule, ] @NgModule({ @@ -74,6 +77,7 @@ const PrimeNGModules = [ HideableHeaderComponent, MultiSelectColumnsComponent, FeatureFlagListComponent, + DataImportAndExportComponent, ], imports: [ CommonModule, @@ -91,6 +95,7 @@ const PrimeNGModules = [ HideableHeaderComponent, MultiSelectColumnsComponent, FeatureFlagListComponent, + DataImportAndExportComponent ] }) export class SharedModule { diff --git a/web/src/app/modules/view/server/achievements/components/achievement/achievement.component.html b/web/src/app/modules/view/server/achievements/components/achievement/achievement.component.html index a84d3fbc..823db3e1 100644 --- a/web/src/app/modules/view/server/achievements/components/achievement/achievement.component.html +++ b/web/src/app/modules/view/server/achievements/components/achievement/achievement.component.html @@ -27,6 +27,8 @@ + @@ -246,7 +248,7 @@ (click)="deleteAchievement(achievement)" [disabled]="!user || !user.isModerator && !user.isAdmin"> + icon="pi pi-check-circle" (click)="onRowEditSave(achievement, ri)" [disabled]="!user || !user.isModerator && !user.isAdmin"> diff --git a/web/src/app/modules/view/server/achievements/components/achievement/achievement.component.ts b/web/src/app/modules/view/server/achievements/components/achievement/achievement.component.ts index 96625572..18f03c2b 100644 --- a/web/src/app/modules/view/server/achievements/components/achievement/achievement.component.ts +++ b/web/src/app/modules/view/server/achievements/components/achievement/achievement.component.ts @@ -215,7 +215,7 @@ export class AchievementComponent extends ComponentWithTable implements OnInit, this.clonedAchievements[index] = { ...user }; } - public onRowEditSave(table: Table, newAchievement: Achievement, index: number): void { + public override onRowEditSave(newAchievement: Achievement, index: number): void { if (this.isEditingNew && JSON.stringify(newAchievement) === JSON.stringify(this.newAchievementTemplate)) { this.isEditingNew = false; this.achievements.splice(index, 1); diff --git a/web/src/app/modules/view/server/auto-role/components/auto-roles-rules/auto-roles-rules.component.html b/web/src/app/modules/view/server/auto-role/components/auto-roles-rules/auto-roles-rules.component.html index 432bdfae..638c8ad3 100644 --- a/web/src/app/modules/view/server/auto-role/components/auto-roles-rules/auto-roles-rules.component.html +++ b/web/src/app/modules/view/server/auto-role/components/auto-roles-rules/auto-roles-rules.component.html @@ -26,6 +26,8 @@ + @@ -174,7 +176,7 @@ (click)="deleteAutoRoleRule(autoRoleRule)"> + icon="pi pi-check-circle" (click)="onRowEditSave(autoRoleRule, ri)"> diff --git a/web/src/app/modules/view/server/auto-role/components/auto-roles-rules/auto-roles-rules.component.ts b/web/src/app/modules/view/server/auto-role/components/auto-roles-rules/auto-roles-rules.component.ts index f19a8c2f..a8fda8d6 100644 --- a/web/src/app/modules/view/server/auto-role/components/auto-roles-rules/auto-roles-rules.component.ts +++ b/web/src/app/modules/view/server/auto-role/components/auto-roles-rules/auto-roles-rules.component.ts @@ -203,7 +203,7 @@ export class AutoRolesRulesComponent extends ComponentWithTable implements OnIni this.clonedUsers[index] = { ...autoRoleRule }; } - public onRowEditSave(table: Table, newAutoRoleRule: AutoRoleRule, index: number): void { + public override onRowEditSave(newAutoRoleRule: AutoRoleRule, index: number): void { if (this.isEditingNew && JSON.stringify(newAutoRoleRule) === JSON.stringify(this.newAutoRoleTemplate)) { this.isEditingNew = false; this.rules.splice(index, 1); diff --git a/web/src/app/modules/view/server/auto-role/components/auto-roles/auto-roles.component.html b/web/src/app/modules/view/server/auto-role/components/auto-roles/auto-roles.component.html index 12f1448c..7784981d 100644 --- a/web/src/app/modules/view/server/auto-role/components/auto-roles/auto-roles.component.html +++ b/web/src/app/modules/view/server/auto-role/components/auto-roles/auto-roles.component.html @@ -27,6 +27,8 @@ + @@ -209,7 +211,7 @@ (click)="deleteAutoRole(autoRole)"> + icon="pi pi-check-circle" (click)="onRowEditSave(autoRole, ri)"> diff --git a/web/src/app/modules/view/server/auto-role/components/auto-roles/auto-roles.component.ts b/web/src/app/modules/view/server/auto-role/components/auto-roles/auto-roles.component.ts index 2c77fede..c5b26460 100644 --- a/web/src/app/modules/view/server/auto-role/components/auto-roles/auto-roles.component.ts +++ b/web/src/app/modules/view/server/auto-role/components/auto-roles/auto-roles.component.ts @@ -192,7 +192,7 @@ export class AutoRolesComponent extends ComponentWithTable implements OnInit, On this.clonedUsers[index] = { ...autoRole }; } - public onRowEditSave(table: Table, newAutoRole: AutoRole, index: number): void { + public override onRowEditSave(newAutoRole: AutoRole, index: number): void { if (this.isEditingNew && JSON.stringify(newAutoRole) === JSON.stringify(this.newAutoRoleTemplate)) { this.isEditingNew = false; this.auto_roles.splice(index, 1); diff --git a/web/src/app/modules/view/server/levels/components/levels/levels.component.html b/web/src/app/modules/view/server/levels/components/levels/levels.component.html index 5d9f5912..329fcd3b 100644 --- a/web/src/app/modules/view/server/levels/components/levels/levels.component.html +++ b/web/src/app/modules/view/server/levels/components/levels/levels.component.html @@ -1,226 +1,238 @@

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

-
- +
+ - -
-
-
- {{levels.length}} {{'common.of' | translate}} - {{dt.totalRecords}} - - {{'view.server.levels.levels' | translate}} -
+ +
+
+
+ {{levels.length}} {{'common.of' | translate}} + {{dt.totalRecords}} + + {{'view.server.levels.levels' | translate}} +
- -
+ +
-
- - -
-
- +
+ + + +
+
+
- - - -
-
{{'common.id' | translate}}
- -
- + + + +
+
{{'common.id' | translate}}
+ +
+ - -
-
{{'common.name' | translate}}
- -
- + +
+
{{'common.name' | translate}}
+ +
+ - -
-
{{'common.color' | translate}}
- -
- + +
+
{{'common.color' | translate}}
+ +
+ - -
-
{{'common.min_xp' | translate}}
- -
- + +
+
{{'common.min_xp' | translate}}
+ +
+ - -
-
{{'common.permissions' | translate}}
- -
- + +
+
{{'common.permissions' | translate}}
+ +
+ - -
-
{{'common.created_at' | translate}}
-
- + +
+
{{'common.created_at' | translate}}
+
+ - -
-
{{'common.modified_at' | translate}}
-
- + +
+
{{'common.modified_at' | translate}}
+
+ - -
-
{{'common.actions' | translate}}
-
- - + +
+
{{'common.actions' | translate}}
+
+ + - - -
- -
- - -
- -
- - - - - - - - -
+ + +
+ +
+ + +
+ +
+ + + + + + + + +
- - - - {{'common.id' | translate}}: - - - {{level.id}} - - - {{level.id}} - - - + + + + {{'common.id' | translate}}: + + + {{level.id}} + + + {{level.id}} + + + - - {{'common.name' | translate}}: - - - - - - {{level.name}} - - - + + {{'common.name' | translate}}: + + + + + + {{level.name}} + + + - - {{'common.color' | translate}}: - - - - - - {{level.color}} - - - + + {{'common.color' | translate}}: + + + + + + {{level.color}} + + + - - {{'common.min_xp' | translate}}: - - - - - - {{level.minXp}} - - - + + {{'common.min_xp' | translate}}: + + + + + + {{level.minXp}} + + + - - {{'common.permissions' | translate}}: - - - - - - {{level.permissions}} - - - + + {{'common.permissions' | translate}}: + + + + + + {{level.permissions}} + + + - - {{'common.created_at' | translate}}: - - - {{level.createdAt | date:'dd.MM.yy HH:mm'}} - - - {{level.createdAt | date:'dd.MM.yy HH:mm'}} - - - - - {{'common.modified_at' | translate}}: - - - {{level.modifiedAt | date:'dd.MM.yy HH:mm'}} - - - {{level.modifiedAt | date:'dd.MM.yy HH:mm'}} - - - - -
- - - + + {{'common.created_at' | translate}}: + + + {{level.createdAt | date:'dd.MM.yy HH:mm'}} + + + {{level.createdAt | date:'dd.MM.yy HH:mm'}} + + + + + {{'common.modified_at' | translate}}: + + + {{level.modifiedAt | date:'dd.MM.yy HH:mm'}} + + + {{level.modifiedAt | date:'dd.MM.yy HH:mm'}} + + + + +
+ + + - - -
- - - + + +
+ + +
- - - - {{'common.no_entries_found' | translate}} - - - + + + + {{'common.no_entries_found' | translate}} + + + - - -
-
+ + +
+
diff --git a/web/src/app/modules/view/server/levels/components/levels/levels.component.ts b/web/src/app/modules/view/server/levels/components/levels/levels.component.ts index c1b808b2..80f3660a 100644 --- a/web/src/app/modules/view/server/levels/components/levels/levels.component.ts +++ b/web/src/app/modules/view/server/levels/components/levels/levels.component.ts @@ -25,249 +25,241 @@ import { UserDTO } from "../../../../../../models/auth/auth-user.dto"; import { ComponentWithTable } from "../../../../../../base/component-with-table"; @Component({ - selector: "app-levels", - templateUrl: "./levels.component.html", - styleUrls: ["./levels.component.scss"] + selector: "app-levels", + templateUrl: "./levels.component.html", + styleUrls: ["./levels.component.scss"] }) export class LevelsComponent extends ComponentWithTable implements OnInit, OnDestroy { - public levels: Level[] = []; - public loading = true; + public levels: Level[] = []; + public loading = true; - public isEditingNew: boolean = false; + public isEditingNew: boolean = false; - public filterForm!: FormGroup<{ - id: FormControl, - name: FormControl, - color: FormControl, - min_xp: FormControl, - permissions: FormControl, - }>; + 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 filter: LevelFilter = {}; + public page: Page = { + pageSize: undefined, + pageIndex: undefined + }; + public sort: Sort = { + sortColumn: undefined, + sortDirection: undefined + }; - public totalRecords: number = 0; + public totalRecords: number = 0; - public clonedLevels: { [s: string]: Level; } = {}; + public clonedLevels: { [s: string]: Level; } = {}; - private unsubscriber = new Subject(); - private server: Server = {}; - public user: UserDTO | null = null; + private unsubscriber = new Subject(); + private server: Server = {}; + public user: UserDTO | null = null; - query: string = Queries.levelWithHistoryQuery; + 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"]); - } - - 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(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 = { - 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; + 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"]); } - 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(); - 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(); - 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(); - 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 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 addLevel(table: Table): void { - const newLevel = JSON.parse(JSON.stringify(this.newLevelTemplate)); + public ngOnDestroy(): void { + this.unsubscriber.next(); + this.unsubscriber.complete(); + } - this.levels = [newLevel, ...this.levels]; + 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; + }); + } - table.initRowEdit(newLevel); + 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) + }); - const index = this.levels.findIndex(l => l.id == newLevel.id); - this.onRowEditInit(table, newLevel, index); + this.filterForm.valueChanges.pipe( + takeUntil(this.unsubscriber), + debounceTime(600) + ).subscribe(changes => { + if (changes.id) { + this.filter.id = changes.id; + } else { + this.filter.id = undefined; + } - this.isEditingNew = true; - } + 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; + } + + 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(); + 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(); + 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(); + 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)); + + 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; + } } diff --git a/web/src/app/modules/view/server/members/members.component.html b/web/src/app/modules/view/server/members/members.component.html index ba4baabd..a5b465b2 100644 --- a/web/src/app/modules/view/server/members/members.component.html +++ b/web/src/app/modules/view/server/members/members.component.html @@ -242,7 +242,7 @@ [routerLink]="member.id"> + icon="pi pi-check-circle" (click)="onRowEditSave(member, ri)"> diff --git a/web/src/app/modules/view/server/members/members.component.ts b/web/src/app/modules/view/server/members/members.component.ts index bfb65b75..980de0ca 100644 --- a/web/src/app/modules/view/server/members/members.component.ts +++ b/web/src/app/modules/view/server/members/members.component.ts @@ -213,15 +213,7 @@ export class MembersComponent extends ComponentWithTable implements OnInit, OnDe this.clonedUsers[index] = { ...user }; } - onRowEditSave(table: Table, newUser: User, index: number) { - // 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; - // } - + public override onRowEditSave(newUser: User, index: number) { if (this.isEditingNew && JSON.stringify(newUser) === JSON.stringify(this.newUserTemplate)) { this.isEditingNew = false; this.members.splice(index, 1); diff --git a/web/src/app/modules/view/server/short-role-name/components/short-role-names/short-role-names.component.html b/web/src/app/modules/view/server/short-role-name/components/short-role-names/short-role-names.component.html index 0cbc7ead..bb312ecf 100644 --- a/web/src/app/modules/view/server/short-role-name/components/short-role-names/short-role-names.component.html +++ b/web/src/app/modules/view/server/short-role-name/components/short-role-names/short-role-names.component.html @@ -27,6 +27,8 @@ + @@ -192,7 +194,7 @@ (click)="deleteShortRoleName(shortRoleName)"> + icon="pi pi-check-circle" (click)="onRowEditSave(shortRoleName, ri)"> diff --git a/web/src/app/modules/view/server/short-role-name/components/short-role-names/short-role-names.component.ts b/web/src/app/modules/view/server/short-role-name/components/short-role-names/short-role-names.component.ts index cd254446..49665c6a 100644 --- a/web/src/app/modules/view/server/short-role-name/components/short-role-names/short-role-names.component.ts +++ b/web/src/app/modules/view/server/short-role-name/components/short-role-names/short-role-names.component.ts @@ -199,7 +199,7 @@ export class ShortRoleNamesComponent extends ComponentWithTable implements OnIni this.clonedShortRoleNames[index] = { ...user }; } - public onRowEditSave(table: Table, newShortRoleName: ShortRoleName, index: number): void { + public override onRowEditSave(newShortRoleName: ShortRoleName, index: number): void { if (this.isEditingNew && JSON.stringify(newShortRoleName) === JSON.stringify(this.newShortRoleNameTemplate)) { this.isEditingNew = false; this.shortRoleNames.splice(index, 1); diff --git a/web/src/assets/i18n/de.json b/web/src/assets/i18n/de.json index ade9226c..3cb071ed 100644 --- a/web/src/assets/i18n/de.json +++ b/web/src/assets/i18n/de.json @@ -144,6 +144,9 @@ "emoji": "Emoji", "error": "Fehler", "feature_flags": "Funktionen", + "file": { + "uploaded": "Daten wurden erfolgreich importiert." + }, "first_name": "Vorname", "hidden_columns": "Ausgeblendete Spalten", "history": { diff --git a/web/src/assets/i18n/en.json b/web/src/assets/i18n/en.json index 36d7f324..b1a37671 100644 --- a/web/src/assets/i18n/en.json +++ b/web/src/assets/i18n/en.json @@ -144,6 +144,9 @@ "emoji": "Emoji", "error": "Error", "feature_flags": "Features", + "file": { + "uploaded": "Data was imported successfully." + }, "first_name": "First name", "hidden_columns": "Hidden columns", "history": { diff --git a/web/src/assets/version.json b/web/src/assets/version.json index 3ae731e3..c2737cb6 100644 --- a/web/src/assets/version.json +++ b/web/src/assets/version.json @@ -2,6 +2,6 @@ "WebVersion": { "Major": "1", "Minor": "2", - "Micro": "0" + "Micro": "dev407" } } \ No newline at end of file