diff --git a/apps/red-ui/src/app/app.module.ts b/apps/red-ui/src/app/app.module.ts index 07c42e3e1..40bb58e12 100644 --- a/apps/red-ui/src/app/app.module.ts +++ b/apps/red-ui/src/app/app.module.ts @@ -51,6 +51,7 @@ import { MAT_TOOLTIP_DEFAULT_OPTIONS } from '@angular/material/tooltip'; import { LoggerModule, NgxLoggerLevel, TOKEN_LOGGER_CONFIG, TOKEN_LOGGER_RULES_SERVICE } from 'ngx-logger'; import { LoggerRulesService } from '@services/logger-rules.service'; import { ILoggerConfig } from '@red/domain'; +import { SystemPreferencesService } from '@services/system-preferences.service'; export function httpLoaderFactory(httpClient: HttpClient, configService: ConfigService): PruningTranslationLoader { return new PruningTranslationLoader(httpClient, '/assets/i18n/', `.json?version=${configService.values.FRONTEND_APP_VERSION}`); @@ -167,6 +168,7 @@ const components = [AppComponent, AuthErrorComponent, NotificationsComponent, Sp KeycloakService, Title, ConfigService, + SystemPreferencesService, FeaturesService, GeneralSettingsService, LanguageService, diff --git a/apps/red-ui/src/app/modules/admin/admin.module.ts b/apps/red-ui/src/app/modules/admin/admin.module.ts index de6e99167..89a4a2435 100644 --- a/apps/red-ui/src/app/modules/admin/admin.module.ts +++ b/apps/red-ui/src/app/modules/admin/admin.module.ts @@ -43,6 +43,7 @@ import { ConfirmDeleteDossierStateDialogComponent } from './dialogs/confirm-dele import { BaseEntityScreenComponent } from './base-entity-screen/base-entity-screen.component'; import { CloneDossierTemplateDialogComponent } from './dialogs/clone-dossier-template-dialog/clone-dossier-template-dialog.component'; import { AdminSideNavComponent } from './admin-side-nav/admin-side-nav.component'; +import { SystemPreferencesFormComponent } from './screens/general-config/system-preferences-form/system-preferences-form.component'; const dialogs = [ AddEditDossierTemplateDialogComponent, @@ -84,6 +85,7 @@ const components = [ BaseEntityScreenComponent, GeneralConfigFormComponent, SmtpFormComponent, + SystemPreferencesFormComponent, ...dialogs, ...screens, diff --git a/apps/red-ui/src/app/modules/admin/screens/general-config/general-config-form/general-config-form.component.ts b/apps/red-ui/src/app/modules/admin/screens/general-config/general-config-form/general-config-form.component.ts index 70b032385..10f31632e 100644 --- a/apps/red-ui/src/app/modules/admin/screens/general-config/general-config-form/general-config-form.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/general-config/general-config-form/general-config-form.component.ts @@ -24,20 +24,6 @@ export class GeneralConfigFormComponent extends BaseFormComponent implements OnI this.form = this._getForm(); } - get generalConfigurationChanged(): boolean { - if (!this._initialConfiguration) { - return true; - } - - for (const key of Object.keys(this.form.getRawValue())) { - if (this._initialConfiguration[key] !== this.form.get(key).value) { - return true; - } - } - - return false; - } - async ngOnInit(): Promise { await this._loadData(); } diff --git a/apps/red-ui/src/app/modules/admin/screens/general-config/general-config-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/general-config/general-config-screen.component.html index af303ea03..e15bc83d6 100644 --- a/apps/red-ui/src/app/modules/admin/screens/general-config/general-config-screen.component.html +++ b/apps/red-ui/src/app/modules/admin/screens/general-config/general-config-screen.component.html @@ -24,6 +24,9 @@
+
+ +
diff --git a/apps/red-ui/src/app/modules/admin/screens/general-config/general-config-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/general-config/general-config-screen.component.ts index 94b036eca..020d1b125 100644 --- a/apps/red-ui/src/app/modules/admin/screens/general-config/general-config-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/general-config/general-config-screen.component.ts @@ -3,6 +3,7 @@ import { UserService } from '@services/user.service'; import { GeneralConfigFormComponent } from './general-config-form/general-config-form.component'; import { SmtpFormComponent } from './smtp-form/smtp-form.component'; import { BaseFormComponent } from '@iqser/common-ui'; +import { SystemPreferencesFormComponent } from './system-preferences-form/system-preferences-form.component'; @Component({ selector: 'redaction-general-config-screen', @@ -13,6 +14,7 @@ export class GeneralConfigScreenComponent extends BaseFormComponent implements A readonly currentUser = this._userService.currentUser; @ViewChild(GeneralConfigFormComponent) generalConfigFormComponent: GeneralConfigFormComponent; + @ViewChild(SystemPreferencesFormComponent) systemPreferencesFormComponent: SystemPreferencesFormComponent; @ViewChild(SmtpFormComponent) smtpFormComponent: SmtpFormComponent; children: BaseFormComponent[]; @@ -20,10 +22,6 @@ export class GeneralConfigScreenComponent extends BaseFormComponent implements A super(); } - ngAfterViewInit() { - this.children = [this.generalConfigFormComponent, this.smtpFormComponent]; - } - get changed(): boolean { for (const child of this.children) { if (child.changed) { @@ -42,6 +40,10 @@ export class GeneralConfigScreenComponent extends BaseFormComponent implements A return true; } + ngAfterViewInit() { + this.children = [this.generalConfigFormComponent, this.systemPreferencesFormComponent, this.smtpFormComponent]; + } + async save(): Promise { for (const child of this.children) { if (child.changed) { diff --git a/apps/red-ui/src/app/modules/admin/screens/general-config/system-preferences-form/system-preferences-form.component.html b/apps/red-ui/src/app/modules/admin/screens/general-config/system-preferences-form/system-preferences-form.component.html new file mode 100644 index 000000000..892cb080c --- /dev/null +++ b/apps/red-ui/src/app/modules/admin/screens/general-config/system-preferences-form/system-preferences-form.component.html @@ -0,0 +1,18 @@ +
+
+
+
+
+
+
+ + +
+
+
+
+ +
+
diff --git a/apps/red-ui/src/app/modules/admin/screens/general-config/system-preferences-form/system-preferences-form.component.scss b/apps/red-ui/src/app/modules/admin/screens/general-config/system-preferences-form/system-preferences-form.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/apps/red-ui/src/app/modules/admin/screens/general-config/system-preferences-form/system-preferences-form.component.ts b/apps/red-ui/src/app/modules/admin/screens/general-config/system-preferences-form/system-preferences-form.component.ts new file mode 100644 index 000000000..4defe8ca9 --- /dev/null +++ b/apps/red-ui/src/app/modules/admin/screens/general-config/system-preferences-form/system-preferences-form.component.ts @@ -0,0 +1,51 @@ +import { Component } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { SystemPreferences } from '@red/domain'; +import { BaseFormComponent, KeysOf, LoadingService } from '@iqser/common-ui'; +import { firstValueFrom } from 'rxjs'; +import { SystemPreferencesService } from '@services/system-preferences.service'; +import { systemPreferencesTranslations } from '@translations/system-preferences-translations'; + +@Component({ + selector: 'redaction-system-preferences-form', + templateUrl: './system-preferences-form.component.html', + styleUrls: ['./system-preferences-form.component.scss'], +}) +export class SystemPreferencesFormComponent extends BaseFormComponent { + readonly translations = systemPreferencesTranslations; + readonly keys: KeysOf[] = [ + 'softDeleteCleanupTime', + 'downloadCleanupDownloadFilesHours', + 'downloadCleanupNotDownloadFilesHours', + ]; + private _initialConfiguration: SystemPreferences; + + constructor( + private readonly _loadingService: LoadingService, + private readonly _systemPreferencesService: SystemPreferencesService, + private readonly _formBuilder: FormBuilder, + ) { + super(); + this.form = this._getForm(); + this._loadData(); + } + + async save(): Promise { + this._loadingService.start(); + await firstValueFrom(this._systemPreferencesService.update(this.form.getRawValue())); + this._loadData(); + this._loadingService.stop(); + } + + private _getForm(): FormGroup { + const controlsConfig = {}; + this.keys.forEach(key => (controlsConfig[key] = [this._systemPreferencesService.values[key], Validators.required])); + return this._formBuilder.group(controlsConfig); + } + + private _loadData() { + this._initialConfiguration = this._systemPreferencesService.values; + this.form.patchValue(this._initialConfiguration, { emitEvent: false }); + this.initialFormValue = this.form.getRawValue(); + } +} diff --git a/apps/red-ui/src/app/services/config.service.ts b/apps/red-ui/src/app/services/config.service.ts index 3ba92c7bd..ce80e5511 100644 --- a/apps/red-ui/src/app/services/config.service.ts +++ b/apps/red-ui/src/app/services/config.service.ts @@ -28,15 +28,6 @@ export class ConfigService { return this._values; } - loadAppConfig(): Observable { - return this._httpClient.get('/app-config').pipe( - tap(config => { - console.log('[REDACTION] Loaded config: ', config); - this._values = { ...this._values, ...config }; - }), - ); - } - loadLocalConfig(): Observable { return this._httpClient.get('/assets/config/config.json').pipe( tap(config => { diff --git a/apps/red-ui/src/app/services/entity-services/trash.service.ts b/apps/red-ui/src/app/services/entity-services/trash.service.ts index d888d42bf..8fbf43c5f 100644 --- a/apps/red-ui/src/app/services/entity-services/trash.service.ts +++ b/apps/red-ui/src/app/services/entity-services/trash.service.ts @@ -4,13 +4,13 @@ import { Dossier, File, IDossier, IFile, TrashDossier, TrashFile, TrashItem } fr import { catchError, switchMap, take, tap } from 'rxjs/operators'; import { forkJoin, map, Observable, of } from 'rxjs'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -import { ConfigService } from '../config.service'; import { PermissionsService } from '../permissions.service'; import { ActiveDossiersService } from '../dossiers/active-dossiers.service'; import { UserService } from '../user.service'; import { flatMap } from 'lodash-es'; import { DossierStatsService } from '../dossiers/dossier-stats.service'; import { FilesService } from '../files/files.service'; +import { SystemPreferencesService } from '@services/system-preferences.service'; @Injectable({ providedIn: 'root', @@ -19,7 +19,7 @@ export class TrashService extends EntitiesService { constructor( protected readonly _injector: Injector, private readonly _toaster: Toaster, - private readonly _configService: ConfigService, + private readonly _systemPreferencesService: SystemPreferencesService, private readonly _permissionsService: PermissionsService, private readonly _activeDossiersService: ActiveDossiersService, private readonly _userService: UserService, @@ -64,7 +64,7 @@ export class TrashService extends EntitiesService { dossier => new TrashDossier( dossier, - this._configService.values.softDeleteCleanupTime, + this._systemPreferencesService.values.softDeleteCleanupTime, this._permissionsService.canRestoreDossier(dossier), this._permissionsService.canHardDeleteDossier(dossier), ), @@ -82,7 +82,7 @@ export class TrashService extends EntitiesService { return new TrashFile( file, dossier.dossierTemplateId, - this._configService.values.softDeleteCleanupTime, + this._systemPreferencesService.values.softDeleteCleanupTime, this._permissionsService.canRestoreFile(file, dossier), this._permissionsService.canHardDeleteFile(file, dossier), ); diff --git a/apps/red-ui/src/app/services/system-preferences.service.ts b/apps/red-ui/src/app/services/system-preferences.service.ts new file mode 100644 index 000000000..b48c18ca8 --- /dev/null +++ b/apps/red-ui/src/app/services/system-preferences.service.ts @@ -0,0 +1,29 @@ +import { Injectable, Injector } from '@angular/core'; +import { GenericService } from '@iqser/common-ui'; +import { SystemPreferences } from '@red/domain'; +import { Observable, switchMap } from 'rxjs'; +import { tap } from 'rxjs/operators'; + +@Injectable({ + providedIn: 'root', +}) +export class SystemPreferencesService extends GenericService { + values: SystemPreferences; + + constructor(protected readonly _injector: Injector) { + super(_injector, 'app-config'); + } + + loadPreferences(): Observable { + return this.get().pipe( + tap((config: SystemPreferences) => { + console.log('[REDACTION] Loaded config: ', config); + this.values = config; + }), + ); + } + + update(value: SystemPreferences): Observable { + return this._post(value).pipe(switchMap(() => this.loadPreferences())); + } +} diff --git a/apps/red-ui/src/app/translations/system-preferences-translations.ts b/apps/red-ui/src/app/translations/system-preferences-translations.ts new file mode 100644 index 000000000..d2aaf0f93 --- /dev/null +++ b/apps/red-ui/src/app/translations/system-preferences-translations.ts @@ -0,0 +1,20 @@ +import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { SystemPreferences } from '@red/domain'; +import { KeysOf } from '@iqser/common-ui'; + +export const systemPreferencesTranslations: Record<'label' | 'placeholder', Record, string>> = { + label: { + softDeleteCleanupTime: _('general-config-screen.system-preferences.labels.soft-delete-cleanup-time'), + downloadCleanupDownloadFilesHours: _('general-config-screen.system-preferences.labels.download-cleanup-download-files-hours'), + downloadCleanupNotDownloadFilesHours: _( + 'general-config-screen.system-preferences.labels.download-cleanup-not-download-files-hours', + ), + }, + placeholder: { + softDeleteCleanupTime: _('general-config-screen.system-preferences.placeholders.soft-delete-cleanup-time'), + downloadCleanupDownloadFilesHours: _('general-config-screen.system-preferences.placeholders.download-cleanup-download-files-hours'), + downloadCleanupNotDownloadFilesHours: _( + 'general-config-screen.system-preferences.placeholders.download-cleanup-not-download-files-hours', + ), + }, +} as const; diff --git a/apps/red-ui/src/app/utils/configuration.initializer.ts b/apps/red-ui/src/app/utils/configuration.initializer.ts index c73f33ce9..e60a1cdf6 100644 --- a/apps/red-ui/src/app/utils/configuration.initializer.ts +++ b/apps/red-ui/src/app/utils/configuration.initializer.ts @@ -8,6 +8,7 @@ import { LanguageService } from '@i18n/language.service'; import { UserPreferenceService } from '@services/user-preference.service'; import { UserService } from '@services/user.service'; import { FeaturesService } from '@services/features.service'; +import { SystemPreferencesService } from '@services/system-preferences.service'; function lastDossierTemplateRedirect(baseHref: string, userPreferenceService: UserPreferenceService) { const url = window.location.href.split('/').filter(s => s.length > 0); @@ -22,6 +23,7 @@ export function configurationInitializer( keycloakService: KeycloakService, title: Title, configService: ConfigService, + systemPreferencesService: SystemPreferencesService, featuresService: FeaturesService, generalSettingsService: GeneralSettingsService, languageService: LanguageService, @@ -39,7 +41,7 @@ export function configurationInitializer( switchMap(user => (!user.hasAnyREDRoles ? throwError('Not user has no red roles') : of({}))), mergeMap(() => generalSettingsService.getGeneralConfigurations()), tap(configuration => configService.updateDisplayName(configuration.displayName)), - switchMap(() => configService.loadAppConfig()), + switchMap(() => systemPreferencesService.loadPreferences()), switchMap(() => userPreferenceService.reload()), catchError(e => { console.log('[Redaction] Initialization error:', e); diff --git a/apps/red-ui/src/assets/i18n/de.json b/apps/red-ui/src/assets/i18n/de.json index a067e33ca..b7fe82feb 100644 --- a/apps/red-ui/src/assets/i18n/de.json +++ b/apps/red-ui/src/assets/i18n/de.json @@ -1444,6 +1444,19 @@ "title": "Allgemeine Einstellungen" }, "subtitle": "SMTP (Simple Mail Transfer Protocol) ermöglicht es Ihnen, Ihre E-Mails über die angegebenen Servereinstellungen zu versenden.", + "system-preferences": { + "labels": { + "download-cleanup-download-files-hours": "", + "download-cleanup-not-download-files-hours": "", + "soft-delete-cleanup-time": "" + }, + "placeholders": { + "download-cleanup-download-files-hours": "", + "download-cleanup-not-download-files-hours": "", + "soft-delete-cleanup-time": "" + }, + "title": "" + }, "test": { "error": "Die Test-E-Mail konnte nicht gesendet werden! Bitte überprüfen Sie die E-Mail-Adresse.", "success": "Die Test-E-Mail wurde erfolgreich versendet!" diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index 1895f5b49..d83700599 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -1444,6 +1444,19 @@ "title": "General Configurations" }, "subtitle": "SMTP (Simple Mail Transfer Protocol) enables you to send your emails through the specified server settings.", + "system-preferences": { + "labels": { + "download-cleanup-download-files-hours": "Cleanup time for downloaded files (hours)", + "download-cleanup-not-download-files-hours": "Cleanup time for not downloaded files (hours)", + "soft-delete-cleanup-time": "Soft delete cleanup time (hours)" + }, + "placeholders": { + "download-cleanup-download-files-hours": "(hours)", + "download-cleanup-not-download-files-hours": "(hours)", + "soft-delete-cleanup-time": "(hours)" + }, + "title": "System Preferences" + }, "test": { "error": "Test email could not be sent! Please revise the email address.", "success": "Test email was sent successfully!" diff --git a/libs/red-domain/src/lib/shared/app-config.ts b/libs/red-domain/src/lib/shared/app-config.ts index 3c13e3db7..32b81a77d 100644 --- a/libs/red-domain/src/lib/shared/app-config.ts +++ b/libs/red-domain/src/lib/shared/app-config.ts @@ -20,7 +20,4 @@ export interface AppConfig { RECENT_PERIOD_IN_HOURS: number; SELECTION_MODE: string; MANUAL_BASE_URL: string; - softDeleteCleanupTime?: number; - downloadCleanupDownloadFilesHours?: number; - downloadCleanupNotDownloadFilesHours?: number; } diff --git a/libs/red-domain/src/lib/shared/index.ts b/libs/red-domain/src/lib/shared/index.ts index 670578d71..f66679007 100644 --- a/libs/red-domain/src/lib/shared/index.ts +++ b/libs/red-domain/src/lib/shared/index.ts @@ -12,3 +12,4 @@ export * from './logger-config'; export * from './admin-side-nav-types'; export * from './charts'; export * from './app-config'; +export * from './system-preferences'; diff --git a/libs/red-domain/src/lib/shared/system-preferences.ts b/libs/red-domain/src/lib/shared/system-preferences.ts new file mode 100644 index 000000000..a0ff4c902 --- /dev/null +++ b/libs/red-domain/src/lib/shared/system-preferences.ts @@ -0,0 +1,5 @@ +export interface SystemPreferences { + softDeleteCleanupTime: number; + downloadCleanupDownloadFilesHours: number; + downloadCleanupNotDownloadFilesHours: number; +}