Added server config to frontend #127
This commit is contained in:
parent
5d36f1188a
commit
6c39cd1ae1
@ -150,6 +150,12 @@ class ServerConfigMutation(QueryABC):
|
||||
|
||||
self._server_configs.delete_server_team_role_id_config(role_id)
|
||||
|
||||
for role_id in new_config.team_role_ids:
|
||||
guild = self._bot.get_guild(new_config.server.discord_id)
|
||||
role = guild.get_role(int(role_id.role_id))
|
||||
if role is None:
|
||||
raise ValueError(f"Invalid roleId")
|
||||
|
||||
for role_id in new_config.team_role_ids:
|
||||
if role_id.role_id in old_config.team_role_ids.select(lambda x: str(x.role_id)):
|
||||
continue
|
||||
|
21
kdb-web/src/app/models/config/server-config.model.ts
Normal file
21
kdb-web/src/app/models/config/server-config.model.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { DataWithHistory } from "../data/data.model";
|
||||
|
||||
export interface ServerConfig extends DataWithHistory {
|
||||
id?: number;
|
||||
messageDeleteTimer?: number;
|
||||
notificationChatId?: string;
|
||||
maxVoiceStateHours?: number;
|
||||
xpPerMessage?: number;
|
||||
xpPerReaction?: number;
|
||||
maxMessageXpPerHour?: number;
|
||||
xpPerOntimeHour?: number;
|
||||
xpPerEventParticipation?: number;
|
||||
xpPerAchievement?: number;
|
||||
afkCommandChannelId?: string;
|
||||
helpVoiceChannelId?: string;
|
||||
teamChannelId?: string;
|
||||
loginMessageChannelId?: string;
|
||||
afkChannelIds: string[];
|
||||
moderatorRoleIds: string[];
|
||||
adminRoleIds: string[];
|
||||
}
|
@ -6,6 +6,6 @@ export interface TechnicianConfig extends DataWithHistory {
|
||||
waitForRestart?: number;
|
||||
waitForShutdown?: number;
|
||||
cacheMaxMessages?: number;
|
||||
pingURLs?: string[];
|
||||
technicianIds?: string[];
|
||||
pingURLs: string[];
|
||||
technicianIds: string[];
|
||||
}
|
||||
|
@ -166,8 +166,6 @@ export class Mutations {
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
|
||||
static updateTechnicianConfig = `
|
||||
mutation updateTechnicianConfig($id: ID, $helpCommandReferenceUrl: String, $waitForRestart: Int, $waitForShutdown: Int, $cacheMaxMessages: Int, $pingURLs: [String], $technicianIds: [String]) {
|
||||
technicianConfig {
|
||||
@ -191,4 +189,70 @@ export class Mutations {
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
static updateServerConfig = `
|
||||
mutation updateServerConfig(
|
||||
$id: ID,
|
||||
$messageDeleteTimer: Int,
|
||||
$notificationChatId: String,
|
||||
$maxVoiceStateHours: Int,
|
||||
$xpPerMessage: Int,
|
||||
$xpPerReaction: Int,
|
||||
$maxMessageXpPerHour: Int,
|
||||
$xpPerOntimeHour: Int,
|
||||
$xpPerEventParticipation: Int,
|
||||
$xpPerAchievement: Int,
|
||||
$afkCommandChannelId: String,
|
||||
$helpVoiceChannelId: String,
|
||||
$teamChannelId: String,
|
||||
$loginMessageChannelId: String,
|
||||
$afkChannelIds: [String],
|
||||
$moderatorRoleIds: [String],
|
||||
$adminRoleIds: [String]
|
||||
) {
|
||||
serverConfig {
|
||||
updateServerConfig(input: {
|
||||
id: $id,
|
||||
messageDeleteTimer: $messageDeleteTimer
|
||||
notificationChatId: $notificationChatId
|
||||
maxVoiceStateHours: $maxVoiceStateHours
|
||||
xpPerMessage: $xpPerMessage
|
||||
xpPerReaction: $xpPerReaction
|
||||
maxMessageXpPerHour: $maxMessageXpPerHour
|
||||
xpPerOntimeHour: $xpPerOntimeHour
|
||||
xpPerEventParticipation: $xpPerEventParticipation
|
||||
xpPerAchievement: $xpPerAchievement
|
||||
afkCommandChannelId: $afkCommandChannelId
|
||||
helpVoiceChannelId: $helpVoiceChannelId
|
||||
teamChannelId: $teamChannelId
|
||||
loginMessageChannelId: $loginMessageChannelId
|
||||
afkChannelIds: $afkChannelIds
|
||||
moderatorRoleIds: $moderatorRoleIds
|
||||
adminRoleIds: $adminRoleIds
|
||||
}) {
|
||||
id
|
||||
messageDeleteTimer
|
||||
notificationChatId
|
||||
maxVoiceStateHours
|
||||
xpPerMessage
|
||||
xpPerReaction
|
||||
maxMessageXpPerHour
|
||||
xpPerOntimeHour
|
||||
xpPerEventParticipation
|
||||
xpPerAchievement
|
||||
afkCommandChannelId
|
||||
helpVoiceChannelId
|
||||
teamChannelId
|
||||
loginMessageChannelId
|
||||
afkChannelIds
|
||||
moderatorRoleIds
|
||||
adminRoleIds
|
||||
|
||||
server {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
@ -1,22 +1,5 @@
|
||||
export class Queries {
|
||||
|
||||
static technicianConfigQuery = `
|
||||
query technicianConfigQuery {
|
||||
technicianConfig {
|
||||
id
|
||||
helpCommandReferenceUrl
|
||||
waitForRestart
|
||||
waitForShutdown
|
||||
cacheMaxMessages
|
||||
pingURLs
|
||||
technicianIds
|
||||
|
||||
createdAt
|
||||
modifiedAt
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
static guildsQuery = `
|
||||
query GuildsQuery($id: ID) {
|
||||
guilds(filter: {id: $id}) {
|
||||
@ -71,7 +54,7 @@ export class Queries {
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
`;
|
||||
|
||||
static levelQuery = `
|
||||
query LevelsList($serverId: ID, $filter: LevelFilter, $page: Page, $sort: Sort) {
|
||||
@ -361,4 +344,52 @@ export class Queries {
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
static technicianConfigQuery = `
|
||||
query technicianConfigQuery {
|
||||
technicianConfig {
|
||||
id
|
||||
helpCommandReferenceUrl
|
||||
waitForRestart
|
||||
waitForShutdown
|
||||
cacheMaxMessages
|
||||
pingURLs
|
||||
technicianIds
|
||||
|
||||
createdAt
|
||||
modifiedAt
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
static serverConfigQuery = `
|
||||
query serverConfigQuery($serverId: ID) {
|
||||
servers(filter: { id: $serverId }) {
|
||||
name
|
||||
config {
|
||||
id
|
||||
messageDeleteTimer
|
||||
notificationChatId
|
||||
maxVoiceStateHours
|
||||
xpPerMessage
|
||||
xpPerReaction
|
||||
maxMessageXpPerHour
|
||||
xpPerOntimeHour
|
||||
xpPerEventParticipation
|
||||
xpPerAchievement
|
||||
afkCommandChannelId
|
||||
helpVoiceChannelId
|
||||
teamChannelId
|
||||
loginMessageChannelId
|
||||
afkChannelIds
|
||||
moderatorRoleIds
|
||||
adminRoleIds
|
||||
|
||||
server {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import { Guild } from "../data/discord.model";
|
||||
import { Level } from "../data/level.model";
|
||||
import { Achievement, AchievementAttribute } from "../data/achievement.model";
|
||||
import { TechnicianConfig } from "../config/technician-config.model";
|
||||
import { ServerConfig } from "../config/server-config.model";
|
||||
|
||||
export interface Query {
|
||||
serverCount: number;
|
||||
@ -15,6 +16,10 @@ export interface TechnicianConfigQuery {
|
||||
technicianConfig: TechnicianConfig;
|
||||
}
|
||||
|
||||
export interface ServerConfigQuery {
|
||||
config: ServerConfig;
|
||||
}
|
||||
|
||||
export interface SingleDiscordQuery {
|
||||
guilds: Guild[];
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import { Level } from "../data/level.model";
|
||||
import { Server } from "../data/server.model";
|
||||
import { Achievement } from "../data/achievement.model";
|
||||
import { TechnicianConfig } from "../config/technician-config.model";
|
||||
import { ServerConfig } from "../config/server-config.model";
|
||||
|
||||
export interface GraphQLResult {
|
||||
data: {
|
||||
@ -54,6 +55,12 @@ export interface TechnicianConfigMutationResult {
|
||||
};
|
||||
}
|
||||
|
||||
export interface ServerConfigMutationResult {
|
||||
serverConfig: {
|
||||
updateServerConfig?: ServerConfig
|
||||
};
|
||||
}
|
||||
|
||||
export interface AchievementMutationResult {
|
||||
achievement: {
|
||||
createAchievement?: Achievement
|
||||
|
@ -160,103 +160,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="content-divider"></div>
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">
|
||||
{{'admin.settings.bot.ping_urls' | translate}}:
|
||||
</div>
|
||||
<div class="content-data-value-row">
|
||||
<p-table #dt [value]="pingUrls" dataKey="id" editMode="row">
|
||||
<ng-template pTemplate="caption">
|
||||
<div class="table-caption">
|
||||
<div class="table-caption-btn-wrapper btn-wrapper">
|
||||
<button pButton class="icon-btn btn"
|
||||
icon="pi pi-plus" (click)="pingUrlsAddNew(dt)">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
<ng-template pTemplate="body" let-pingUrl let-editing="editing" let-ri="rowIndex">
|
||||
<tr [pEditableRow]="pingUrl">
|
||||
<td>
|
||||
<p-cellEditor>
|
||||
<ng-template pTemplate="input">
|
||||
<input class="table-edit-input" pInputText type="text" [(ngModel)]="pingUrl.value">
|
||||
</ng-template>
|
||||
<ng-template pTemplate="output">
|
||||
{{pingUrl.value}}
|
||||
</ng-template>
|
||||
</p-cellEditor>
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-wrapper">
|
||||
<button *ngIf="!editing" pButton type="button" pInitEditableRow class="btn icon-btn" icon="pi pi-pencil" (click)="pingUrlsEditInit(pingUrl, ri)"></button>
|
||||
<button *ngIf="!editing" pButton type="button" class="btn danger-icon-btn" icon="pi pi-trash" (click)="pingUrlsDelete(ri)"></button>
|
||||
|
||||
<button *ngIf="editing" pButton type="button" pSaveEditableRow class="btn icon-btn" icon="pi pi-check" (click)="pingUrlsEditSave(pingUrl, ri)"></button>
|
||||
<button *ngIf="editing" pButton type="button" pCancelEditableRow class="btn danger-icon-btn" icon="pi pi-times"
|
||||
(click)="pingUrlsEditCancel(pingUrl, ri)"></button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</ng-template>
|
||||
</p-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-divider"></div>
|
||||
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">
|
||||
{{'admin.settings.bot.technicianIds' | translate}}:
|
||||
</div>
|
||||
<div class="content-data-value-row">
|
||||
<p-table #dt [value]="technicianIds" dataKey="id" editMode="row">
|
||||
<ng-template pTemplate="caption">
|
||||
<div class="table-caption">
|
||||
<div class="table-caption-btn-wrapper btn-wrapper">
|
||||
<button pButton class="icon-btn btn"
|
||||
icon="pi pi-plus" (click)="technicianIdsAddNew(dt)">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
<ng-template pTemplate="body" let-technicianId let-editing="editing" let-ri="rowIndex">
|
||||
<tr [pEditableRow]="technicianId">
|
||||
<td>
|
||||
<p-cellEditor>
|
||||
<ng-template pTemplate="input">
|
||||
<input class="table-edit-input" pInputText type="text" [(ngModel)]="technicianId.value">
|
||||
</ng-template>
|
||||
<ng-template pTemplate="output">
|
||||
{{technicianId.value}}
|
||||
</ng-template>
|
||||
</p-cellEditor>
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-wrapper">
|
||||
<button *ngIf="!editing" pButton type="button" pInitEditableRow class="btn icon-btn" icon="pi pi-pencil" (click)="technicianIdsEditInit(technicianId, ri)"></button>
|
||||
<button *ngIf="!editing" pButton type="button" class="btn danger-icon-btn" icon="pi pi-trash" (click)="technicianIdsDelete(ri)"></button>
|
||||
|
||||
<button *ngIf="editing" pButton type="button" pSaveEditableRow class="btn icon-btn" icon="pi pi-check" (click)="technicianIdsEditSave(technicianId, ri)"></button>
|
||||
<button *ngIf="editing" pButton type="button" pCancelEditableRow class="btn danger-icon-btn" icon="pi pi-times"
|
||||
(click)="technicianIdsEditCancel(technicianId, ri)"></button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</ng-template>
|
||||
</p-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-divider"></div>
|
||||
<app-config-list translationKey="admin.settings.bot.ping_urls" [(data)]="config.pingURLs"></app-config-list>
|
||||
<app-config-list translationKey="admin.settings.bot.technician_ids" [(data)]="config.technicianIds"></app-config-list>
|
||||
|
||||
<div class="content-row">
|
||||
<button pButton icon="pi pi-save" label="{{'common.save' | translate}}" class="btn login-form-submit-btn"
|
||||
(click)="saveTechnicianConfig()" [disabled]="technicianConfigForm.invalid"></button>
|
||||
(click)="saveTechnicianConfig()"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from "@angular/forms";
|
||||
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
import { catchError } from "rxjs/operators";
|
||||
import { SettingsDTO } from "src/app/models/config/settings.dto";
|
||||
@ -17,17 +17,7 @@ import { DataService } from "../../../../../services/data/data.service";
|
||||
import { TechnicianConfigMutationResult } from "../../../../../models/graphql/result.model";
|
||||
import { Mutations } from "../../../../../models/graphql/mutations.model";
|
||||
import { AuthService } from "../../../../../services/auth/auth.service";
|
||||
import { Table } from "primeng/table";
|
||||
|
||||
type PingUrl = {
|
||||
id: number;
|
||||
value: string;
|
||||
};
|
||||
|
||||
type TechnicianId = {
|
||||
id: number;
|
||||
value: string;
|
||||
};
|
||||
|
||||
@Component({
|
||||
selector: "app-settings",
|
||||
@ -37,16 +27,6 @@ type TechnicianId = {
|
||||
export class SettingsComponent implements OnInit {
|
||||
|
||||
testMailForm!: FormGroup;
|
||||
technicianConfigForm: FormGroup = this.formBuilder.group({
|
||||
helpCommandReferenceUrl: [null, [Validators.required]],
|
||||
waitForRestart: [null, [Validators.required]],
|
||||
waitForShutdown: [null, [Validators.required]],
|
||||
cacheMaxMessages: [null, [Validators.required]]
|
||||
});
|
||||
pingUrls: PingUrl[] = [];
|
||||
clonedPingUrls: { [s: number]: PingUrl } = {};
|
||||
technicianIds: TechnicianId[] = [];
|
||||
clonedTechnicianIds: { [s: number]: TechnicianId } = {};
|
||||
data: SettingsDTO = {
|
||||
webVersion: "",
|
||||
apiVersion: "",
|
||||
@ -114,23 +94,6 @@ export class SettingsComponent implements OnInit {
|
||||
this.testMailForm = this.formBuilder.group({
|
||||
mail: [null, [Validators.required, Validators.email]]
|
||||
});
|
||||
this.technicianConfigForm = this.formBuilder.group({
|
||||
helpCommandReferenceUrl: [this.config.helpCommandReferenceUrl, [Validators.required]],
|
||||
waitForRestart: [this.config.waitForRestart, [Validators.required]],
|
||||
waitForShutdown: [this.config.waitForShutdown, [Validators.required]],
|
||||
cacheMaxMessages: [this.config.cacheMaxMessages, [Validators.required]]
|
||||
});
|
||||
let id = 0;
|
||||
for (const url of this.config.pingURLs ?? []) {
|
||||
this.pingUrls.push({ id: id, value: url });
|
||||
id++;
|
||||
}
|
||||
|
||||
id = 0;
|
||||
for (const technicianId of this.config.technicianIds ?? []) {
|
||||
this.technicianIds.push({ id: id, value: technicianId });
|
||||
id++;
|
||||
}
|
||||
}
|
||||
|
||||
testMail(): void {
|
||||
@ -187,16 +150,11 @@ export class SettingsComponent implements OnInit {
|
||||
waitForRestart: this.config.waitForRestart,
|
||||
waitForShutdown: this.config.waitForShutdown,
|
||||
cacheMaxMessages: this.config.cacheMaxMessages,
|
||||
pingURLs: this.pingUrls.filter(value => value.value).map(value => {
|
||||
return value.value;
|
||||
}),
|
||||
technicianIds: this.technicianIds.filter(value => value.value).map(value => {
|
||||
return value.value;
|
||||
})
|
||||
pingURLs: this.config.pingURLs,
|
||||
technicianIds: this.config.technicianIds
|
||||
}
|
||||
).pipe(catchError(err => {
|
||||
this.spinner.hideSpinner();
|
||||
this.toastService.error(this.translate.instant("admin.settings.message.technician_config_create_failed"), this.translate.instant("admin.settings.message.technician_config_create_failed_d"));
|
||||
return throwError(err);
|
||||
})).subscribe(result => {
|
||||
this.spinner.hideSpinner();
|
||||
@ -204,71 +162,5 @@ export class SettingsComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
pingUrlsAddNew(table: Table) {
|
||||
const id = Math.max.apply(Math, this.pingUrls.map(url => {
|
||||
return url.id ?? 0;
|
||||
})) + 1;
|
||||
const newItem = { id: id, value: "" };
|
||||
this.pingUrls.push(newItem);
|
||||
|
||||
table.initRowEdit(newItem);
|
||||
const index = this.pingUrls.findIndex(l => l.id == newItem.id);
|
||||
this.pingUrlsEditInit(newItem, index);
|
||||
}
|
||||
|
||||
pingUrlsEditInit(url: PingUrl, index: number) {
|
||||
this.clonedPingUrls[index] = { ...url };
|
||||
}
|
||||
|
||||
pingUrlsDelete(index: number) {
|
||||
this.pingUrls.splice(index, 1);
|
||||
}
|
||||
|
||||
pingUrlsEditSave(url: PingUrl, index: number) {
|
||||
if (!url.value || this.pingUrls[index] == this.clonedPingUrls[index]) {
|
||||
return;
|
||||
}
|
||||
|
||||
delete this.clonedPingUrls[index];
|
||||
}
|
||||
|
||||
pingUrlsEditCancel(url: PingUrl, index: number) {
|
||||
this.pingUrls[index] = this.clonedPingUrls[index];
|
||||
delete this.clonedPingUrls[index];
|
||||
}
|
||||
|
||||
|
||||
technicianIdsAddNew(table: Table) {
|
||||
const id = Math.max.apply(Math, this.technicianIds.map(url => {
|
||||
return url.id ?? 0;
|
||||
})) + 1;
|
||||
const newItem = { id: id, value: "" };
|
||||
this.technicianIds.push(newItem);
|
||||
|
||||
table.initRowEdit(newItem);
|
||||
const index = this.technicianIds.findIndex(l => l.id == newItem.id);
|
||||
this.technicianIdsEditInit(newItem, index);
|
||||
}
|
||||
|
||||
technicianIdsEditInit(url: PingUrl, index: number) {
|
||||
this.clonedTechnicianIds[index] = { ...url };
|
||||
}
|
||||
|
||||
technicianIdsDelete(index: number) {
|
||||
this.technicianIds.splice(index, 1);
|
||||
}
|
||||
|
||||
technicianIdsEditSave(url: PingUrl, index: number) {
|
||||
if (!url.value || this.technicianIds[index] == this.clonedTechnicianIds[index]) {
|
||||
return;
|
||||
}
|
||||
|
||||
delete this.clonedTechnicianIds[index];
|
||||
}
|
||||
|
||||
technicianIdsEditCancel(url: PingUrl, index: number) {
|
||||
this.technicianIds[index] = this.clonedTechnicianIds[index];
|
||||
delete this.clonedTechnicianIds[index];
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,45 @@
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">
|
||||
{{translationKey | translate}}:
|
||||
</div>
|
||||
<div class="content-data-value-row">
|
||||
<p-table #dt [value]="internal_data" dataKey="id" editMode="row">
|
||||
<ng-template pTemplate="caption">
|
||||
<div class="table-caption">
|
||||
<div class="table-caption-btn-wrapper btn-wrapper">
|
||||
<button pButton class="icon-btn btn"
|
||||
icon="pi pi-plus" (click)="addNew(dt)">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</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.value">
|
||||
</ng-template>
|
||||
<ng-template pTemplate="output">
|
||||
{{value.value}}
|
||||
</ng-template>
|
||||
</p-cellEditor>
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-wrapper">
|
||||
<button *ngIf="!editing" pButton type="button" pInitEditableRow class="btn icon-btn" icon="pi pi-pencil" (click)="editInit(value, ri)"></button>
|
||||
<button *ngIf="!editing" pButton type="button" class="btn danger-icon-btn" icon="pi pi-trash" (click)="delete(ri)"></button>
|
||||
|
||||
<button *ngIf="editing" pButton type="button" pSaveEditableRow class="btn icon-btn" icon="pi pi-check" (click)="editSave(value, ri)"></button>
|
||||
<button *ngIf="editing" pButton type="button" pCancelEditableRow class="btn danger-icon-btn" icon="pi pi-times"
|
||||
(click)="editCancel(ri)"></button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</ng-template>
|
||||
</p-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-divider"></div>
|
@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ConfigListComponent } from './config-list.component';
|
||||
|
||||
describe('ConfigListComponent', () => {
|
||||
let component: ConfigListComponent;
|
||||
let fixture: ComponentFixture<ConfigListComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ ConfigListComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ConfigListComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,72 @@
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
||||
import { Table } from "primeng/table";
|
||||
|
||||
@Component({
|
||||
selector: "app-config-list",
|
||||
templateUrl: "./config-list.component.html",
|
||||
styleUrls: ["./config-list.component.scss"]
|
||||
})
|
||||
export class ConfigListComponent {
|
||||
internal_data: any[] = [];
|
||||
|
||||
@Input() translationKey: string = "";
|
||||
|
||||
@Input()
|
||||
set data(val: any[]) {
|
||||
this.dataChange.emit(val);
|
||||
let id = 0;
|
||||
this.internal_data = val.map(value => {
|
||||
value = { id: id, value: value };
|
||||
id++;
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
get data() {
|
||||
return this.getData();
|
||||
}
|
||||
|
||||
@Output() dataChange: EventEmitter<any> = new EventEmitter<any>();
|
||||
clonedData: { [s: number]: any } = {};
|
||||
|
||||
private getData(): any[] {
|
||||
return this.internal_data.map(value => {
|
||||
return value.value;
|
||||
});
|
||||
}
|
||||
|
||||
addNew(table: Table) {
|
||||
const id = Math.max.apply(Math, this.internal_data.map(value => {
|
||||
return value.id ?? 0;
|
||||
})) + 1;
|
||||
const newItem = { id: id, value: "" };
|
||||
this.internal_data.push(newItem);
|
||||
|
||||
table.initRowEdit(newItem);
|
||||
const index = this.internal_data.findIndex(l => l.id == newItem.id);
|
||||
this.editInit(newItem, index);
|
||||
}
|
||||
|
||||
editInit(value: any, index: number) {
|
||||
this.clonedData[index] = { ...value };
|
||||
}
|
||||
|
||||
delete(index: number) {
|
||||
this.internal_data.splice(index, 1);
|
||||
this.dataChange.emit(this.getData());
|
||||
}
|
||||
|
||||
editSave(value: any, index: number) {
|
||||
if (!value.value || this.internal_data[index] == this.clonedData[index]) {
|
||||
return;
|
||||
}
|
||||
|
||||
delete this.clonedData[index];
|
||||
this.dataChange.emit(this.getData());
|
||||
}
|
||||
|
||||
editCancel(index: number) {
|
||||
this.internal_data[index] = this.clonedData[index];
|
||||
delete this.clonedData[index];
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@ import { ImageModule } from "primeng/image";
|
||||
import { SidebarModule } from "primeng/sidebar";
|
||||
import { HistoryBtnComponent } from './components/history-btn/history-btn.component';
|
||||
import { DataViewModule, DataViewLayoutOptions } from 'primeng/dataview';
|
||||
import { ConfigListComponent } from './components/config-list/config-list.component';
|
||||
|
||||
|
||||
@NgModule({
|
||||
@ -33,6 +34,7 @@ import { DataViewModule, DataViewLayoutOptions } from 'primeng/dataview';
|
||||
IpAddressPipe,
|
||||
BoolPipe,
|
||||
HistoryBtnComponent,
|
||||
ConfigListComponent,
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
@ -86,7 +88,8 @@ import { DataViewModule, DataViewLayoutOptions } from 'primeng/dataview';
|
||||
SidebarModule,
|
||||
HistoryBtnComponent,
|
||||
DataViewModule,
|
||||
DataViewLayoutOptions
|
||||
DataViewLayoutOptions,
|
||||
ConfigListComponent
|
||||
]
|
||||
})
|
||||
export class SharedModule { }
|
||||
|
@ -236,7 +236,6 @@ export class AchievementComponent implements OnInit, OnDestroy {
|
||||
).pipe(catchError(err => {
|
||||
this.isEditingNew = false;
|
||||
this.spinner.hideSpinner();
|
||||
this.toastService.error(this.translate.instant("view.server.achievements.message.achievement_create_failed"), this.translate.instant("view.server.achievements.message.achievement_create_failed_d"));
|
||||
return throwError(err);
|
||||
})).subscribe(result => {
|
||||
this.isEditingNew = false;
|
||||
@ -258,7 +257,6 @@ export class AchievementComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
).pipe(catchError(err => {
|
||||
this.spinner.hideSpinner();
|
||||
this.toastService.error(this.translate.instant("view.server.achievements.message.achievement_update_failed"), this.translate.instant("view.server.achievements.message.achievement_update_failed_d", { name: newAchievement.name }));
|
||||
return throwError(err);
|
||||
})).subscribe(_ => {
|
||||
this.spinner.hideSpinner();
|
||||
@ -290,7 +288,6 @@ export class AchievementComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
).pipe(catchError(err => {
|
||||
this.spinner.hideSpinner();
|
||||
this.toastService.error(this.translate.instant("view.server.achievements.message.achievement_delete_failed"), this.translate.instant("view.server.achievements.message.achievement_delete_failed_d", { name: achievement.name }));
|
||||
return throwError(err);
|
||||
})).subscribe(l => {
|
||||
this.spinner.hideSpinner();
|
||||
|
@ -222,7 +222,6 @@ export class AutoRolesRulesComponent implements OnInit, OnDestroy {
|
||||
).pipe(catchError(err => {
|
||||
this.isEditingNew = false;
|
||||
this.spinner.hideSpinner();
|
||||
this.toastService.error(this.translate.instant("view.server.auto_roles.rules.message.auto_role_rule_create_failed"), this.translate.instant("view.server.auto_roles.rules.message.auto_role_rule_create_failed_d"));
|
||||
return throwError(err);
|
||||
})).subscribe(result => {
|
||||
this.isEditingNew = false;
|
||||
@ -241,7 +240,6 @@ export class AutoRolesRulesComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
).pipe(catchError(err => {
|
||||
this.spinner.hideSpinner();
|
||||
this.toastService.error(this.translate.instant("view.server.auto_roles.rules.message.auto_role_rule_update_failed"), this.translate.instant("view.server.auto_roles.rules.message.auto_role_rule_update_failed_d"));
|
||||
return throwError(err);
|
||||
})).subscribe(result => {
|
||||
this.spinner.hideSpinner();
|
||||
@ -272,7 +270,6 @@ export class AutoRolesRulesComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
).pipe(catchError(err => {
|
||||
this.spinner.hideSpinner();
|
||||
this.toastService.error(this.translate.instant("view.server.auto_roles.rules.message.auto_role_rule_delete_failed"), this.translate.instant("view.server.auto_roles.rules.message.auto_role_rule_delete_failed_d", { id: autoRoleRule.id }));
|
||||
return throwError(err);
|
||||
})).subscribe(_ => {
|
||||
this.spinner.hideSpinner();
|
||||
|
@ -208,7 +208,6 @@ export class AutoRolesComponent implements OnInit, OnDestroy {
|
||||
).pipe(catchError(err => {
|
||||
this.isEditingNew = false;
|
||||
this.spinner.hideSpinner();
|
||||
this.toastService.error(this.translate.instant("view.server.auto_roles.message.auto_role_create_failed"), this.translate.instant("view.server.auto_roles.message.auto_role_create_failed_d"));
|
||||
return throwError(err);
|
||||
})).subscribe(result => {
|
||||
this.isEditingNew = false;
|
||||
@ -240,7 +239,6 @@ export class AutoRolesComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
).pipe(catchError(err => {
|
||||
this.spinner.hideSpinner();
|
||||
this.toastService.error(this.translate.instant("view.server.auto_roles.message.auto_role_delete_failed"), this.translate.instant("view.server.auto_roles.message.auto_role_delete_failed_d", { id: autoRole.id }));
|
||||
return throwError(err);
|
||||
})).subscribe(_ => {
|
||||
this.spinner.hideSpinner();
|
||||
|
@ -0,0 +1,123 @@
|
||||
<h1>
|
||||
{{'view.server.config.header' | translate}}
|
||||
</h1>
|
||||
|
||||
<div class="content-wrapper">
|
||||
<div class="content-header">
|
||||
<h2>
|
||||
{{'view.server.config.bot.header' | translate}}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'view.server.config.bot.message_delete_timer' | translate}}:</div>
|
||||
<input class="content-data-value" type="number" pInputText [(ngModel)]="config.messageDeleteTimer"
|
||||
placeholder="{{'view.server.config.bot.message_delete_timer' | translate}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'view.server.config.bot.notification_chat_id' | translate}}:</div>
|
||||
<input class="content-data-value" type="text" pInputText [(ngModel)]="config.notificationChatId"
|
||||
placeholder="{{'view.server.config.bot.notification_chat_id' | translate}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'view.server.config.bot.max_voice_state_hours' | translate}}:</div>
|
||||
<input class="content-data-value" type="number" pInputText [(ngModel)]="config.maxVoiceStateHours"
|
||||
placeholder="{{'view.server.config.bot.max_voice_state_hours' | translate}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'view.server.config.bot.xp_per_message' | translate}}:</div>
|
||||
<input class="content-data-value" type="number" pInputText [(ngModel)]="config.xpPerMessage" placeholder="{{'view.server.config.bot.xp_per_message' | translate}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'view.server.config.bot.xp_per_reaction' | translate}}:</div>
|
||||
<input class="content-data-value" type="number" pInputText [(ngModel)]="config.xpPerReaction" placeholder="{{'view.server.config.bot.xp_per_reaction' | translate}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'view.server.config.bot.max_message_xp_per_hour' | translate}}:</div>
|
||||
<input class="content-data-value" type="number" pInputText [(ngModel)]="config.maxMessageXpPerHour"
|
||||
placeholder="{{'view.server.config.bot.max_message_xp_per_hour' | translate}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'view.server.config.bot.xp_per_ontime_hour' | translate}}:</div>
|
||||
<input class="content-data-value" type="number" pInputText [(ngModel)]="config.xpPerOntimeHour" placeholder="{{'view.server.config.bot.xp_per_ontime_hour' | translate}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'view.server.config.bot.xp_per_event_participation' | translate}}:</div>
|
||||
<input class="content-data-value" type="number" pInputText [(ngModel)]="config.xpPerEventParticipation"
|
||||
placeholder="{{'view.server.config.bot.xp_per_event_participation' | translate}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'view.server.config.bot.xp_per_achievement' | translate}}:</div>
|
||||
<input class="content-data-value" type="number" pInputText [(ngModel)]="config.xpPerAchievement" placeholder="{{'view.server.config.bot.xp_per_achievement' | translate}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'view.server.config.bot.afk_command_channel_id' | translate}}:</div>
|
||||
<input class="content-data-value" type="text" pInputText [(ngModel)]="config.afkCommandChannelId"
|
||||
placeholder="{{'view.server.config.bot.afk_command_channel_id' | translate}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'view.server.config.bot.help_voice_channel_id' | translate}}:</div>
|
||||
<input class="content-data-value" type="text" pInputText [(ngModel)]="config.helpVoiceChannelId"
|
||||
placeholder="{{'view.server.config.bot.help_voice_channel_id' | translate}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'view.server.config.bot.team_channel_id' | translate}}:</div>
|
||||
<input class="content-data-value" type="text" pInputText [(ngModel)]="config.teamChannelId" placeholder="{{'view.server.config.bot.team_channel_id' | translate}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'view.server.config.bot.login_message_channel_id' | translate}}:</div>
|
||||
<input class="content-data-value" type="text" pInputText [(ngModel)]="config.loginMessageChannelId"
|
||||
placeholder="{{'view.server.config.bot.login_message_channel_id' | translate}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-divider"></div>
|
||||
<app-config-list translationKey="view.server.config.bot.afk_channels" [(data)]="config.afkChannelIds"></app-config-list>
|
||||
<app-config-list translationKey="view.server.config.bot.moderator_roles" [(data)]="config.moderatorRoleIds"></app-config-list>
|
||||
<app-config-list translationKey="view.server.config.bot.admin_roles" [(data)]="config.adminRoleIds"></app-config-list>
|
||||
|
||||
<div class="content-row">
|
||||
<button pButton icon="pi pi-save" label="{{'common.save' | translate}}" class="btn login-form-submit-btn"
|
||||
(click)="saveServerConfig()"></button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ConfigComponent } from './config.component';
|
||||
|
||||
describe('ConfigComponent', () => {
|
||||
let component: ConfigComponent;
|
||||
let fixture: ComponentFixture<ConfigComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ ConfigComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ConfigComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,116 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
import { catchError } from "rxjs/operators";
|
||||
import { GuiService } from "src/app/services/gui/gui.service";
|
||||
import { SettingsService } from "src/app/services/settings/settings.service";
|
||||
import { SpinnerService } from "src/app/services/spinner/spinner.service";
|
||||
import { ToastService } from "src/app/services/toast/toast.service";
|
||||
import { throwError } from "rxjs";
|
||||
import { Query, ServerConfigQuery } from "../../../../../../models/graphql/query.model";
|
||||
import { Queries } from "../../../../../../models/graphql/queries.model";
|
||||
import { DataService } from "../../../../../../services/data/data.service";
|
||||
import { ServerConfigMutationResult } from "../../../../../../models/graphql/result.model";
|
||||
import { Mutations } from "../../../../../../models/graphql/mutations.model";
|
||||
import { AuthService } from "../../../../../../services/auth/auth.service";
|
||||
import { ServerConfig } from "../../../../../../models/config/server-config.model";
|
||||
import { Server } from "../../../../../../models/data/server.model";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { Table } from "primeng/table";
|
||||
|
||||
type AFKChannelId = {
|
||||
id: number;
|
||||
value: string;
|
||||
};
|
||||
|
||||
@Component({
|
||||
selector: "app-config",
|
||||
templateUrl: "./config.component.html",
|
||||
styleUrls: ["./config.component.scss"]
|
||||
})
|
||||
export class ConfigComponent implements OnInit {
|
||||
config: ServerConfig = {
|
||||
messageDeleteTimer: 0,
|
||||
afkChannelIds: [],
|
||||
moderatorRoleIds: [],
|
||||
adminRoleIds: []
|
||||
};
|
||||
|
||||
|
||||
afkChannelIds: AFKChannelId[] = [];
|
||||
clonedAfkChannelIds: { [s: number]: AFKChannelId } = {};
|
||||
|
||||
private server: Server = {};
|
||||
|
||||
constructor(
|
||||
private data: DataService,
|
||||
private settingsService: SettingsService,
|
||||
private spinnerService: SpinnerService,
|
||||
private guiService: GuiService,
|
||||
private formBuilder: FormBuilder,
|
||||
private toastService: ToastService,
|
||||
private translate: TranslateService,
|
||||
private authService: AuthService,
|
||||
private spinner: SpinnerService,
|
||||
private route: ActivatedRoute
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.spinnerService.showSpinner();
|
||||
|
||||
this.data.getServerFromRoute(this.route).then(async server => {
|
||||
this.server = server;
|
||||
this.loadConfig();
|
||||
});
|
||||
}
|
||||
|
||||
loadConfig() {
|
||||
this.data.query<ServerConfigQuery>(Queries.serverConfigQuery, {
|
||||
serverId: this.server.id
|
||||
},
|
||||
(data: Query) => {
|
||||
return data.servers[0];
|
||||
}).subscribe(data => {
|
||||
this.config = data.config;
|
||||
|
||||
let id = 0;
|
||||
for (const afkChannelId of this.config.afkChannelIds ?? []) {
|
||||
this.afkChannelIds.push({ id: id, value: afkChannelId });
|
||||
id++;
|
||||
}
|
||||
|
||||
this.spinnerService.hideSpinner();
|
||||
});
|
||||
}
|
||||
|
||||
saveServerConfig() {
|
||||
this.spinner.showSpinner();
|
||||
this.data.mutation<ServerConfigMutationResult>(Mutations.updateServerConfig, {
|
||||
id: this.config.id,
|
||||
messageDeleteTimer: this.config.messageDeleteTimer,
|
||||
notificationChatId: this.config.notificationChatId,
|
||||
maxVoiceStateHours: this.config.maxVoiceStateHours,
|
||||
xpPerMessage: this.config.xpPerMessage,
|
||||
xpPerReaction: this.config.xpPerReaction,
|
||||
maxMessageXpPerHour: this.config.maxMessageXpPerHour,
|
||||
xpPerOntimeHour: this.config.xpPerOntimeHour,
|
||||
xpPerEventParticipation: this.config.xpPerEventParticipation,
|
||||
xpPerAchievement: this.config.xpPerAchievement,
|
||||
afkCommandChannelId: this.config.afkCommandChannelId,
|
||||
helpVoiceChannelId: this.config.helpVoiceChannelId,
|
||||
teamChannelId: this.config.teamChannelId,
|
||||
loginMessageChannelId: this.config.loginMessageChannelId,
|
||||
afkChannelIds: this.config.afkChannelIds,
|
||||
moderatorRoleIds: this.config.moderatorRoleIds,
|
||||
adminRoleIds: this.config.adminRoleIds
|
||||
}
|
||||
).pipe(catchError(err => {
|
||||
this.spinner.hideSpinner();
|
||||
return throwError(err);
|
||||
})).subscribe(result => {
|
||||
this.spinner.hideSpinner();
|
||||
this.toastService.success(this.translate.instant("view.server.config.message.technician_config_create"), this.translate.instant("view.server.config.message.technician_config_create_d"));
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { ConfigComponent } from "./components/config/config.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{path: '', component: ConfigComponent},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class ConfigRoutingModule { }
|
19
kdb-web/src/app/modules/view/server/config/config.module.ts
Normal file
19
kdb-web/src/app/modules/view/server/config/config.module.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { ConfigRoutingModule } from './config-routing.module';
|
||||
import { ConfigComponent } from './components/config/config.component';
|
||||
import { SharedModule } from "../../../shared/shared.module";
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
ConfigComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
ConfigRoutingModule,
|
||||
SharedModule,
|
||||
]
|
||||
})
|
||||
export class ConfigModule { }
|
@ -196,7 +196,6 @@ export class LevelsComponent implements OnInit, OnDestroy {
|
||||
).pipe(catchError(err => {
|
||||
this.isEditingNew = false;
|
||||
this.spinner.hideSpinner();
|
||||
this.toastService.error(this.translate.instant("view.server.levels.message.level_create_failed"), this.translate.instant("view.server.levels.message.level_create_failed_d"));
|
||||
return throwError(err);
|
||||
})).subscribe(result => {
|
||||
this.isEditingNew = false;
|
||||
@ -217,7 +216,6 @@ export class LevelsComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
).pipe(catchError(err => {
|
||||
this.spinner.hideSpinner();
|
||||
this.toastService.error(this.translate.instant("view.server.levels.message.level_update_failed"), this.translate.instant("view.server.levels.message.level_update_failed_d", { name: newLevel.name }));
|
||||
return throwError(err);
|
||||
})).subscribe(_ => {
|
||||
this.spinner.hideSpinner();
|
||||
@ -249,7 +247,6 @@ export class LevelsComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
).pipe(catchError(err => {
|
||||
this.spinner.hideSpinner();
|
||||
this.toastService.error(this.translate.instant("view.server.levels.message.level_delete_failed"), this.translate.instant("view.server.levels.message.level_delete_failed_d", { name: level.name }));
|
||||
return throwError(err);
|
||||
})).subscribe(l => {
|
||||
this.spinner.hideSpinner();
|
||||
|
@ -237,7 +237,6 @@ export class MembersComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
).pipe(catchError(err => {
|
||||
this.spinner.hideSpinner();
|
||||
this.toastService.error(this.translate.instant("view.server.members.message.user_change_failed"), this.translate.instant("view.server.members.message.user_change_failed_d", { name: newUser.name }));
|
||||
return throwError(err);
|
||||
})).subscribe(_ => {
|
||||
this.spinner.hideSpinner();
|
||||
|
@ -10,7 +10,8 @@ const routes: Routes = [
|
||||
{ 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) },
|
||||
{ path: "achievements", loadChildren: () => import("./achievements/achievements.module").then(m => m.AchievementsModule) }
|
||||
{ path: "achievements", loadChildren: () => import("./achievements/achievements.module").then(m => m.AchievementsModule) },
|
||||
{ path: "config", loadChildren: () => import("./config/config.module").then(m => m.ConfigModule) }
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
@ -10,6 +10,8 @@ import { Query } from "../../models/graphql/query.model";
|
||||
import { SidebarService } from "../sidebar/sidebar.service";
|
||||
import { SpinnerService } from "../spinner/spinner.service";
|
||||
import { GraphQLResult } from "../../models/graphql/result.model";
|
||||
import { ToastService } from "../toast/toast.service";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
|
||||
@Injectable({
|
||||
providedIn: "root"
|
||||
@ -21,7 +23,9 @@ export class DataService {
|
||||
private http: HttpClient,
|
||||
private sidebar: SidebarService,
|
||||
private spinner: SpinnerService,
|
||||
private router: Router
|
||||
private router: Router,
|
||||
private toast: ToastService,
|
||||
private translate: TranslateService,
|
||||
) {
|
||||
}
|
||||
|
||||
@ -72,6 +76,10 @@ export class DataService {
|
||||
})
|
||||
.pipe(map(d => {
|
||||
if (d.errors && d.errors.length > 0) {
|
||||
d.errors.forEach((error: Error) => {
|
||||
this.toast.error(this.translate.instant("common.error"), error.message)
|
||||
});
|
||||
|
||||
throw new Error(d.errors.toString());
|
||||
}
|
||||
return d.data;
|
||||
|
@ -3,7 +3,7 @@ import { MenuItem } from "primeng/api";
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
import { AuthRoles } from "../../models/auth/auth-roles.enum";
|
||||
import { AuthService } from "../auth/auth.service";
|
||||
import { LangChangeEvent, TranslateService } from "@ngx-translate/core";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
import { NavigationEnd, Router } from "@angular/router";
|
||||
import { ThemeService } from "../theme/theme.service";
|
||||
import { Server } from "../../models/data/server.model";
|
||||
@ -25,6 +25,7 @@ export class SidebarService {
|
||||
serverAutoRoles: MenuItem = {};
|
||||
serverLevels: MenuItem = {};
|
||||
serverAchievements: MenuItem = {};
|
||||
serverConfig: MenuItem = {};
|
||||
serverMenu: MenuItem = {};
|
||||
adminConfig: MenuItem = {};
|
||||
adminUsers: MenuItem = {};
|
||||
@ -110,12 +111,19 @@ export class SidebarService {
|
||||
routerLink: `server/${this.server$.value?.id}/achievements`
|
||||
};
|
||||
|
||||
this.serverConfig = {
|
||||
label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.config") : "",
|
||||
icon: "pi pi-cog",
|
||||
visible: true,
|
||||
routerLink: `server/${this.server$.value?.id}/config`
|
||||
};
|
||||
|
||||
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, this.serverLevels, this.serverAchievements]
|
||||
items: [this.serverDashboard, this.serverProfile, this.serverMembers, this.serverAutoRoles, this.serverLevels, this.serverAchievements, this.serverConfig]
|
||||
};
|
||||
this.adminConfig = {
|
||||
label: this.isSidebarOpen ? this.translateService.instant("sidebar.config") : "",
|
||||
@ -151,6 +159,7 @@ export class SidebarService {
|
||||
this.serverAutoRoles.visible = !!user?.isModerator;
|
||||
this.serverLevels.visible = !!user?.isModerator;
|
||||
this.serverAchievements.visible = !!user?.isModerator;
|
||||
this.serverConfig.visible = !!user?.isAdmin;
|
||||
} else {
|
||||
this.serverMenu.visible = false;
|
||||
}
|
||||
|
@ -37,7 +37,7 @@
|
||||
"header": "Bot",
|
||||
"help_url": "Befehlsreferenz",
|
||||
"ping_urls": "Ping Adressen",
|
||||
"technicianIds": "Techniker Ids",
|
||||
"technician_ids": "Techniker Ids",
|
||||
"wait_for_restart": "Wartezeit vor Neustart",
|
||||
"wait_for_shutdown": "Wartezeit vor Herunterfahren"
|
||||
},
|
||||
@ -156,7 +156,7 @@
|
||||
"id": "Id",
|
||||
"leftServer": "Server verlassen",
|
||||
"messageId": "Nachricht Id",
|
||||
"minXp": "Min. XP",
|
||||
"min_xp": "Min. XP",
|
||||
"name": "Name",
|
||||
"operator": "Operator",
|
||||
"permissions": "Berechtigung",
|
||||
@ -407,6 +407,28 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"bot": {
|
||||
"admin_roles": "Admin Rollen",
|
||||
"afk_channels": "AFK Sprachkanäle",
|
||||
"afk_command_channel_id": "AFK Kanal für den Befehl /afk",
|
||||
"header": "Bot Konfiguration",
|
||||
"help_voice_channel_id": "Sprachkanal für Hilfsbenachrichtung",
|
||||
"login_message_channel_id": "Kanal für die Nachricht vom Bot nach Start",
|
||||
"max_message_xp_per_hour": "Maximale XP pro Stunde durch Nachrichten",
|
||||
"max_voice_state_hours": "Maximale Stunden für eine ontime nach Bot neustart",
|
||||
"message_delete_timer": "Zeit bis zum löschen einer Botnachricht in sekunden",
|
||||
"moderator_roles": "Moderator Rollen",
|
||||
"notification_chat_id": "Benachrichtungskanal",
|
||||
"team_channel_id": "Team chat",
|
||||
"xp_per_achievement": "XP für Errungenschaft",
|
||||
"xp_per_event_participation": "XP für Event Teilnahme",
|
||||
"xp_per_message": "XP für eine Nachricht",
|
||||
"xp_per_ontime_hour": "XP für eine Stunde im Sprachkanal",
|
||||
"xp_per_reaction": "XP für eine Reaktion"
|
||||
},
|
||||
"header": "Server Konfiguration"
|
||||
},
|
||||
"dashboard": {
|
||||
"deleted_message_count": "Gelöschte Nachrichten",
|
||||
"header": "Server dashboard",
|
||||
|
@ -37,7 +37,7 @@
|
||||
"header": "Bot",
|
||||
"help_url": "Help URL",
|
||||
"ping_urls": "Ping addresses",
|
||||
"technicianIds": "Technician Ids",
|
||||
"technician_ids": "Technician Ids",
|
||||
"wait_for_restart": "Time to wait before restart",
|
||||
"wait_for_shutdown": "Time to wait before shutdown"
|
||||
},
|
||||
@ -156,7 +156,7 @@
|
||||
"id": "Id",
|
||||
"leftServer": "Left server",
|
||||
"messageId": "Message Id",
|
||||
"minXp": "Min. XP",
|
||||
"min_xp": "Min. XP",
|
||||
"name": "Name",
|
||||
"operator": "Operator",
|
||||
"permissions": "Permissions",
|
||||
@ -407,6 +407,28 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"bot": {
|
||||
"admin_roles": "Admin Roles",
|
||||
"afk_channels": "AFK Voicechannel",
|
||||
"afk_command_channel_id": "AFK Channel for the command /afk",
|
||||
"header": "Bot configuration",
|
||||
"help_voice_channel_id": "Voicechannel für help notifications",
|
||||
"login_message_channel_id": "Channel for bot message after start",
|
||||
"max_message_xp_per_hour": "Max xp per hour with message",
|
||||
"max_voice_state_hours": "Max ontime hours after bot restart",
|
||||
"message_delete_timer": "Time to wait before delete bot messages",
|
||||
"moderator_roles": "Moderator roles",
|
||||
"notification_chat_id": "Notification channel",
|
||||
"team_channel_id": "Team chat",
|
||||
"xp_per_achievement": "XP for achievement",
|
||||
"xp_per_event_participation": "XP for event participation",
|
||||
"xp_per_message": "XP for message",
|
||||
"xp_per_ontime_hour": "XP for one hour in an voice channel",
|
||||
"xp_per_reaction": "XP for an reaction"
|
||||
},
|
||||
"header": "Server configuration"
|
||||
},
|
||||
"dashboard": {
|
||||
"deleted_message_count": "Deleted messages",
|
||||
"header": "Server dashboard",
|
||||
@ -487,7 +509,7 @@
|
||||
"ontime": "Ontime",
|
||||
"permission_denied": "Access denied!",
|
||||
"permission_denied_d": "You have to be moderator to see other profiles!",
|
||||
"xp": "Xp"
|
||||
"xp": "XP"
|
||||
}
|
||||
},
|
||||
"user_settings": {
|
||||
|
Loading…
Reference in New Issue
Block a user