WIP: levels table

This commit is contained in:
Jonas Drescher 2023-02-20 20:27:08 +01:00 committed by Sven Heidemann
parent 75ab159539
commit 113d77eb77
10 changed files with 455 additions and 14 deletions

View File

@ -58,6 +58,8 @@ export class Queries {
id
name
}
createdAt
modifiedAt
}
}
`;

View File

@ -0,0 +1,215 @@
<h1>
{{'view.server.levels.header' | translate}}
</h1>
<div class="content-wrapper">
<div class="content">
<p-table #dt [value]="levels" 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">{{levels.length}} {{'view.server.levels.of' | translate}}
{{dt.totalRecords}}
</ng-container>
{{'view.server.levels.levels' | translate}}
</div>
<div class="table-caption-btn-wrapper btn-wrapper">
<button pButton label="{{'admin.auth_users.add' | translate}}" class="icon-btn btn"
icon="pi pi-user-plus" [disabled]="isEditingNew">
</button>
<button pButton label="{{'view.server.levels.reset_filters' | translate}}" icon="pi pi-undo"
class="icon-btn btn">
</button>
</div>
</div>
</ng-template>
<ng-template pTemplate="header">
<tr>
<th pSortableColumn="id">
<div class="table-header-label">
<div class="table-header-text">{{'view.server.levels.headers.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.levels.headers.name' | translate}}</div>
<p-sortIcon field="name" class="table-header-icon"></p-sortIcon>
</div>
</th>
<th pSortableColumn="color">
<div class="table-header-label">
<div class="table-header-text">{{'view.server.levels.headers.color' | translate}}</div>
<p-sortIcon field="color" class="table-header-icon"></p-sortIcon>
</div>
</th>
<th pSortableColumn="minXp">
<div class="table-header-label">
<div class="table-header-text">{{'view.server.levels.headers.min_xp' | translate}}</div>
<p-sortIcon field="minXp" class="table-header-icon"></p-sortIcon>
</div>
</th>
<th pSortableColumn="permissions">
<div class="table-header-label">
<div class="table-header-text">{{'view.server.levels.headers.permissions' | translate}}</div>
<p-sortIcon field="permissions" 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">{{'view.server.members.headers.actions' | translate}}</div>
</div>
</th>
</tr>
<tr>
<th class="table-header-small">
<form [formGroup]="filterForm">
<input type="text" pInputText formControlName="id"
placeholder="{{'view.server.levels.headers.id' | translate}}">
</form>
</th>
<th>
<form [formGroup]="filterForm">
<input type="text" pInputText formControlName="name"
placeholder="{{'view.server.levels.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-level let-editing="editing" let-ri="rowIndex">
<tr [pEditableRow]="level">
<td>
<p-cellEditor>
<ng-template pTemplate="input">
{{level.id}}
</ng-template>
<ng-template pTemplate="output">
{{level.id}}
</ng-template>
</p-cellEditor>
</td>
<td>
<p-cellEditor>
<ng-template pTemplate="input">
{{level.name}}
</ng-template>
<ng-template pTemplate="output">
{{level.name}}
</ng-template>
</p-cellEditor>
</td>
<td>
<p-cellEditor>
<ng-template pTemplate="input">
{{level.color}}
</ng-template>
<ng-template pTemplate="output">
{{level.color}}
</ng-template>
</p-cellEditor>
</td>
<td>
<p-cellEditor>
<ng-template pTemplate="input">
{{level.minXp}}
</ng-template>
<ng-template pTemplate="output">
{{level.minXp}}
</ng-template>
</p-cellEditor>
</td>
<td>
<p-cellEditor>
<ng-template pTemplate="input">
{{level.permissions}}
</ng-template>
<ng-template pTemplate="output">
{{level.permissions}}
</ng-template>
</p-cellEditor>
</td>
<td>
<p-cellEditor>
<ng-template pTemplate="input">
{{level.createdAt | date:'dd.MM.yy HH:mm'}}
</ng-template>
<ng-template pTemplate="output">
{{level.createdAt | date:'dd.MM.yy HH:mm'}}
</ng-template>
</p-cellEditor>
</td>
<td>
<p-cellEditor>
<ng-template pTemplate="input">
{{level.modifiedAt | date:'dd.MM.yy HH:mm'}}
</ng-template>
<ng-template pTemplate="output">
{{level.modifiedAt | date:'dd.MM.yy HH:mm'}}
</ng-template>
</p-cellEditor>
</td>
<td>
<div class="btn-wrapper">
<button *ngIf="!editing" pButton pInitEditableRow class="btn icon-btn" icon="pi pi-pencil"
></button>
<button *ngIf="!editing" pButton pInitEditableRow class="btn icon-btn" icon="pi pi-user"
[routerLink]="[level.id, 'rules']"></button>
<button *ngIf="editing" pButton pSaveEditableRow class="btn icon-btn"
icon="pi pi-check-circle"></button>
<button *ngIf="editing" pButton pCancelEditableRow class="btn icon-btn danger-icon-btn"
icon="pi pi-times-circle"></button>
</div>
</td>
</tr>
</ng-template>
<ng-template pTemplate="emptymessage">
<tr></tr>
<tr>
<td colspan="10">{{'view.server.auto_roles.no_entries_found' | translate}}</td>
</tr>
<tr></tr>
</ng-template>
<ng-template pTemplate="paginatorleft">
</ng-template>
</p-table>
</div>
</div>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { LevelsComponent } from './levels.component';
describe('LevelsComponent', () => {
let component: LevelsComponent;
let fixture: ComponentFixture<LevelsComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ LevelsComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(LevelsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,127 @@
import {Component} from '@angular/core';
import {AuthService} from "../../../../../../services/auth/auth.service";
import {SpinnerService} from "../../../../../../services/spinner/spinner.service";
import {ToastService} from "../../../../../../services/toast/toast.service";
import {ConfirmationDialogService} from "../../../../../../services/confirmation-dialog/confirmation-dialog.service";
import {FormBuilder, FormControl, FormGroup} from "@angular/forms";
import {TranslateService} from "@ngx-translate/core";
import {DataService} from "../../../../../../services/data/data.service";
import {SidebarService} from "../../../../../../services/sidebar/sidebar.service";
import {ActivatedRoute} from "@angular/router";
import {Page} from "../../../../../../models/graphql/filter/page.model";
import {Sort, SortDirection} from "../../../../../../models/graphql/filter/sort.model";
import {Level, LevelFilter} from "../../../../../../models/data/level.model";
import {LevelListQuery} from "../../../../../../models/graphql/query.model";
import {Queries} from "../../../../../../models/graphql/queries.model";
import {debounceTime} from "rxjs/operators";
import {LazyLoadEvent} from "primeng/api";
@Component({
selector: 'app-levels',
templateUrl: './levels.component.html',
styleUrls: ['./levels.component.scss']
})
export class LevelsComponent {
levels!: Level[];
loading = true;
isEditingNew: boolean = false;
filterForm!: FormGroup<{
id: FormControl<number | null>,
name: FormControl<string | null>,
color: FormControl<string | null>,
min_xp: FormControl<number | null>,
permissions: FormControl<number | null>,
}>;
filter: LevelFilter = {};
page: Page = {
pageSize: undefined,
pageIndex: undefined
};
sort: Sort = {
sortColumn: undefined,
sortDirection: undefined
};
totalRecords!: number;
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.data.getServerFromRoute(this.route);
this.setFilterForm();
this.loadNextPage();
}
public loadNextPage() {
this.loading = true;
this.data.query<LevelListQuery>(Queries.levelQuery, {
filter: this.filter, page: this.page, sort: this.sort
}
).subscribe(data => {
this.totalRecords = data.levelCount;
this.levels = data.levels;
this.spinner.hideSpinner();
this.loading = false;
});
}
public setFilterForm() {
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<number | null>(null),
});
this.filterForm.valueChanges.pipe(
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 nextPage(event: LazyLoadEvent) {
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();
}
}

View File

@ -0,0 +1,16 @@
import {NgModule} from "@angular/core";
import {RouterModule, Routes} from "@angular/router";
import {LevelsComponent} from "./components/levels/levels.component";
const routes: Routes = [
{path: '', component: LevelsComponent},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class LevelsRoutingModule {
}

View File

@ -0,0 +1,18 @@
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {LevelsComponent} from './components/levels/levels.component'
import {SharedModule} from "../../../shared/shared.module";
import {LevelsRoutingModule} from "./levels-routing.module";
@NgModule({
declarations: [
LevelsComponent
],
imports: [
CommonModule,
LevelsRoutingModule,
SharedModule
]
})
export class LevelsModule {
}

View File

@ -9,10 +9,12 @@ const routes: Routes = [
{path: 'members', component: MembersComponent},
{path: 'members/:memberId', component: ProfileComponent},
{path: 'auto-roles', loadChildren: () => import('./auto-role/auto-role.module').then(m => m.AutoRoleModule)},
{path: 'levels', loadChildren: () => import('./levels/levels.module').then(m => m.LevelsModule)},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class ServerRoutingModule { }
export class ServerRoutingModule {
}

View File

@ -24,6 +24,7 @@ export class SidebarService {
serverMembers!: MenuItem;
serverAutoRoles!: MenuItem;
serverAutoRoleRules!: MenuItem;
serverLevels!: MenuItem;
serverMenu!: MenuItem;
adminConfig!: MenuItem;
adminUsers!: MenuItem;
@ -66,7 +67,11 @@ export class SidebarService {
}
async buildMenu(user: UserDTO | null, hasPermission: boolean) {
this.dashboard = { label: this.isSidebarOpen ? this.translateService.instant("sidebar.dashboard") : "", icon: "pi pi-th-large", routerLink: "dashboard" };
this.dashboard = {
label: this.isSidebarOpen ? this.translateService.instant("sidebar.dashboard") : "",
icon: "pi pi-th-large",
routerLink: "dashboard"
};
this.serverDashboard = {
label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.dashboard") : "",
icon: "pi pi-th-large",
@ -74,7 +79,7 @@ export class SidebarService {
};
this.serverProfile = {
label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.profile") : "",
icon: "pi pi-user",
icon: "pi pi-id-card",
routerLink: `server/${this.server$.value?.id}/members/${user?.id}`
};
this.serverMembers = {
@ -91,14 +96,25 @@ export class SidebarService {
routerLink: `server/${this.server$.value?.id}/auto-roles`
};
this.serverLevels = {
label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.levels") : "",
icon: "pi pi-book",
visible: true,
routerLink: `server/${this.server$.value?.id}/levels`
};
this.serverMenu = {
label: this.isSidebarOpen ? this.server$.value?.name : "",
icon: "pi pi-server",
visible: false,
expanded: true,
items: [this.serverDashboard, this.serverProfile, this.serverMembers, this.serverAutoRoles]
items: [this.serverDashboard, this.serverProfile, this.serverMembers, this.serverAutoRoles, this.serverLevels]
};
this.adminConfig = {
label: this.isSidebarOpen ? this.translateService.instant("sidebar.config") : "",
icon: "pi pi-cog",
routerLink: "/admin/settings"
};
this.adminConfig = { label: this.isSidebarOpen ? this.translateService.instant("sidebar.config") : "", icon: "pi pi-cog", routerLink: "/admin/settings" };
this.adminUsers = {
label: this.isSidebarOpen ? this.translateService.instant("sidebar.auth_user_list") : "",
icon: "pi pi-user-edit",

View File

@ -11,6 +11,7 @@
"dashboard": "Dashboard",
"profile": "Dein Profil",
"members": "Mitglieder",
"levels": "Level",
"auto_roles": "Auto Rollen"
},
"server_empty": "Kein Server ausgewählt",
@ -277,6 +278,27 @@
"auto_role_rule_delete_failed_d": "Die Löschung der Auto Rollen Regel {{id}} ist fehlgeschlagen!"
}
}
},
"levels": {
"header": "Level",
"reset_filters": "Filter zurücksetzen",
"of": "von",
"add": "Hinzufügen",
"levels": "Level",
"headers": {
"id": "Id",
"name": "Name",
"color": "Farbe",
"min_xp": "Min. XP",
"permissions": "Rechte"
},
"no_entries_found": "Keine Einträge gefunden",
"message": {
"level_changed": "Level geändert",
"level_changed_d": "Level {{name}} erfolgreich geändert",
"level_change_failed": "Level Änderung fehlgeschlagen",
"level_change_failed_d": "Level {{name}} konnte nicht geändert werden!"
}
}
},
"user-list": {},