From 02a3a0f5a9a013994f8a9917d615ff9d9c0443a6 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Mon, 7 Aug 2023 14:59:19 +0200 Subject: [PATCH] Added technician config to frontend #127_config_in_wi --- kdb-web/package-lock.json | 10 +- kdb-web/package.json | 5 +- .../models/config/technician-config.model.ts | 11 + .../src/app/models/graphql/mutations.model.ts | 26 ++ .../src/app/models/graphql/queries.model.ts | 17 ++ kdb-web/src/app/models/graphql/query.model.ts | 5 + .../src/app/models/graphql/result.model.ts | 7 + .../settings/settings.component.html | 267 ++++++++++-------- .../components/settings/settings.component.ts | 141 ++++++--- .../src/app/modules/shared/shared.module.ts | 6 +- kdb-web/src/assets/config.json | 4 +- kdb-web/src/styles.scss | 9 + 12 files changed, 351 insertions(+), 157 deletions(-) create mode 100644 kdb-web/src/app/models/config/technician-config.model.ts diff --git a/kdb-web/package-lock.json b/kdb-web/package-lock.json index 9c7b31b2..9281a434 100644 --- a/kdb-web/package-lock.json +++ b/kdb-web/package-lock.json @@ -1,12 +1,12 @@ { "name": "kdb-web", - "version": "1.0.dev251", + "version": "1.0.dev127_config_in_wi", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "kdb-web", - "version": "1.0.dev251", + "version": "1.0.dev127_config_in_wi", "dependencies": { "@angular/animations": "^15.1.4", "@angular/common": "^15.1.4", @@ -21,6 +21,7 @@ "@ngx-translate/core": "^14.0.0", "@ngx-translate/http-loader": "^7.0.0", "@types/socket.io-client": "^3.0.0", + "primeflex": "^3.3.1", "primeicons": "^6.0.1", "primeng": "^15.2.0", "rxjs": "~7.5.0", @@ -9302,6 +9303,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/primeflex": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/primeflex/-/primeflex-3.3.1.tgz", + "integrity": "sha512-zaOq3YvcOYytbAmKv3zYc+0VNS9Wg5d37dfxZnveKBFPr7vEIwfV5ydrpiouTft8MVW6qNjfkaQphHSnvgQbpQ==" + }, "node_modules/primeicons": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/primeicons/-/primeicons-6.0.1.tgz", diff --git a/kdb-web/package.json b/kdb-web/package.json index 70c9306f..a45b5813 100644 --- a/kdb-web/package.json +++ b/kdb-web/package.json @@ -1,6 +1,6 @@ { "name": "kdb-web", - "version": "1.0.dev268_achievements", + "version": "1.0.dev127_config_in_wi", "scripts": { "ng": "ng", "update-version": "ts-node-esm update-version.ts", @@ -30,6 +30,7 @@ "@ngx-translate/core": "^14.0.0", "@ngx-translate/http-loader": "^7.0.0", "@types/socket.io-client": "^3.0.0", + "primeflex": "^3.3.1", "primeicons": "^6.0.1", "primeng": "^15.2.0", "rxjs": "~7.5.0", @@ -51,4 +52,4 @@ "tslib": "^2.4.1", "typescript": "~4.9.5" } -} \ No newline at end of file +} diff --git a/kdb-web/src/app/models/config/technician-config.model.ts b/kdb-web/src/app/models/config/technician-config.model.ts new file mode 100644 index 00000000..02ade32c --- /dev/null +++ b/kdb-web/src/app/models/config/technician-config.model.ts @@ -0,0 +1,11 @@ +import { DataWithHistory } from "../data/data.model"; + +export interface TechnicianConfig extends DataWithHistory { + id?: number; + helpCommandReferenceUrl?: string; + waitForRestart?: number; + waitForShutdown?: number; + cacheMaxMessages?: number; + pingURLs?: string[]; + technicianIds?: string[]; +} diff --git a/kdb-web/src/app/models/graphql/mutations.model.ts b/kdb-web/src/app/models/graphql/mutations.model.ts index ac4448d0..2aa447cd 100644 --- a/kdb-web/src/app/models/graphql/mutations.model.ts +++ b/kdb-web/src/app/models/graphql/mutations.model.ts @@ -165,4 +165,30 @@ export class Mutations { } } `; + + + + static updateTechnicianConfig = ` + mutation updateTechnicianConfig($id: ID, $helpCommandReferenceUrl: String, $waitForRestart: Int, $waitForShutdown: Int, $cacheMaxMessages: Int, $pingURLs: [String], $technicianIds: [String]) { + technicianConfig { + updateTechnicianConfig(input: { + id: $id, + helpCommandReferenceUrl: $helpCommandReferenceUrl, + waitForRestart: $waitForRestart, + waitForShutdown: $waitForShutdown, + cacheMaxMessages: $cacheMaxMessages, + pingURLs: $pingURLs, + technicianIds: $technicianIds + }) { + id + helpCommandReferenceUrl + waitForRestart + waitForShutdown + cacheMaxMessages + pingURLs + technicianIds + } + } + } + `; } diff --git a/kdb-web/src/app/models/graphql/queries.model.ts b/kdb-web/src/app/models/graphql/queries.model.ts index 6dc78904..5311141e 100644 --- a/kdb-web/src/app/models/graphql/queries.model.ts +++ b/kdb-web/src/app/models/graphql/queries.model.ts @@ -1,5 +1,22 @@ 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}) { diff --git a/kdb-web/src/app/models/graphql/query.model.ts b/kdb-web/src/app/models/graphql/query.model.ts index 92c54ae7..1cc35083 100644 --- a/kdb-web/src/app/models/graphql/query.model.ts +++ b/kdb-web/src/app/models/graphql/query.model.ts @@ -4,12 +4,17 @@ import { AutoRole, AutoRoleRule } from "../data/auto_role.model"; 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"; export interface Query { serverCount: number; servers: Server[]; } +export interface TechnicianConfigQuery { + technicianConfig: TechnicianConfig; +} + export interface SingleDiscordQuery { guilds: Guild[]; } diff --git a/kdb-web/src/app/models/graphql/result.model.ts b/kdb-web/src/app/models/graphql/result.model.ts index d77c2cdc..37445578 100644 --- a/kdb-web/src/app/models/graphql/result.model.ts +++ b/kdb-web/src/app/models/graphql/result.model.ts @@ -3,6 +3,7 @@ import { AutoRole, AutoRoleRule } from "../data/auto_role.model"; 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"; export interface GraphQLResult { data: { @@ -47,6 +48,12 @@ export interface LevelMutationResult { }; } +export interface TechnicianConfigMutationResult { + technicianConfig: { + updateTechnicianConfig?: TechnicianConfig + }; +} + export interface AchievementMutationResult { achievement: { createAchievement?: Achievement diff --git a/kdb-web/src/app/modules/admin/settings/components/settings/settings.component.html b/kdb-web/src/app/modules/admin/settings/components/settings/settings.component.html index 3c78d1a6..a710fa79 100644 --- a/kdb-web/src/app/modules/admin/settings/components/settings/settings.component.html +++ b/kdb-web/src/app/modules/admin/settings/components/settings/settings.component.html @@ -1,125 +1,168 @@

