Show user warnings in profile & lazy load other stuff #402
This commit is contained in:
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
@@ -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 {
|
||||
|
16
kdb-web/src/app/models/data/user_warning.model.ts
Normal file
16
kdb-web/src/app/models/data/user_warning.model.ts
Normal 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;
|
||||
}
|
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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[];
|
||||
|
@@ -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">
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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({
|
||||
|
@@ -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);
|
||||
|
@@ -122,6 +122,8 @@
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"user_warnings": "Verwarnungen",
|
||||
"author": "Autor",
|
||||
"404": "404 - Der Eintrag konnte nicht gefunden werden",
|
||||
"actions": "Aktionen",
|
||||
"active": "Aktiv",
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"WebVersion": {
|
||||
"Major": "1",
|
||||
"Minor": "1",
|
||||
"Micro": "10"
|
||||
}
|
||||
}
|
||||
"WebVersion": {
|
||||
"Major": "1",
|
||||
"Minor": "1",
|
||||
"Micro": "dev402"
|
||||
}
|
||||
}
|
@@ -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 {
|
||||
|
@@ -20,7 +20,8 @@
|
||||
background-color: $primaryBackgroundColor;
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
h2,
|
||||
h3 {
|
||||
color: $primaryHeaderColor;
|
||||
}
|
||||
|
||||
|
@@ -20,7 +20,8 @@
|
||||
background-color: $primaryBackgroundColor;
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
h2,
|
||||
h3 {
|
||||
color: $primaryHeaderColor;
|
||||
}
|
||||
|
||||
|
@@ -21,7 +21,8 @@
|
||||
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
h2,
|
||||
h3 {
|
||||
color: $primaryHeaderColor;
|
||||
}
|
||||
|
||||
|
@@ -20,7 +20,8 @@
|
||||
background-color: $primaryBackgroundColor;
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
h2,
|
||||
h3 {
|
||||
color: $primaryHeaderColor;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user