Show user warnings in profile & lazy load other stuff #402

This commit is contained in:
2023-10-10 12:21:21 +02:00
parent eeda0405f3
commit 5afd0fafa8
27 changed files with 508 additions and 82 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "kdb-web",
"version": "1.1.10",
"version": "1.1.dev402",
"scripts": {
"ng": "ng",
"update-version": "ts-node update-version.ts",
@@ -51,4 +51,4 @@
"tslib": "^2.4.1",
"typescript": "~4.9.5"
}
}
}

View File

@@ -5,6 +5,7 @@ import { UserJoinedServer } from "./user_joined_server.model";
import { UserJoinedVoiceChannel } from "./user_joined_voice_channel.model";
import { UserJoinedGameServer } from "./user_joined_game_server.model";
import { Achievement } from "./achievement.model";
import { UserWarning } from "./user_warning.model";
export interface User extends DataWithHistory {
id?: number;
@@ -29,6 +30,9 @@ export interface User extends DataWithHistory {
achievementCount?: number;
achievements?: Achievement[];
userWarningCount?: number;
userWarnings?: UserWarning[];
}
export interface UserFilter {

View File

@@ -0,0 +1,16 @@
import { DataWithHistory } from "./data.model";
import { User, UserFilter } from "./user.model";
export interface UserWarning extends DataWithHistory {
id?: number;
user?: User;
description?: string;
author?: User;
}
export interface UserWarningFilter {
id?: number;
user?: UserFilter;
description?: string;
author?: UserFilter;
}

View File

@@ -208,7 +208,7 @@ export class Queries {
query {
shortRoleNamePositions
}
`
`;
static shortRoleNameQuery = `
query ShortRoleNameList($serverId: ID, $filter: ShortRoleNameFilter, $page: Page, $sort: Sort) {
@@ -279,58 +279,94 @@ export class Queries {
static userProfile = `
query UserProfile($serverId: ID, $userId: ID, $page: Page, $sort: Sort) {
servers(filter: {id: $serverId}) {
userCount
users(filter: {id: $userId}, page: $page, sort: $sort) {
userCount
users(filter: {server: {id: $serverId}, id: $userId}, page: $page, sort: $sort) {
id
discordId
name
xp
ontime
level {
id
discordId
name
xp
ontime
level {
}
leftServer
server {
id
name
}
joinedServerCount
joinedServers {
id
joinedOn
leavedOn
}
createdAt
modifiedAt
}
}
`;
static userProfileAchievements = `
query UserProfile($serverId: ID, $userId: ID, $page: Page, $sort: Sort) {
users(filter: {server: {id: $serverId}, id: $userId}, page: $page, sort: $sort) {
achievementCount
achievements {
id
name
description
createdAt
}
}
}
`;
static userProfileVoiceChannelJoins = `
query UserProfile($serverId: ID, $userId: ID, $page: Page, $sort: Sort) {
users(filter: {server: {id: $serverId}, id: $userId}, page: $page, sort: $sort) {
joinedVoiceChannelCount
joinedVoiceChannels {
id
channelId
channelName
time
joinedOn
leavedOn
}
}
}
`;
static userProfileGameserverJoins = `
query UserProfile($serverId: ID, $userId: ID, $page: Page, $sort: Sort) {
users(filter: {server: {id: $serverId}, id: $userId}, page: $page, sort: $sort) {
userJoinedGameServerCount
userJoinedGameServers {
id
gameServer
time
joinedOn
leavedOn
}
}
}
`;
static userProfileWarnings = `
query UserProfile($serverId: ID, $userId: ID, $page: Page, $sort: Sort) {
users(filter: {server: {id: $serverId}, id: $userId}, page: $page, sort: $sort) {
userWarningCount
userWarnings {
id
description
author {
id
name
}
leftServer
server {
id
name
}
joinedServerCount
joinedServers {
id
joinedOn
leavedOn
}
joinedVoiceChannelCount
joinedVoiceChannels {
id
channelId
channelName
time
joinedOn
leavedOn
}
userJoinedGameServerCount
userJoinedGameServers {
id
gameServer
time
joinedOn
leavedOn
}
achievements {
id
name
createdAt
}
createdAt
modifiedAt
}
}
}

View File

@@ -8,6 +8,7 @@ import { TechnicianConfig } from "../config/technician-config.model";
import { ServerConfig } from "../config/server-config.model";
import { ShortRoleName } from "../data/short_role_name.model";
import { FeatureFlag } from "../config/feature-flags.model";
import { UserWarning } from "../data/user_warning.model";
export interface Query {
serverCount: number;
@@ -31,6 +32,11 @@ export interface UserListQuery {
users: User[];
}
export interface UserWarningQuery {
userWarningCount: number;
userWarnings: UserWarning[];
}
export interface GameServerListQuery {
gameServerCount: number;
gameServers: GameServer[];

View File

@@ -76,9 +76,103 @@
</div>
</div>
<div>
<div class="content-divider"></div>
<p-table #dt [value]="(user.userWarnings ?? [])" [responsive]="true" responsiveLayout="stack" [breakpoint]="'720px'" dataKey="id" editMode="row">
<ng-template pTemplate="caption">
<div class="table-caption">
<div class="table-caption-table-info">
<div class="table-caption-text">
<h3>{{'common.user_warnings' | translate}}</h3>
</div>
</div>
<div class="table-caption-btn-wrapper btn-wrapper">
<button pButton label="{{'common.add' | translate}}" class="icon-btn btn"
icon="pi pi-plus" (click)="addNewUserWarning(dt)">
</button>
</div>
</div>
</ng-template>
<ng-template pTemplate="header">
<tr>
<th>
<div class="table-header-label">
<div class="table-header-text">{{'common.description' | translate}}</div>
</div>
</th>
<th>
<div class="table-header-label">
<div class="table-header-text">{{'common.author' | translate}}</div>
</div>
</th>
<th>
<div class="table-header-label">
<div class="table-header-text">{{'common.created_at' | translate}}</div>
</div>
</th>
<th class="table-header-actions">
<div class="table-header-label">
<div class="table-header-text">{{'common.actions' | translate}}</div>
</div>
</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-value let-editing="editing" let-ri="rowIndex">
<tr [pEditableRow]="value">
<td>
<p-cellEditor>
<ng-template pTemplate="input">
<input class="table-edit-input" pInputText type="text" [(ngModel)]="value.description">
</ng-template>
<ng-template pTemplate="output">
{{value.description}}
</ng-template>
</p-cellEditor>
</td>
<td>
<p-cellEditor>
<ng-template pTemplate="input">
{{value.author.name}}
</ng-template>
<ng-template pTemplate="output">
{{value.author.name}}
</ng-template>
</p-cellEditor>
</td>
<td>
<span class="p-column-title">{{'common.created_at' | translate}}:</span>
<p-cellEditor>
<ng-template pTemplate="input">
{{value.createdAt | date:'dd.MM.yy HH:mm'}}
</ng-template>
<ng-template pTemplate="output">
{{value.createdAt | date:'dd.MM.yy HH:mm'}}
</ng-template>
</p-cellEditor>
</td>
<td>
<div class="btn-wrapper">
<button *ngIf="!editing" pButton type="button" class="btn danger-icon-btn" icon="pi pi-trash" (click)="deleteUserWarning(ri)"></button>
<button *ngIf="editing" pButton type="button" pSaveEditableRow class="btn icon-btn" icon="pi pi-check" (click)="editSaveUserWarning(value, ri)"></button>
<button *ngIf="editing" pButton type="button" pCancelEditableRow class="btn danger-icon-btn" icon="pi pi-times"
(click)="editCancelUserWarning(ri)"></button>
</div>
</td>
</tr>
</ng-template>
</p-table>
<br>
</div>
<div class="content-divider"></div>
<p-panel header="{{'view.server.profile.achievements.header' | translate}}" [toggleable]="true">
<p-panel header="{{'view.server.profile.achievements.header' | translate}}" [toggleable]="true" [collapsed]="true"
(onBeforeToggle)="onBeforeToggle($event.event, $event.collapsed)">
<div *ngFor="let achievement of user.achievements;">
<div class="content-row">
<div class="content-column">
@@ -86,6 +180,11 @@
<div class="content-data-value">{{achievement.name}}</div>
</div>
<div class="content-column">
<div class="content-data-name">{{'common.description' | translate}}:</div>
<div class="content-data-value">{{achievement.description}}</div>
</div>
<div class="content-column">
<div class="content-data-name">{{'view.server.profile.achievements.time' | translate}}:</div>
<div class="content-data-value">{{achievement.createdAt | date:'dd.MM.yyyy HH:mm:ss'}}</div>
@@ -94,7 +193,8 @@
</div>
</p-panel>
<p-panel header="{{'view.server.profile.joined_voice_channel.header' | translate}}" [toggleable]="true">
<p-panel header="{{'view.server.profile.joined_voice_channel.header' | translate}}" [toggleable]="true" [collapsed]="true"
(onBeforeToggle)="onBeforeToggle($event.event, $event.collapsed)">
<div *ngFor="let join of user.joinedVoiceChannels;">
<div class="content-row">
<div class="content-column">
@@ -120,7 +220,8 @@
</div>
</p-panel>
<p-panel header="{{'view.server.profile.joined_game_server.header' | translate}}" [toggleable]="true">
<p-panel header="{{'view.server.profile.joined_game_server.header' | translate}}" [toggleable]="true" [collapsed]="true"
(onBeforeToggle)="onBeforeToggle($event.event, $event.collapsed)">
<div *ngFor="let join of user.userJoinedGameServers;">
<div class="content-row">
<div class="content-column">

View File

@@ -1,7 +1,7 @@
import { Component, OnDestroy, OnInit } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { Queries } from "../../../../models/graphql/queries.model";
import { UserListQuery } from "../../../../models/graphql/query.model";
import { UserListQuery, UserWarningQuery } from "../../../../models/graphql/query.model";
import { SpinnerService } from "../../../../services/spinner/spinner.service";
import { DataService } from "../../../../services/data/data.service";
import { User } from "../../../../models/data/user.model";
@@ -10,8 +10,9 @@ import { AuthService } from "src/app/services/auth/auth.service";
import { ToastService } from "src/app/services/toast/toast.service";
import { TranslateService } from "@ngx-translate/core";
import { Server } from "../../../../models/data/server.model";
import { Subject } from "rxjs";
import { forkJoin, Subject } from "rxjs";
import { takeUntil } from "rxjs/operators";
import { Table } from "primeng/table";
@Component({
selector: "app-profile",
@@ -58,16 +59,27 @@ export class ProfileComponent implements OnInit, OnDestroy {
this.data.query<UserListQuery>(Queries.userProfile, {
serverId: this.server.id,
userId: params["memberId"]
},
(x: { servers: Server[] }) => {
return x.servers[0];
}
).subscribe(users => {
if (!users.users[0]) {
this.router.navigate([`/server/${server.id}`]);
}
this.user = users.users[0];
this.spinner.hideSpinner();
this.data.query<UserWarningQuery>(Queries.userProfileWarnings, {
serverId: this.server.id,
userId: this.user.id
},
(data: UserListQuery) => {
return data.users[0];
}
).subscribe(result => {
this.user.userWarningCount = result.userWarningCount;
this.user.userWarnings = result.userWarnings;
console.log(result);
this.spinner.hideSpinner();
});
});
});
});
@@ -77,4 +89,68 @@ export class ProfileComponent implements OnInit, OnDestroy {
this.unsubscriber.next();
this.unsubscriber.complete();
}
public onBeforeToggle(event: Event, collapsed: boolean) {
const filterUser = (x: { users: User[] }) => {
const users = x.users ?? [];
return users[0];
};
if (collapsed) {
this.spinner.showSpinner();
forkJoin([
this.data.query<User>(Queries.userProfileAchievements, {
serverId: this.server.id,
userId: this.user.id
},
filterUser
),
this.data.query<User>(Queries.userProfileVoiceChannelJoins, {
serverId: this.server.id,
userId: this.user.id
},
filterUser
),
this.data.query<User>(Queries.userProfileGameserverJoins, {
serverId: this.server.id,
userId: this.user.id
},
filterUser
)
]).subscribe(data => {
this.user.achievementCount = data[0].achievementCount;
this.user.achievements = data[0].achievements;
this.user.joinedVoiceChannelCount = data[1].joinedVoiceChannelCount;
this.user.joinedVoiceChannels = data[1].joinedVoiceChannels;
this.user.userJoinedGameServerCount = data[2].userJoinedGameServerCount;
this.user.userJoinedGameServers = data[2].userJoinedGameServers;
this.spinner.hideSpinner();
});
return;
}
this.user.achievementCount = 0;
this.user.achievements = [];
this.user.userJoinedGameServerCount = 0;
this.user.userJoinedGameServers = [];
this.user.joinedVoiceChannelCount = 0;
this.user.joinedVoiceChannels = [];
}
addNewUserWarning(table: Table) {
}
deleteUserWarning(index: number) {
}
editSaveUserWarning(value: any, index: number) {
}
editCancelUserWarning(index: number) {
}
protected readonly visualViewport = visualViewport;
}

View File

@@ -1,12 +1,11 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ServerDashboardComponent } from './server-dashboard/server-dashboard.component';
import { ServerRoutingModule } from './server-routing.module';
import { SharedModule } from '../../shared/shared.module';
import { ProfileComponent } from './profile/profile.component';
import { MembersComponent } from './members/members.component';
import { ClientComponent } from './server-dashboard/components/client/client.component';
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { ServerDashboardComponent } from "./server-dashboard/server-dashboard.component";
import { ServerRoutingModule } from "./server-routing.module";
import { SharedModule } from "../../shared/shared.module";
import { ProfileComponent } from "./profile/profile.component";
import { MembersComponent } from "./members/members.component";
import { ClientComponent } from "./server-dashboard/components/client/client.component";
@NgModule({

View File

@@ -194,7 +194,6 @@ export class SidebarService {
let user: UserDTO | null = authUser?.users?.find(u => u.server == this.server?.id) ?? null;
let isTechnician = (authUser?.users?.map(u => u.isTechnician).filter(u => u) ?? []).length > 0;
let isTechnicianAndFullAccessActive = this.hasFeature("TechnicianFullAccess") && isTechnician;
console.log(this.hasFeature("TechnicianFullAccess"))
if (build || this.menuItems$.value.length == 0) {
await this.buildMenu(user, hasPermission, isTechnician);

View File

@@ -122,6 +122,8 @@
}
},
"common": {
"user_warnings": "Verwarnungen",
"author": "Autor",
"404": "404 - Der Eintrag konnte nicht gefunden werden",
"actions": "Aktionen",
"active": "Aktiv",

View File

@@ -1,7 +1,7 @@
{
"WebVersion": {
"Major": "1",
"Minor": "1",
"Micro": "10"
}
}
"WebVersion": {
"Major": "1",
"Minor": "1",
"Micro": "dev402"
}
}

View File

@@ -201,10 +201,10 @@ header {
font-size: 18px;
}
}
.content-divider {
margin: 5px 0;
}
.content-divider {
margin: 10px 0;
}
p-panel {
@@ -493,7 +493,7 @@ header {
}
.content-divider {
margin: 5px 0;
margin: 10px 0;
}
.content-input-field {

View File

@@ -20,7 +20,8 @@
background-color: $primaryBackgroundColor;
h1,
h2 {
h2,
h3 {
color: $primaryHeaderColor;
}

View File

@@ -20,7 +20,8 @@
background-color: $primaryBackgroundColor;
h1,
h2 {
h2,
h3 {
color: $primaryHeaderColor;
}

View File

@@ -21,7 +21,8 @@
h1,
h2 {
h2,
h3 {
color: $primaryHeaderColor;
}

View File

@@ -20,7 +20,8 @@
background-color: $primaryBackgroundColor;
h1,
h2 {
h2,
h3 {
color: $primaryHeaderColor;
}