- {{'admin.settings.header' | translate}} + {{'admin.settings.header' | translate}}

-
-

- {{'admin.settings.website.header' | translate}} -

+
+

+ {{'admin.settings.website.header' | translate}} +

+
+ +
+
+
+
{{'admin.settings.website.frontend_version' | translate}}:
+
{{data.webVersion}}
+
-
-
-
-
{{'admin.settings.website.frontend_version' | translate}}:
-
{{data.webVersion}}
-
-
- -
-
-
{{'admin.settings.website.backend_version' | translate}}:
-
{{data.apiVersion}}
-
-
- -
-
-
{{'admin.settings.website.config_path' | translate}}:
-
{{data.configPath}}
-
-
- -
-
-
{{'admin.settings.website.frontend_base_url' | translate}}:
-
{{data.webBaseURL}}
-
-
- -
-
-
{{'admin.settings.website.backend_base_url' | translate}}:
-
{{data.apiBaseURL}}
-
-
- -
- -
-
-
{{'admin.settings.website.token_expire_time' | translate}}:
-
{{data.tokenExpireTime}} {{'general.minutes' | translate}}
-
-
- -
-
-
{{'admin.settings.website.refresh_token_expire_time' | translate}}:
-
{{data.refreshTokenExpireTime}} {{'general.days' | translate}}
-
-
+
+
+
{{'admin.settings.website.backend_version' | translate}}:
+
{{data.apiVersion}}
+
+ +
+
+
{{'admin.settings.website.config_path' | translate}}:
+
{{data.configPath}}
+
+
+ +
+
+
{{'admin.settings.website.frontend_base_url' | translate}}:
+
{{data.webBaseURL}}
+
+
+ +
+
+
{{'admin.settings.website.backend_base_url' | translate}}:
+
{{data.apiBaseURL}}
+
+
+ +
+ +
+
+
{{'admin.settings.website.token_expire_time' | translate}}:
+
{{data.tokenExpireTime}} {{'general.minutes' | translate}}
+
+
+ +
+
+
{{'admin.settings.website.refresh_token_expire_time' | translate}}:
+
{{data.refreshTokenExpireTime}} {{'general.days' | translate}}
+
+
+
-
-

