Added server config to frontend #127
This commit is contained in:
parent
45a96cf06e
commit
97e7f2f01e
@ -150,6 +150,12 @@ class ServerConfigMutation(QueryABC):
|
|||||||
|
|
||||||
self._server_configs.delete_server_team_role_id_config(role_id)
|
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:
|
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)):
|
if role_id.role_id in old_config.team_role_ids.select(lambda x: str(x.role_id)):
|
||||||
continue
|
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;
|
waitForRestart?: number;
|
||||||
waitForShutdown?: number;
|
waitForShutdown?: number;
|
||||||
cacheMaxMessages?: number;
|
cacheMaxMessages?: number;
|
||||||
pingURLs?: string[];
|
pingURLs: string[];
|
||||||
technicianIds?: string[];
|
technicianIds: string[];
|
||||||
}
|
}
|
||||||
|
@ -166,8 +166,6 @@ export class Mutations {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static updateTechnicianConfig = `
|
static updateTechnicianConfig = `
|
||||||
mutation updateTechnicianConfig($id: ID, $helpCommandReferenceUrl: String, $waitForRestart: Int, $waitForShutdown: Int, $cacheMaxMessages: Int, $pingURLs: [String], $technicianIds: [String]) {
|
mutation updateTechnicianConfig($id: ID, $helpCommandReferenceUrl: String, $waitForRestart: Int, $waitForShutdown: Int, $cacheMaxMessages: Int, $pingURLs: [String], $technicianIds: [String]) {
|
||||||
technicianConfig {
|
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 {
|
export class Queries {
|
||||||
|
|
||||||
static technicianConfigQuery = `
|
|
||||||
query technicianConfigQuery {
|
|
||||||
technicianConfig {
|
|
||||||
id
|
|
||||||
helpCommandReferenceUrl
|
|
||||||
waitForRestart
|
|
||||||
waitForShutdown
|
|
||||||
cacheMaxMessages
|
|
||||||
pingURLs
|
|
||||||
technicianIds
|
|
||||||
|
|
||||||
createdAt
|
|
||||||
modifiedAt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
static guildsQuery = `
|
static guildsQuery = `
|
||||||
query GuildsQuery($id: ID) {
|
query GuildsQuery($id: ID) {
|
||||||
guilds(filter: {id: $id}) {
|
guilds(filter: {id: $id}) {
|
||||||
@ -71,7 +54,7 @@ export class Queries {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`;
|
||||||
|
|
||||||
static levelQuery = `
|
static levelQuery = `
|
||||||
query LevelsList($serverId: ID, $filter: LevelFilter, $page: Page, $sort: Sort) {
|
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 { Level } from "../data/level.model";
|
||||||
import { Achievement, AchievementAttribute } from "../data/achievement.model";
|
import { Achievement, AchievementAttribute } from "../data/achievement.model";
|
||||||
import { TechnicianConfig } from "../config/technician-config.model";
|
import { TechnicianConfig } from "../config/technician-config.model";
|
||||||
|
import { ServerConfig } from "../config/server-config.model";
|
||||||
|
|
||||||
export interface Query {
|
export interface Query {
|
||||||
serverCount: number;
|
serverCount: number;
|
||||||
@ -15,6 +16,10 @@ export interface TechnicianConfigQuery {
|
|||||||
technicianConfig: TechnicianConfig;
|
technicianConfig: TechnicianConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ServerConfigQuery {
|
||||||
|
config: ServerConfig;
|
||||||
|
}
|
||||||
|
|
||||||
export interface SingleDiscordQuery {
|
export interface SingleDiscordQuery {
|
||||||
guilds: Guild[];
|
guilds: Guild[];
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import { Level } from "../data/level.model";
|
|||||||
import { Server } from "../data/server.model";
|
import { Server } from "../data/server.model";
|
||||||
import { Achievement } from "../data/achievement.model";
|
import { Achievement } from "../data/achievement.model";
|
||||||
import { TechnicianConfig } from "../config/technician-config.model";
|
import { TechnicianConfig } from "../config/technician-config.model";
|
||||||
|
import { ServerConfig } from "../config/server-config.model";
|
||||||
|
|
||||||
export interface GraphQLResult {
|
export interface GraphQLResult {
|
||||||
data: {
|
data: {
|
||||||
@ -54,6 +55,12 @@ export interface TechnicianConfigMutationResult {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ServerConfigMutationResult {
|
||||||
|
serverConfig: {
|
||||||
|
updateServerConfig?: ServerConfig
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export interface AchievementMutationResult {
|
export interface AchievementMutationResult {
|
||||||
achievement: {
|
achievement: {
|
||||||
createAchievement?: Achievement
|
createAchievement?: Achievement
|
||||||
|
@ -160,103 +160,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</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>
|
<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">
|
<div class="content-row">
|
||||||
<button pButton icon="pi pi-save" label="{{'common.save' | translate}}" class="btn login-form-submit-btn"
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
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 { TranslateService } from "@ngx-translate/core";
|
||||||
import { catchError } from "rxjs/operators";
|
import { catchError } from "rxjs/operators";
|
||||||
import { SettingsDTO } from "src/app/models/config/settings.dto";
|
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 { TechnicianConfigMutationResult } from "../../../../../models/graphql/result.model";
|
||||||
import { Mutations } from "../../../../../models/graphql/mutations.model";
|
import { Mutations } from "../../../../../models/graphql/mutations.model";
|
||||||
import { AuthService } from "../../../../../services/auth/auth.service";
|
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({
|
@Component({
|
||||||
selector: "app-settings",
|
selector: "app-settings",
|
||||||
@ -37,16 +27,6 @@ type TechnicianId = {
|
|||||||
export class SettingsComponent implements OnInit {
|
export class SettingsComponent implements OnInit {
|
||||||
|
|
||||||
testMailForm!: FormGroup;
|
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 = {
|
data: SettingsDTO = {
|
||||||
webVersion: "",
|
webVersion: "",
|
||||||
apiVersion: "",
|
apiVersion: "",
|
||||||
@ -114,23 +94,6 @@ export class SettingsComponent implements OnInit {
|
|||||||
this.testMailForm = this.formBuilder.group({
|
this.testMailForm = this.formBuilder.group({
|
||||||
mail: [null, [Validators.required, Validators.email]]
|
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 {
|
testMail(): void {
|
||||||
@ -187,16 +150,11 @@ export class SettingsComponent implements OnInit {
|
|||||||
waitForRestart: this.config.waitForRestart,
|
waitForRestart: this.config.waitForRestart,
|
||||||
waitForShutdown: this.config.waitForShutdown,
|
waitForShutdown: this.config.waitForShutdown,
|
||||||
cacheMaxMessages: this.config.cacheMaxMessages,
|
cacheMaxMessages: this.config.cacheMaxMessages,
|
||||||
pingURLs: this.pingUrls.filter(value => value.value).map(value => {
|
pingURLs: this.config.pingURLs,
|
||||||
return value.value;
|
technicianIds: this.config.technicianIds
|
||||||
}),
|
|
||||||
technicianIds: this.technicianIds.filter(value => value.value).map(value => {
|
|
||||||
return value.value;
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
).pipe(catchError(err => {
|
).pipe(catchError(err => {
|
||||||
this.spinner.hideSpinner();
|
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);
|
return throwError(err);
|
||||||
})).subscribe(result => {
|
})).subscribe(result => {
|
||||||
this.spinner.hideSpinner();
|
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 { SidebarModule } from "primeng/sidebar";
|
||||||
import { HistoryBtnComponent } from './components/history-btn/history-btn.component';
|
import { HistoryBtnComponent } from './components/history-btn/history-btn.component';
|
||||||
import { DataViewModule, DataViewLayoutOptions } from 'primeng/dataview';
|
import { DataViewModule, DataViewLayoutOptions } from 'primeng/dataview';
|
||||||
|
import { ConfigListComponent } from './components/config-list/config-list.component';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@ -33,6 +34,7 @@ import { DataViewModule, DataViewLayoutOptions } from 'primeng/dataview';
|
|||||||
IpAddressPipe,
|
IpAddressPipe,
|
||||||
BoolPipe,
|
BoolPipe,
|
||||||
HistoryBtnComponent,
|
HistoryBtnComponent,
|
||||||
|
ConfigListComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@ -86,7 +88,8 @@ import { DataViewModule, DataViewLayoutOptions } from 'primeng/dataview';
|
|||||||
SidebarModule,
|
SidebarModule,
|
||||||
HistoryBtnComponent,
|
HistoryBtnComponent,
|
||||||
DataViewModule,
|
DataViewModule,
|
||||||
DataViewLayoutOptions
|
DataViewLayoutOptions,
|
||||||
|
ConfigListComponent
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class SharedModule { }
|
export class SharedModule { }
|
||||||
|
@ -236,7 +236,6 @@ export class AchievementComponent implements OnInit, OnDestroy {
|
|||||||
).pipe(catchError(err => {
|
).pipe(catchError(err => {
|
||||||
this.isEditingNew = false;
|
this.isEditingNew = false;
|
||||||
this.spinner.hideSpinner();
|
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);
|
return throwError(err);
|
||||||
})).subscribe(result => {
|
})).subscribe(result => {
|
||||||
this.isEditingNew = false;
|
this.isEditingNew = false;
|
||||||
@ -258,7 +257,6 @@ export class AchievementComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
).pipe(catchError(err => {
|
).pipe(catchError(err => {
|
||||||
this.spinner.hideSpinner();
|
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);
|
return throwError(err);
|
||||||
})).subscribe(_ => {
|
})).subscribe(_ => {
|
||||||
this.spinner.hideSpinner();
|
this.spinner.hideSpinner();
|
||||||
@ -290,7 +288,6 @@ export class AchievementComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
).pipe(catchError(err => {
|
).pipe(catchError(err => {
|
||||||
this.spinner.hideSpinner();
|
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);
|
return throwError(err);
|
||||||
})).subscribe(l => {
|
})).subscribe(l => {
|
||||||
this.spinner.hideSpinner();
|
this.spinner.hideSpinner();
|
||||||
|
@ -222,7 +222,6 @@ export class AutoRolesRulesComponent implements OnInit, OnDestroy {
|
|||||||
).pipe(catchError(err => {
|
).pipe(catchError(err => {
|
||||||
this.isEditingNew = false;
|
this.isEditingNew = false;
|
||||||
this.spinner.hideSpinner();
|
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);
|
return throwError(err);
|
||||||
})).subscribe(result => {
|
})).subscribe(result => {
|
||||||
this.isEditingNew = false;
|
this.isEditingNew = false;
|
||||||
@ -241,7 +240,6 @@ export class AutoRolesRulesComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
).pipe(catchError(err => {
|
).pipe(catchError(err => {
|
||||||
this.spinner.hideSpinner();
|
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);
|
return throwError(err);
|
||||||
})).subscribe(result => {
|
})).subscribe(result => {
|
||||||
this.spinner.hideSpinner();
|
this.spinner.hideSpinner();
|
||||||
@ -272,7 +270,6 @@ export class AutoRolesRulesComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
).pipe(catchError(err => {
|
).pipe(catchError(err => {
|
||||||
this.spinner.hideSpinner();
|
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);
|
return throwError(err);
|
||||||
})).subscribe(_ => {
|
})).subscribe(_ => {
|
||||||
this.spinner.hideSpinner();
|
this.spinner.hideSpinner();
|
||||||
|
@ -208,7 +208,6 @@ export class AutoRolesComponent implements OnInit, OnDestroy {
|
|||||||
).pipe(catchError(err => {
|
).pipe(catchError(err => {
|
||||||
this.isEditingNew = false;
|
this.isEditingNew = false;
|
||||||
this.spinner.hideSpinner();
|
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);
|
return throwError(err);
|
||||||
})).subscribe(result => {
|
})).subscribe(result => {
|
||||||
this.isEditingNew = false;
|
this.isEditingNew = false;
|
||||||
@ -240,7 +239,6 @@ export class AutoRolesComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
).pipe(catchError(err => {
|
).pipe(catchError(err => {
|
||||||
this.spinner.hideSpinner();
|
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);
|
return throwError(err);
|
||||||
})).subscribe(_ => {
|
})).subscribe(_ => {
|
||||||
this.spinner.hideSpinner();
|
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 => {
|
).pipe(catchError(err => {
|
||||||
this.isEditingNew = false;
|
this.isEditingNew = false;
|
||||||
this.spinner.hideSpinner();
|
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);
|
return throwError(err);
|
||||||
})).subscribe(result => {
|
})).subscribe(result => {
|
||||||
this.isEditingNew = false;
|
this.isEditingNew = false;
|
||||||
@ -217,7 +216,6 @@ export class LevelsComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
).pipe(catchError(err => {
|
).pipe(catchError(err => {
|
||||||
this.spinner.hideSpinner();
|
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);
|
return throwError(err);
|
||||||
})).subscribe(_ => {
|
})).subscribe(_ => {
|
||||||
this.spinner.hideSpinner();
|
this.spinner.hideSpinner();
|
||||||
@ -249,7 +247,6 @@ export class LevelsComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
).pipe(catchError(err => {
|
).pipe(catchError(err => {
|
||||||
this.spinner.hideSpinner();
|
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);
|
return throwError(err);
|
||||||
})).subscribe(l => {
|
})).subscribe(l => {
|
||||||
this.spinner.hideSpinner();
|
this.spinner.hideSpinner();
|
||||||
|
@ -237,7 +237,6 @@ export class MembersComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
).pipe(catchError(err => {
|
).pipe(catchError(err => {
|
||||||
this.spinner.hideSpinner();
|
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);
|
return throwError(err);
|
||||||
})).subscribe(_ => {
|
})).subscribe(_ => {
|
||||||
this.spinner.hideSpinner();
|
this.spinner.hideSpinner();
|
||||||
|
@ -10,7 +10,8 @@ const routes: Routes = [
|
|||||||
{ path: "members/:memberId", component: ProfileComponent },
|
{ path: "members/:memberId", component: ProfileComponent },
|
||||||
{ path: "auto-roles", loadChildren: () => import("./auto-role/auto-role.module").then(m => m.AutoRoleModule) },
|
{ 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: "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({
|
@NgModule({
|
||||||
|
@ -10,6 +10,8 @@ import { Query } from "../../models/graphql/query.model";
|
|||||||
import { SidebarService } from "../sidebar/sidebar.service";
|
import { SidebarService } from "../sidebar/sidebar.service";
|
||||||
import { SpinnerService } from "../spinner/spinner.service";
|
import { SpinnerService } from "../spinner/spinner.service";
|
||||||
import { GraphQLResult } from "../../models/graphql/result.model";
|
import { GraphQLResult } from "../../models/graphql/result.model";
|
||||||
|
import { ToastService } from "../toast/toast.service";
|
||||||
|
import { TranslateService } from "@ngx-translate/core";
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: "root"
|
providedIn: "root"
|
||||||
@ -21,7 +23,9 @@ export class DataService {
|
|||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private sidebar: SidebarService,
|
private sidebar: SidebarService,
|
||||||
private spinner: SpinnerService,
|
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 => {
|
.pipe(map(d => {
|
||||||
if (d.errors && d.errors.length > 0) {
|
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());
|
throw new Error(d.errors.toString());
|
||||||
}
|
}
|
||||||
return d.data;
|
return d.data;
|
||||||
|
@ -3,7 +3,7 @@ import { MenuItem } from "primeng/api";
|
|||||||
import { BehaviorSubject } from "rxjs";
|
import { BehaviorSubject } from "rxjs";
|
||||||
import { AuthRoles } from "../../models/auth/auth-roles.enum";
|
import { AuthRoles } from "../../models/auth/auth-roles.enum";
|
||||||
import { AuthService } from "../auth/auth.service";
|
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 { NavigationEnd, Router } from "@angular/router";
|
||||||
import { ThemeService } from "../theme/theme.service";
|
import { ThemeService } from "../theme/theme.service";
|
||||||
import { Server } from "../../models/data/server.model";
|
import { Server } from "../../models/data/server.model";
|
||||||
@ -25,6 +25,7 @@ export class SidebarService {
|
|||||||
serverAutoRoles: MenuItem = {};
|
serverAutoRoles: MenuItem = {};
|
||||||
serverLevels: MenuItem = {};
|
serverLevels: MenuItem = {};
|
||||||
serverAchievements: MenuItem = {};
|
serverAchievements: MenuItem = {};
|
||||||
|
serverConfig: MenuItem = {};
|
||||||
serverMenu: MenuItem = {};
|
serverMenu: MenuItem = {};
|
||||||
adminConfig: MenuItem = {};
|
adminConfig: MenuItem = {};
|
||||||
adminUsers: MenuItem = {};
|
adminUsers: MenuItem = {};
|
||||||
@ -110,12 +111,19 @@ export class SidebarService {
|
|||||||
routerLink: `server/${this.server$.value?.id}/achievements`
|
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 = {
|
this.serverMenu = {
|
||||||
label: this.isSidebarOpen ? this.server$.value?.name : "",
|
label: this.isSidebarOpen ? this.server$.value?.name : "",
|
||||||
icon: "pi pi-server",
|
icon: "pi pi-server",
|
||||||
visible: false,
|
visible: false,
|
||||||
expanded: true,
|
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 = {
|
this.adminConfig = {
|
||||||
label: this.isSidebarOpen ? this.translateService.instant("sidebar.config") : "",
|
label: this.isSidebarOpen ? this.translateService.instant("sidebar.config") : "",
|
||||||
@ -151,6 +159,7 @@ export class SidebarService {
|
|||||||
this.serverAutoRoles.visible = !!user?.isModerator;
|
this.serverAutoRoles.visible = !!user?.isModerator;
|
||||||
this.serverLevels.visible = !!user?.isModerator;
|
this.serverLevels.visible = !!user?.isModerator;
|
||||||
this.serverAchievements.visible = !!user?.isModerator;
|
this.serverAchievements.visible = !!user?.isModerator;
|
||||||
|
this.serverConfig.visible = !!user?.isAdmin;
|
||||||
} else {
|
} else {
|
||||||
this.serverMenu.visible = false;
|
this.serverMenu.visible = false;
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
"header": "Bot",
|
"header": "Bot",
|
||||||
"help_url": "Befehlsreferenz",
|
"help_url": "Befehlsreferenz",
|
||||||
"ping_urls": "Ping Adressen",
|
"ping_urls": "Ping Adressen",
|
||||||
"technicianIds": "Techniker Ids",
|
"technician_ids": "Techniker Ids",
|
||||||
"wait_for_restart": "Wartezeit vor Neustart",
|
"wait_for_restart": "Wartezeit vor Neustart",
|
||||||
"wait_for_shutdown": "Wartezeit vor Herunterfahren"
|
"wait_for_shutdown": "Wartezeit vor Herunterfahren"
|
||||||
},
|
},
|
||||||
@ -156,7 +156,7 @@
|
|||||||
"id": "Id",
|
"id": "Id",
|
||||||
"leftServer": "Server verlassen",
|
"leftServer": "Server verlassen",
|
||||||
"messageId": "Nachricht Id",
|
"messageId": "Nachricht Id",
|
||||||
"minXp": "Min. XP",
|
"min_xp": "Min. XP",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"operator": "Operator",
|
"operator": "Operator",
|
||||||
"permissions": "Berechtigung",
|
"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": {
|
"dashboard": {
|
||||||
"deleted_message_count": "Gelöschte Nachrichten",
|
"deleted_message_count": "Gelöschte Nachrichten",
|
||||||
"header": "Server dashboard",
|
"header": "Server dashboard",
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
"header": "Bot",
|
"header": "Bot",
|
||||||
"help_url": "Help URL",
|
"help_url": "Help URL",
|
||||||
"ping_urls": "Ping addresses",
|
"ping_urls": "Ping addresses",
|
||||||
"technicianIds": "Technician Ids",
|
"technician_ids": "Technician Ids",
|
||||||
"wait_for_restart": "Time to wait before restart",
|
"wait_for_restart": "Time to wait before restart",
|
||||||
"wait_for_shutdown": "Time to wait before shutdown"
|
"wait_for_shutdown": "Time to wait before shutdown"
|
||||||
},
|
},
|
||||||
@ -156,7 +156,7 @@
|
|||||||
"id": "Id",
|
"id": "Id",
|
||||||
"leftServer": "Left server",
|
"leftServer": "Left server",
|
||||||
"messageId": "Message Id",
|
"messageId": "Message Id",
|
||||||
"minXp": "Min. XP",
|
"min_xp": "Min. XP",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"operator": "Operator",
|
"operator": "Operator",
|
||||||
"permissions": "Permissions",
|
"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": {
|
"dashboard": {
|
||||||
"deleted_message_count": "Deleted messages",
|
"deleted_message_count": "Deleted messages",
|
||||||
"header": "Server dashboard",
|
"header": "Server dashboard",
|
||||||
@ -487,7 +509,7 @@
|
|||||||
"ontime": "Ontime",
|
"ontime": "Ontime",
|
||||||
"permission_denied": "Access denied!",
|
"permission_denied": "Access denied!",
|
||||||
"permission_denied_d": "You have to be moderator to see other profiles!",
|
"permission_denied_d": "You have to be moderator to see other profiles!",
|
||||||
"xp": "Xp"
|
"xp": "XP"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"user_settings": {
|
"user_settings": {
|
||||||
|
Loading…
Reference in New Issue
Block a user