diff --git a/code/frontend/src/app/core/interceptors/error.interceptor.ts b/code/frontend/src/app/core/interceptors/error.interceptor.ts index 791d4cbf..c00b9cf7 100644 --- a/code/frontend/src/app/core/interceptors/error.interceptor.ts +++ b/code/frontend/src/app/core/interceptors/error.interceptor.ts @@ -14,8 +14,11 @@ export const errorInterceptor: HttpInterceptorFn = (req, next) => { if (error.error instanceof ErrorEvent) { // Client-side error message = error.error.message; + } else if (typeof error.error === 'string') { + // Server-side error with plain string body + message = error.error; } else { - // Server-side error + // Server-side error with JSON body message = error.error?.error ?? error.error?.message ?? error.message diff --git a/code/frontend/src/app/features/settings/malware-blocker/malware-blocker.component.html b/code/frontend/src/app/features/settings/malware-blocker/malware-blocker.component.html index 1465c74f..30e16518 100644 --- a/code/frontend/src/app/features/settings/malware-blocker/malware-blocker.component.html +++ b/code/frontend/src/app/features/settings/malware-blocker/malware-blocker.component.html @@ -70,7 +70,7 @@ @if (enabled()) { - + @for (name of arrNames; track name) {

{{ capitalize(name) }}

diff --git a/code/frontend/src/app/features/settings/malware-blocker/malware-blocker.component.ts b/code/frontend/src/app/features/settings/malware-blocker/malware-blocker.component.ts index b8eec44f..11f51aec 100644 --- a/code/frontend/src/app/features/settings/malware-blocker/malware-blocker.component.ts +++ b/code/frontend/src/app/features/settings/malware-blocker/malware-blocker.component.ts @@ -6,6 +6,7 @@ import { type SelectOption, } from '@ui'; import { MalwareBlockerApi } from '@core/api/malware-blocker.api'; +import { ApiError } from '@core/interceptors/error.interceptor'; import { ToastService } from '@core/services/toast.service'; import { MalwareBlockerConfig, BlocklistSettings, MalwareScheduleOptions } from '@shared/models/malware-blocker-config.model'; import { BlocklistType, ScheduleUnit } from '@shared/models/enums'; @@ -120,7 +121,18 @@ export class MalwareBlockerComponent implements OnInit, HasPendingChanges { return undefined; } + readonly noBlocklistError = computed(() => { + if (!this.enabled()) return undefined; + const blocklists = this.arrBlocklists(); + const hasAnyEnabled = ARR_NAMES.some(name => blocklists[name]?.enabled); + if (!hasAnyEnabled) { + return 'At least one blocklist must be configured'; + } + return undefined; + }); + readonly hasErrors = computed(() => { + if (this.noBlocklistError()) return true; if (this.scheduleEveryError()) return true; if (this.cronError()) return true; if (this.chipInputs().some(c => c.hasUncommittedInput())) return true; @@ -225,8 +237,10 @@ export class MalwareBlockerComponent implements OnInit, HasPendingChanges { setTimeout(() => this.saved.set(false), 1500); this.savedSnapshot.set(this.buildSnapshot()); }, - error: () => { - this.toast.error('Failed to save malware blocker settings'); + error: (err: ApiError) => { + this.toast.error(err.statusCode === 400 + ? err.message + : 'Failed to save malware blocker settings'); this.saving.set(false); }, });