- {{'admin.settings.email.header' | translate}} -

+
+

+ {{'admin.settings.email.header' | translate}} +

+
+ +
+
+
+
{{'admin.settings.email.user' | translate}}:
+
{{data.mailUser}}
+
-
-
-
-
{{'admin.settings.email.user' | translate}}:
-
{{data.mailUser}}
-
-
- -
-
-
{{'admin.settings.email.host' | translate}}:
-
{{data.mailHost}}
-
-
- -
-
-
{{'admin.settings.email.port' | translate}}:
-
{{data.mailPort}}
-
-
- -
-
-
{{'admin.settings.email.transceiver' | translate}}:
-
{{data.mailTransceiver}}
-
-
- -
-
-
{{'admin.settings.email.email_address' | translate}}:
-
{{data.mailTransceiverAddress}}
-
-
- -
-
-
-
- -
-
- -
- -
-
-
+
+
+
{{'admin.settings.email.host' | translate}}:
+
{{data.mailHost}}
+
+ +
+
+
{{'admin.settings.email.port' | translate}}:
+
{{data.mailPort}}
+
+
+ +
+
+
{{'admin.settings.email.transceiver' | translate}}:
+
{{data.mailTransceiver}}
+
+
+ +
+
+
{{'admin.settings.email.email_address' | translate}}:
+
{{data.mailTransceiverAddress}}
+
+
+ +
+
+
+
+ +
+
+ +
+ +
+
+
+
+
+ +
+
+

+ {{'admin.settings.bot.header' | translate}} +

+
+ +
+
+
+
{{'admin.settings.bot.help_url' | translate}}:
+ +
+
+ +
+
+
{{'admin.settings.bot.wait_for_restart' | translate}}:
+ +
+
+ +
+
+
{{'admin.settings.bot.wait_for_shutdown' | translate}}:
+ +
+
+ +
+
+
{{'admin.settings.bot.cache_max_messages' | translate}}:
+ +
+
+ +
+ +
+
diff --git a/kdb-web/src/app/modules/admin/settings/components/settings/settings.component.ts b/kdb-web/src/app/modules/admin/settings/components/settings/settings.component.ts index 0f88f42e..d6030c26 100644 --- a/kdb-web/src/app/modules/admin/settings/components/settings/settings.component.ts +++ b/kdb-web/src/app/modules/admin/settings/components/settings/settings.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from "@angular/core"; -import { FormBuilder, FormGroup, Validators } from "@angular/forms"; +import { FormArray, FormBuilder, FormControl, 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"; @@ -9,66 +9,111 @@ 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 { forkJoin, throwError } from "rxjs"; +import { TechnicianConfig } from "../../../../../models/config/technician-config.model"; +import { TechnicianConfigQuery } from "../../../../../models/graphql/query.model"; +import { Queries } from "../../../../../models/graphql/queries.model"; +import { DataService } from "../../../../../services/data/data.service"; +import { LevelMutationResult, TechnicianConfigMutationResult } from "../../../../../models/graphql/result.model"; +import { Mutations } from "../../../../../models/graphql/mutations.model"; +import { AuthService } from "../../../../../services/auth/auth.service"; +import { ConfirmationDialogService } from "../../../../../services/confirmation-dialog/confirmation-dialog.service"; +import { SidebarService } from "../../../../../services/sidebar/sidebar.service"; +import { ActivatedRoute } from "@angular/router"; @Component({ - selector: 'app-settings', - templateUrl: './settings.component.html', - styleUrls: ['./settings.component.scss'] + selector: "app-settings", + templateUrl: "./settings.component.html", + styleUrls: ["./settings.component.scss"] }) 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: this.formBuilder.array([]) + }); data: SettingsDTO = { - webVersion: '', - apiVersion: '', - configPath: '', - webBaseURL: '', - apiBaseURL: '', + webVersion: "", + apiVersion: "", + configPath: "", + webBaseURL: "", + apiBaseURL: "", tokenExpireTime: 0, refreshTokenExpireTime: 0, - mailUser: '', + mailUser: "", mailPort: 0, - mailHost: '', - mailTransceiver: '', - mailTransceiverAddress: '', + mailHost: "", + mailTransceiver: "", + mailTransceiverAddress: "" + }; + + config: TechnicianConfig = { + helpCommandReferenceUrl: "", + waitForRestart: 0, + waitForShutdown: 0, + cacheMaxMessages: 0, + pingURLs: [], + technicianIds: [] }; constructor( + private dataService: DataService, private settingsService: SettingsService, private spinnerService: SpinnerService, private guiService: GuiService, private formBuilder: FormBuilder, private toastService: ToastService, - private translate: TranslateService - ) { } + private translate: TranslateService, + private authService: AuthService, + private spinner: SpinnerService, + ) { + } ngOnInit(): void { this.spinnerService.showSpinner(); this.initForms(); - this.guiService.getSettings() - .pipe(catchError(error => { + forkJoin([ + this.guiService.getSettings().pipe(catchError(error => { this.spinnerService.hideSpinner(); return throwError(() => error); - })) - .subscribe(settings => { - this.spinnerService.hideSpinner(); - this.data = settings; - this.data.webVersion = this.settingsService.getWebVersion()?.getVersionString() ?? '0.0.0'; - this.data.apiBaseURL = this.settingsService.getApiURL(); - if (!this.data.apiBaseURL.endsWith('/')) { - this.data.apiBaseURL += '/'; - } - }); + })), + this.dataService.query(Queries.technicianConfigQuery) + ]).subscribe(data => { + this.data = data[0]; + this.data.webVersion = this.settingsService.getWebVersion()?.getVersionString() ?? "0.0.0"; + this.data.apiBaseURL = this.settingsService.getApiURL(); + if (!this.data.apiBaseURL.endsWith("/")) { + this.data.apiBaseURL += "/"; + } + + this.config = data[1].technicianConfig; + this.initForms(); + this.spinnerService.hideSpinner(); + }); } initForms(): void { 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]], + pingUrls: this.formBuilder.array([]) + }); + const pingUrls = this.technicianConfigForm.controls["pingUrls"]; + for (const url of this.config.pingURLs ?? []) { + pingUrls.push(new FormControl(url, [Validators.required])); + } } testMail(): void { @@ -82,27 +127,27 @@ export class SettingsComponent implements OnInit { this.guiService.sendTestMail(mail) .pipe(catchError(error => { - let header = this.translate.instant('admin.settings.message.error'); - let message = this.translate.instant('admin.settings.message.could_not_send_mail'); + let header = this.translate.instant("admin.settings.message.error"); + let message = this.translate.instant("admin.settings.message.could_not_send_mail"); if (error.error !== null) { const err: ErrorDTO = error.error; if (err.errorCode === ServiceErrorCode.ConnectionFailed) { - header = this.translate.instant('admin.settings.message.connection_failed'); - message = this.translate.instant('admin.settings.message.connection_to_mail_failed'); + header = this.translate.instant("admin.settings.message.connection_failed"); + message = this.translate.instant("admin.settings.message.connection_to_mail_failed"); error.error = null; } if (err.errorCode === ServiceErrorCode.InvalidUser) { - header = this.translate.instant('admin.settings.message.connection_failed'); - message = this.translate.instant('admin.settings.message.mail_login_failed'); + header = this.translate.instant("admin.settings.message.connection_failed"); + message = this.translate.instant("admin.settings.message.mail_login_failed"); error.error = null; } if (err.errorCode === ServiceErrorCode.MailError) { - header = this.translate.instant('admin.settings.message.send_failed'); - message = this.translate.instant('admin.settings.message.test_mail_not_send'); + header = this.translate.instant("admin.settings.message.send_failed"); + message = this.translate.instant("admin.settings.message.test_mail_not_send"); error.error = null; } } @@ -113,9 +158,29 @@ export class SettingsComponent implements OnInit { })) .subscribe(res => { this.spinnerService.hideSpinner(); - this.toastService.success(this.translate.instant('admin.settings.message.success'), this.translate.instant('admin.settings.message.send_mail')); + this.toastService.success(this.translate.instant("admin.settings.message.success"), this.translate.instant("admin.settings.message.send_mail")); this.testMailForm.reset(); }); } + saveTechnicianConfig() { + this.spinner.showSpinner(); + this.dataService.mutation(Mutations.updateTechnicianConfig, { + helpCommandReferenceUrl: this.config.helpCommandReferenceUrl, + waitForRestart: this.config.waitForRestart, + waitForShutdown: this.config.waitForShutdown, + cacheMaxMessages: this.config.cacheMaxMessages, + 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(); + this.toastService.success(this.translate.instant("admin.settings.message.technician_config_create"), this.translate.instant("admin.settings.message.technician_config_create_d")); + }); + } + } diff --git a/kdb-web/src/app/modules/shared/shared.module.ts b/kdb-web/src/app/modules/shared/shared.module.ts index e2d14884..61a5db6c 100644 --- a/kdb-web/src/app/modules/shared/shared.module.ts +++ b/kdb-web/src/app/modules/shared/shared.module.ts @@ -24,6 +24,7 @@ import { InputNumberModule } from "primeng/inputnumber"; 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'; @NgModule({ @@ -56,6 +57,7 @@ import { HistoryBtnComponent } from './components/history-btn/history-btn.compon InputNumberModule, ImageModule, SidebarModule, + DataViewModule, ], exports: [ ButtonModule, @@ -82,7 +84,9 @@ import { HistoryBtnComponent } from './components/history-btn/history-btn.compon InputNumberModule, ImageModule, SidebarModule, - HistoryBtnComponent + HistoryBtnComponent, + DataViewModule, + DataViewLayoutOptions ] }) export class SharedModule { } diff --git a/kdb-web/src/assets/config.json b/kdb-web/src/assets/config.json index a2d9a6c2..9d35b928 100644 --- a/kdb-web/src/assets/config.json +++ b/kdb-web/src/assets/config.json @@ -5,7 +5,7 @@ "WebVersion": { "Major": "1", "Minor": "0", - "Micro": "dev268_achievements" + "Micro": "dev127_config_in_wi" }, "Themes": [ { @@ -25,4 +25,4 @@ "Name": "sh-edraft-dark-theme" } ] -} \ No newline at end of file +} diff --git a/kdb-web/src/styles.scss b/kdb-web/src/styles.scss index b9318b03..71be66ee 100644 --- a/kdb-web/src/styles.scss +++ b/kdb-web/src/styles.scss @@ -177,6 +177,14 @@ header { font-size: 18px; } + .content-data-value-row { + display: flex; + flex: 1; + flex-direction: column; + + font-size: 18px; + } + .content-divider { margin: 5px 0; } @@ -477,6 +485,7 @@ footer { .right { width: 50%; text-align: right; + .p-button-label { font-weight: unset !important; }