From 02b0d96012b08792b9a8d2fea01c19d840ed7412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Mon, 18 Jul 2022 16:31:24 +0300 Subject: [PATCH] RED-4634, RED-3800: Refactor watermarks --- .../dossier-watermark-selector.component.html | 37 ------ .../dossier-watermark-selector.component.ts | 82 ------------- .../option-watermark.model.ts | 14 --- .../src/app/guards/watermark-exists.guard.ts | 21 ++++ .../app/modules/admin/admin-routing.module.ts | 36 +----- .../src/app/modules/admin/admin.module.ts | 4 - .../base-watermark-screen.component.html | 27 ----- .../base-watermark-screen.component.ts | 53 --------- .../watermark-screen.component.html | 2 +- .../watermark-screen.component.ts | 108 ++++++++---------- .../screens/watermark/watermark.module.ts | 35 +++++- .../watermarks-listing-screen.component.html | 71 ++++++++++++ .../watermarks-listing-screen.component.ts | 44 ++----- .../watermarks-listing-screen.component.html | 105 ----------------- .../file-preview/services/stamp.service.ts | 13 +-- ...it-dossier-download-package.component.html | 16 ++- ...edit-dossier-download-package.component.ts | 12 +- .../watermark-selector.component.html | 19 +++ .../watermark-selector.component.scss} | 0 .../watermark-selector.component.ts | 81 +++++++++++++ .../add-dossier-dialog.component.html | 17 ++- .../add-dossier-dialog.component.ts | 13 +-- .../src/app/modules/shared/shared.module.ts | 20 ++-- .../dossier-templates.service.ts | 3 + .../entity-services/watermark.service.ts | 49 +++++--- .../entity-services/watermarks-map.service.ts | 8 ++ libs/common-ui | 2 +- .../src/lib/dossiers/dossier.model.ts | 4 +- .../src/lib/dossiers/dossier.request.ts | 4 +- libs/red-domain/src/lib/dossiers/dossier.ts | 4 +- .../src/lib/watermarks/watermark.model.ts | 13 ++- 31 files changed, 398 insertions(+), 519 deletions(-) delete mode 100644 apps/red-ui/src/app/components/dossier-watermark-selector/dossier-watermark-selector.component.html delete mode 100644 apps/red-ui/src/app/components/dossier-watermark-selector/dossier-watermark-selector.component.ts delete mode 100644 apps/red-ui/src/app/components/dossier-watermark-selector/option-watermark.model.ts create mode 100644 apps/red-ui/src/app/guards/watermark-exists.guard.ts delete mode 100644 apps/red-ui/src/app/modules/admin/base-watermark-screen/base-watermark-screen.component.html delete mode 100644 apps/red-ui/src/app/modules/admin/base-watermark-screen/base-watermark-screen.component.ts create mode 100644 apps/red-ui/src/app/modules/admin/screens/watermark/watermarks-listing/watermarks-listing-screen.component.html rename apps/red-ui/src/app/modules/admin/screens/{ => watermark}/watermarks-listing/watermarks-listing-screen.component.ts (72%) delete mode 100644 apps/red-ui/src/app/modules/admin/screens/watermarks-listing/watermarks-listing-screen.component.html create mode 100644 apps/red-ui/src/app/modules/shared/components/dossier-watermark-selector/watermark-selector.component.html rename apps/red-ui/src/app/{components/dossier-watermark-selector/dossier-watermark-selector.component.scss => modules/shared/components/dossier-watermark-selector/watermark-selector.component.scss} (100%) create mode 100644 apps/red-ui/src/app/modules/shared/components/dossier-watermark-selector/watermark-selector.component.ts create mode 100644 apps/red-ui/src/app/services/entity-services/watermarks-map.service.ts diff --git a/apps/red-ui/src/app/components/dossier-watermark-selector/dossier-watermark-selector.component.html b/apps/red-ui/src/app/components/dossier-watermark-selector/dossier-watermark-selector.component.html deleted file mode 100644 index de078ba1e..000000000 --- a/apps/red-ui/src/app/components/dossier-watermark-selector/dossier-watermark-selector.component.html +++ /dev/null @@ -1,37 +0,0 @@ -
-
- - {{ 'dossier-watermark-selector.watermark' | translate }} - - - - - {{ selectedWatermark(watermarkId, watermarks).name }} - - - - {{ watermark.name }} - - -
- -
- - {{ 'dossier-watermark-selector.preview' | translate }} - - - - - {{ selectedWatermark(previewWatermarkId, watermarks).name }} - - - - {{ watermark.name }} - - -
-
diff --git a/apps/red-ui/src/app/components/dossier-watermark-selector/dossier-watermark-selector.component.ts b/apps/red-ui/src/app/components/dossier-watermark-selector/dossier-watermark-selector.component.ts deleted file mode 100644 index 91d837f6b..000000000 --- a/apps/red-ui/src/app/components/dossier-watermark-selector/dossier-watermark-selector.component.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { Observable } from 'rxjs'; -import { IWatermark } from '@red/domain'; -import { WatermarkService } from '@services/entity-services/watermark.service'; -import { mapEach, Required } from '@iqser/common-ui'; -import { OptionWatermark } from '@components/dossier-watermark-selector/option-watermark.model'; -import { map, tap } from 'rxjs/operators'; - -const DocumentTypes = { - REDACTED: 'REDACTED', - PREVIEW: 'PREVIEW', -} as const; -type DocumentType = keyof typeof DocumentTypes; - -export interface UpdateWatermarkIdsEvent { - watermarkId: string | null; - previewWatermarkId: string | null; -} - -@Component({ - selector: 'redaction-dossier-watermark-selector', - templateUrl: './dossier-watermark-selector.component.html', - styleUrls: ['./dossier-watermark-selector.component.scss'], -}) -export class DossierWatermarkSelectorComponent implements OnInit { - @Input() @Required() dossierTemplateId!: string; - @Input() watermarkId: string | null; - @Input() previewWatermarkId: string | null; - @Output() readonly idsUpdate = new EventEmitter(); - watermarks$: Observable; - readonly documentTypes = DocumentTypes; - #oldWatermarkId: string | null; - #oldPreviewWatermarkId: string | null; - - constructor(private readonly _watermarkService: WatermarkService) {} - - ngOnInit(): void { - this.watermarks$ = this._watermarkService.getWatermarks(this.dossierTemplateId).pipe( - map((watermarks: IWatermark[]) => watermarks.sort(this.sortByStatusFn)), - mapEach((watermark: IWatermark) => new OptionWatermark(watermark)), - tap((watermarks: OptionWatermark[]) => (this.#oldWatermarkId = watermarks[0].id)), - tap((watermarks: OptionWatermark[]) => (this.#oldPreviewWatermarkId = watermarks[0].id)), - ); - } - - sortByStatusFn = (a, b) => { - if (a.enabled === b.enabled) { - return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1; - } - return a.enabled ? -1 : 1; - }; - - toggleWatermarkSelection(checked: boolean, documentType: DocumentType): void { - if (checked) { - if (documentType === DocumentTypes.REDACTED) { - this.watermarkId = this.#oldWatermarkId; - } else { - this.previewWatermarkId = this.#oldPreviewWatermarkId; - } - } else { - if (documentType === DocumentTypes.REDACTED) { - this.#oldWatermarkId = this.watermarkId; - this.watermarkId = null; - } else { - this.#oldPreviewWatermarkId = this.previewWatermarkId; - this.previewWatermarkId = null; - } - } - this.emitNewValues(); - } - - emitNewValues(): void { - this.idsUpdate.emit({ - watermarkId: this.watermarkId, - previewWatermarkId: this.previewWatermarkId, - }); - } - - selectedWatermark(id: string, watermarks: OptionWatermark[]): OptionWatermark { - return watermarks.find(watermark => watermark.id === id); - } -} diff --git a/apps/red-ui/src/app/components/dossier-watermark-selector/option-watermark.model.ts b/apps/red-ui/src/app/components/dossier-watermark-selector/option-watermark.model.ts deleted file mode 100644 index 98656a261..000000000 --- a/apps/red-ui/src/app/components/dossier-watermark-selector/option-watermark.model.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { IWatermark } from '@red/domain'; -import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; - -export class OptionWatermark { - id!: string; - name!: string; - enabled!: boolean; - - constructor(watermark: IWatermark) { - this.id = watermark.id; - this.name = watermark.enabled ? watermark.name : `${_('disabled')} - ${watermark.name}`; - this.enabled = watermark.enabled; - } -} diff --git a/apps/red-ui/src/app/guards/watermark-exists.guard.ts b/apps/red-ui/src/app/guards/watermark-exists.guard.ts new file mode 100644 index 000000000..0fab7ef6c --- /dev/null +++ b/apps/red-ui/src/app/guards/watermark-exists.guard.ts @@ -0,0 +1,21 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router'; +import { WatermarksMapService } from '@services/entity-services/watermarks-map.service'; +import { DOSSIER_TEMPLATE_ID, WATERMARK_ID } from '@red/domain'; + +@Injectable({ providedIn: 'root' }) +export class WatermarkExistsGuard implements CanActivate { + constructor(private readonly _watermarksMapService: WatermarksMapService, private readonly _router: Router) {} + + async canActivate(route: ActivatedRouteSnapshot): Promise { + const dossierTemplateId = route.parent.paramMap.get(DOSSIER_TEMPLATE_ID); + const watermarkId = route.paramMap.get(WATERMARK_ID); + + if (this._watermarksMapService.get(dossierTemplateId, watermarkId)) { + return true; + } + + await this._router.navigate(['main', 'admin', 'dossier-templates', dossierTemplateId, 'watermarks']); + return false; + } +} diff --git a/apps/red-ui/src/app/modules/admin/admin-routing.module.ts b/apps/red-ui/src/app/modules/admin/admin-routing.module.ts index 6004dd990..88fe96921 100644 --- a/apps/red-ui/src/app/modules/admin/admin-routing.module.ts +++ b/apps/red-ui/src/app/modules/admin/admin-routing.module.ts @@ -15,14 +15,12 @@ import { GeneralConfigScreenComponent } from './screens/general-config/general-c import { BaseAdminScreenComponent } from './base-admin-screen/base-admin-screen.component'; import { BaseDossierTemplateScreenComponent } from './base-dossier-templates-screen/base-dossier-template-screen.component'; import { DossierTemplatesGuard } from '@guards/dossier-templates.guard'; -import { DOSSIER_TEMPLATE_ID, ENTITY_TYPE, WATERMARK_ID } from '@red/domain'; +import { DOSSIER_TEMPLATE_ID, ENTITY_TYPE } from '@red/domain'; import { DossierTemplateExistsGuard } from '@guards/dossier-template-exists.guard'; import { EntityExistsGuard } from '@guards/entity-exists-guard.service'; import { DossierStatesListingScreenComponent } from './screens/dossier-states-listing/dossier-states-listing-screen.component'; import { BaseEntityScreenComponent } from './base-entity-screen/base-entity-screen.component'; -import { PermissionsGuard } from '../../guards/permissions-guard'; -import { WatermarksListingScreenComponent } from './screens/watermarks-listing/watermarks-listing-screen.component'; -import { BaseWatermarkScreenComponent } from './base-watermark-screen/base-watermark-screen.component'; +import { PermissionsGuard } from '@guards/permissions-guard'; const dossierTemplateIdRoutes: Routes = [ { @@ -72,34 +70,8 @@ const dossierTemplateIdRoutes: Routes = [ }, { path: 'watermarks', - children: [ - { - path: '', - component: WatermarksListingScreenComponent, - canActivate: [CompositeRouteGuard], - data: { - routeGuards: [AuthGuard, RedRoleGuard], - }, - }, - { - path: 'create', - component: BaseWatermarkScreenComponent, - canActivate: [CompositeRouteGuard], - loadChildren: () => import('./screens/watermark/watermark.module').then(m => m.WatermarkModule), - data: { - routeGuards: [AuthGuard, RedRoleGuard], - }, - }, - { - path: `:${WATERMARK_ID}`, - component: BaseWatermarkScreenComponent, - canActivate: [CompositeRouteGuard], - loadChildren: () => import('./screens/watermark/watermark.module').then(m => m.WatermarkModule), - data: { - routeGuards: [AuthGuard, RedRoleGuard], - }, - }, - ], + component: BaseDossierTemplateScreenComponent, + loadChildren: () => import('./screens/watermark/watermark.module').then(m => m.WatermarkModule), }, { path: 'reports', 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 89bbcaa60..ec6c82e40 100644 --- a/apps/red-ui/src/app/modules/admin/admin.module.ts +++ b/apps/red-ui/src/app/modules/admin/admin.module.ts @@ -45,8 +45,6 @@ import { SystemPreferencesFormComponent } from './screens/general-config/system- import { ConfigureCertificateDialogComponent } from './dialogs/configure-digital-signature-dialog/configure-certificate-dialog.component'; import { PkcsSignatureConfigurationComponent } from './dialogs/configure-digital-signature-dialog/form/pkcs-signature-configuration/pkcs-signature-configuration.component'; import { KmsSignatureConfigurationComponent } from './dialogs/configure-digital-signature-dialog/form/kms-signature-configuration/kms-signature-configuration.component'; -import { WatermarksListingScreenComponent } from './screens/watermarks-listing/watermarks-listing-screen.component'; -import { BaseWatermarkScreenComponent } from './base-watermark-screen/base-watermark-screen.component'; const dialogs = [ AddEditCloneDossierTemplateDialogComponent, @@ -74,7 +72,6 @@ const screens = [ GeneralConfigScreenComponent, DossierAttributesListingScreenComponent, DossierStatesListingScreenComponent, - WatermarksListingScreenComponent, ]; const components = [ @@ -87,7 +84,6 @@ const components = [ BaseAdminScreenComponent, BaseDossierTemplateScreenComponent, BaseEntityScreenComponent, - BaseWatermarkScreenComponent, GeneralConfigFormComponent, SmtpFormComponent, SystemPreferencesFormComponent, diff --git a/apps/red-ui/src/app/modules/admin/base-watermark-screen/base-watermark-screen.component.html b/apps/red-ui/src/app/modules/admin/base-watermark-screen/base-watermark-screen.component.html deleted file mode 100644 index ebc6f12c6..000000000 --- a/apps/red-ui/src/app/modules/admin/base-watermark-screen/base-watermark-screen.component.html +++ /dev/null @@ -1,27 +0,0 @@ -
- - -
-
- - -
-
diff --git a/apps/red-ui/src/app/modules/admin/base-watermark-screen/base-watermark-screen.component.ts b/apps/red-ui/src/app/modules/admin/base-watermark-screen/base-watermark-screen.component.ts deleted file mode 100644 index 5a7dd87db..000000000 --- a/apps/red-ui/src/app/modules/admin/base-watermark-screen/base-watermark-screen.component.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { firstValueFrom } from 'rxjs'; -import { AdminDialogService } from '../services/admin-dialog.service'; -import { ConfirmationDialogInput, getParam, LoadingService, Toaster } from '@iqser/common-ui'; -import { WatermarkService } from '../../../services/entity-services/watermark.service'; -import { DOSSIER_TEMPLATE_ID, WATERMARK_ID } from '@red/domain'; -import { Router } from '@angular/router'; -import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; - -@Component({ - templateUrl: './base-watermark-screen.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class BaseWatermarkScreenComponent { - readonly #dossierTemplateId: string = getParam(DOSSIER_TEMPLATE_ID); - readonly #watermarkId: string = getParam(WATERMARK_ID); - - constructor( - private readonly _dialogService: AdminDialogService, - private readonly _loadingService: LoadingService, - private readonly _watermarkService: WatermarkService, - private readonly _toaster: Toaster, - private readonly _router: Router, - ) {} - - get editMode(): boolean { - return !!Number(this.#watermarkId); - } - - async openDeleteWatermarkDialog($event: MouseEvent): Promise { - const isUsed = await firstValueFrom(this._watermarkService.isWatermarkUsed(this.#watermarkId)); - - if (!isUsed) { - await this._deleteWatermark(this.#watermarkId); - return; - } - - const data = new ConfirmationDialogInput({ - question: _('watermarks-listing.watermark-is-used'), - }); - this._dialogService.openDialog('confirm', $event, data, async () => { - await this._deleteWatermark(this.#watermarkId); - }); - } - - private async _deleteWatermark(watermarkId: string): Promise { - this._loadingService.start(); - await firstValueFrom(this._watermarkService.deleteWatermark(watermarkId)); - this._toaster.success(_('watermarks-listing.action.delete-success')); - await this._router.navigate([`/main/admin/dossier-templates/${this.#dossierTemplateId}/watermarks`]); - this._loadingService.stop(); - } -} diff --git a/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.html index 15765c39a..da25b5949 100644 --- a/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.html +++ b/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.html @@ -12,7 +12,7 @@ -
+
diff --git a/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.ts index 8b0fcad16..4ffd87e7b 100644 --- a/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.ts @@ -1,34 +1,29 @@ -import { ChangeDetectorRef, Component, ElementRef, Inject, OnInit, ViewChild } from '@angular/core'; +import { ChangeDetectorRef, Component, ElementRef, Inject, ViewChild } from '@angular/core'; import { PermissionsService } from '@services/permissions.service'; import WebViewer, { WebViewerInstance } from '@pdftron/webviewer'; import { HttpClient } from '@angular/common/http'; -import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { Debounce, getParam, IconButtonTypes, LoadingService, Toaster } from '@iqser/common-ui'; -import { DOSSIER_TEMPLATE_ID, IWatermark, WATERMARK_ID, WatermarkOrientation, WatermarkOrientations } from '@red/domain'; +import { DOSSIER_TEMPLATE_ID, IWatermark, Watermark, WATERMARK_ID, WatermarkOrientation, WatermarkOrientations } from '@red/domain'; import { BASE_HREF_FN, BaseHrefFn } from '../../../../../tokens'; import { stampPDFPage } from '@utils/page-stamper'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { WatermarkService } from '@services/entity-services/watermark.service'; import { firstValueFrom, Observable, of } from 'rxjs'; -import { catchError, tap } from 'rxjs/operators'; +import { tap } from 'rxjs/operators'; import { LicenseService } from '@services/license.service'; import { UserPreferenceService } from '@services/user-preference.service'; import { Router } from '@angular/router'; +import { WatermarksMapService } from '@services/entity-services/watermarks-map.service'; -export const DEFAULT_WATERMARK: IWatermark = { - id: null, - dossierTemplateId: null, +export const DEFAULT_WATERMARK: Partial = { text: 'Watermark', name: '', - enabled: true, hexColor: '#000000', opacity: 30, fontSize: 40, - fontType: 'sans-serif', + fontType: 'helvetica', orientation: WatermarkOrientations.HORIZONTAL, - createdBy: null, - dateAdded: null, - dateModified: null, } as const; @Component({ @@ -36,13 +31,14 @@ export const DEFAULT_WATERMARK: IWatermark = { templateUrl: './watermark-screen.component.html', styleUrls: ['./watermark-screen.component.scss'], }) -export class WatermarkScreenComponent implements OnInit { +export class WatermarkScreenComponent { readonly iconButtonTypes = IconButtonTypes; readonly form: UntypedFormGroup = this._getForm(); + readonly watermark$: Observable>; readonly #dossierTemplateId: string = getParam(DOSSIER_TEMPLATE_ID); readonly #watermarkId = getParam(WATERMARK_ID); private _instance: WebViewerInstance; - private _watermark: IWatermark = {} as IWatermark; + private _watermark: Partial = {}; @ViewChild('viewer', { static: true }) private _viewer: ElementRef; @@ -58,12 +54,16 @@ export class WatermarkScreenComponent implements OnInit { private readonly _changeDetectorRef: ChangeDetectorRef, private readonly _userPreferenceService: UserPreferenceService, private readonly _router: Router, + private readonly _watermarksMapService: WatermarksMapService, ) { - this._loadingService.start(); + const obs$: Observable> = this.#watermarkId + ? _watermarksMapService.watch$(this.#dossierTemplateId, this.#watermarkId) + : of(DEFAULT_WATERMARK); + this.watermark$ = obs$.pipe(tap(wm => this._initForm(wm))); } get changed(): boolean { - for (const key of Object.keys(this._watermark)) { + for (const key of Object.keys(this.form.getRawValue())) { if (this._watermark[key] !== this.form.get(key)?.value) { return true; } @@ -78,22 +78,19 @@ export class WatermarkScreenComponent implements OnInit { return this.form.valid; } - async ngOnInit(): Promise { - if (!this.#watermarkId) { - this._initForm(DEFAULT_WATERMARK); - return; - } - await firstValueFrom(this._loadWatermark()); - } - @Debounce() async configChanged() { await this._drawWatermark(); } async save(): Promise { - const watermark: IWatermark = this.form.getRawValue(); - + const watermark: IWatermark = { + id: this._watermark.id, + enabled: this._watermark.id ? this._watermark.enabled : true, + dossierTemplateId: this.#dossierTemplateId, + ...this.form.getRawValue(), + }; + this._loadingService.start(); try { await firstValueFrom( this._watermarkService.saveWatermark(watermark).pipe( @@ -102,11 +99,11 @@ export class WatermarkScreenComponent implements OnInit { watermark.id ? _('watermark-screen.action.change-success') : _('watermark-screen.action.created-success'), ); }), - tap(async () => { + tap(async updatedWatermark => { if (!watermark.id) { - await this._router.navigate([`/main/admin/dossier-templates/${this.#dossierTemplateId}/watermarks`]); - } else { - await firstValueFrom(this._loadWatermark()); + await this._router.navigate([ + `/main/admin/dossier-templates/${this.#dossierTemplateId}/watermarks/${updatedWatermark.id}`, + ]); } }), ), @@ -114,10 +111,11 @@ export class WatermarkScreenComponent implements OnInit { } catch (error) { this._toaster.error(_('watermark-screen.action.error')); } + this._loadingService.stop(); } async revert() { - this.form.setValue({ ...this._watermark }); + this.form.patchValue({ ...this._watermark }); await this.configChanged(); } @@ -128,17 +126,9 @@ export class WatermarkScreenComponent implements OnInit { } } - private _loadWatermark(): Observable { - return this._watermarkService.getWatermark(this.#watermarkId).pipe( - catchError(() => of(DEFAULT_WATERMARK)), - tap(watermark => this._initForm(watermark)), - ); - } - - private _initForm(watermark: IWatermark) { - this._watermark = watermark; - this._watermark.dossierTemplateId = this.#dossierTemplateId; - this.form.setValue({ ...watermark }); + private _initForm(watermark: Partial) { + this._watermark = { ...watermark, dossierTemplateId: this.#dossierTemplateId }; + this.form.patchValue({ ...watermark }); this._loadViewer(); this._changeDetectorRef.markForCheck(); } @@ -211,26 +201,20 @@ export class WatermarkScreenComponent implements OnInit { } private _getForm(): UntypedFormGroup { - const defaultValue = { - value: null, - disabled: !this.permissionsService.isAdmin(), - }; - const defaultFormControl = [{ ...defaultValue }, Validators.required]; - - return this._formBuilder.group({ - id: [{ ...defaultValue }], - name: [{ ...defaultFormControl }], - enabled: [{ ...defaultValue }], - dossierTemplateId: [{ ...defaultValue }], - text: [{ ...defaultFormControl }], - hexColor: [...defaultFormControl], - opacity: [...defaultFormControl], - fontSize: [...defaultFormControl], - fontType: [...defaultFormControl], - orientation: [...defaultFormControl], - createdBy: [{ ...defaultValue }], - dateAdded: [{ ...defaultValue }], - dateModified: [{ ...defaultValue }], + const form = this._formBuilder.group({ + name: [null], + text: [null], + hexColor: [null], + opacity: [null], + fontSize: [null], + fontType: [null], + orientation: [null], }); + + if (!this.permissionsService.isAdmin()) { + form.disable(); + } + + return form; } } diff --git a/apps/red-ui/src/app/modules/admin/screens/watermark/watermark.module.ts b/apps/red-ui/src/app/modules/admin/screens/watermark/watermark.module.ts index 962eecb37..81bb86e1a 100644 --- a/apps/red-ui/src/app/modules/admin/screens/watermark/watermark.module.ts +++ b/apps/red-ui/src/app/modules/admin/screens/watermark/watermark.module.ts @@ -3,11 +3,42 @@ import { CommonModule } from '@angular/common'; import { RouterModule } from '@angular/router'; import { SharedModule } from '@shared/shared.module'; import { WatermarkScreenComponent } from './watermark-screen/watermark-screen.component'; +import { WatermarksListingScreenComponent } from './watermarks-listing/watermarks-listing-screen.component'; +import { CompositeRouteGuard } from '@iqser/common-ui'; +import { AuthGuard } from '../../../auth/auth.guard'; +import { RedRoleGuard } from '../../../auth/red-role.guard'; +import { WATERMARK_ID } from '@red/domain'; +import { WatermarkExistsGuard } from '@guards/watermark-exists.guard'; -const routes = [{ path: '', component: WatermarkScreenComponent }]; +const routes = [ + { + path: '', + component: WatermarksListingScreenComponent, + canActivate: [CompositeRouteGuard], + data: { + routeGuards: [AuthGuard, RedRoleGuard], + }, + }, + { + path: 'create', + component: WatermarkScreenComponent, + canActivate: [CompositeRouteGuard], + data: { + routeGuards: [AuthGuard, RedRoleGuard], + }, + }, + { + path: `:${WATERMARK_ID}`, + component: WatermarkScreenComponent, + canActivate: [CompositeRouteGuard], + data: { + routeGuards: [AuthGuard, RedRoleGuard, WatermarkExistsGuard], + }, + }, +]; @NgModule({ - declarations: [WatermarkScreenComponent], + declarations: [WatermarkScreenComponent, WatermarksListingScreenComponent], imports: [RouterModule.forChild(routes), CommonModule, SharedModule], }) export class WatermarkModule {} diff --git a/apps/red-ui/src/app/modules/admin/screens/watermark/watermarks-listing/watermarks-listing-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/watermark/watermarks-listing/watermarks-listing-screen.component.html new file mode 100644 index 000000000..759f933a0 --- /dev/null +++ b/apps/red-ui/src/app/modules/admin/screens/watermark/watermarks-listing/watermarks-listing-screen.component.html @@ -0,0 +1,71 @@ +
+ +
+ + +
+ +
+
+ + +
+
+ {{ entity.name }} +
+ +
+ +
+ +
+ +
+ +
+
+ {{ entity.dateAdded | date: 'd MMM yyyy' }} +
+
+ +
+
+ {{ entity.dateModified | date: 'd MMM yyyy' }} +
+
+ +
+
+ + + +
+
+
+
diff --git a/apps/red-ui/src/app/modules/admin/screens/watermarks-listing/watermarks-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/watermark/watermarks-listing/watermarks-listing-screen.component.ts similarity index 72% rename from apps/red-ui/src/app/modules/admin/screens/watermarks-listing/watermarks-listing-screen.component.ts rename to apps/red-ui/src/app/modules/admin/screens/watermark/watermarks-listing/watermarks-listing-screen.component.ts index 56439a7d1..1e72485cd 100644 --- a/apps/red-ui/src/app/modules/admin/screens/watermarks-listing/watermarks-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/watermark/watermarks-listing/watermarks-listing-screen.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, Component } from '@angular/core'; import { CircleButtonTypes, ConfirmationDialogInput, @@ -15,14 +15,15 @@ import { getCurrentUser } from '@services/user.service'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { firstValueFrom } from 'rxjs'; import { WatermarkService } from '@services/entity-services/watermark.service'; -import { AdminDialogService } from '../../services/admin-dialog.service'; +import { AdminDialogService } from '../../../services/admin-dialog.service'; +import { WatermarksMapService } from '@services/entity-services/watermarks-map.service'; @Component({ templateUrl: './watermarks-listing-screen.component.html', changeDetection: ChangeDetectionStrategy.OnPush, providers: listingProvidersFactory(WatermarksListingScreenComponent), }) -export class WatermarksListingScreenComponent extends ListingComponent implements OnInit { +export class WatermarksListingScreenComponent extends ListingComponent { readonly iconButtonTypes = IconButtonTypes; readonly circleButtonTypes = CircleButtonTypes; readonly currentUser = getCurrentUser(); @@ -39,36 +40,29 @@ export class WatermarksListingScreenComponent extends ListingComponent { - await this._loadData(); + this.entitiesService.setEntities(this._watermarksMapService.get(this.#dossierTemplateId)); } async openConfirmDeleteWatermarkDialog($event: MouseEvent, watermark: Watermark): Promise { const isUsed = await firstValueFrom(this._watermarkService.isWatermarkUsed(watermark.id)); - if (!isUsed) { - await this._deleteWatermark(watermark); - return; - } - const data = new ConfirmationDialogInput({ - question: _('watermarks-listing.watermark-is-used'), + question: isUsed ? _('watermarks-listing.watermark-is-used') : null, }); this._dialogService.openDialog('confirm', $event, data, async () => { await this._deleteWatermark(watermark); }); } - async toggleStatus(watermark?: Watermark): Promise { - watermark.enabled = !watermark.enabled; + async toggleStatus(watermark: Watermark): Promise { this._loadingService.start(); - await firstValueFrom(this._watermarkService.saveWatermark(watermark)); + const updatedWatermark = await firstValueFrom(this._watermarkService.saveWatermark({ ...watermark, enabled: !watermark.enabled })); + this.entitiesService.replace(updatedWatermark); this._loadingService.stop(); } @@ -76,25 +70,11 @@ export class WatermarksListingScreenComponent extends ListingComponent { - this._loadingService.start(); - - try { - const response = await firstValueFrom(this._watermarkService.getWatermarks(this.#dossierTemplateId)); - const watermarkConfig = response?.map(item => new Watermark(item)) || []; - this.entitiesService.setEntities(watermarkConfig); - } catch (e) { - console.log(e); - } - - this._loadingService.stop(); - } - private async _deleteWatermark(watermark: Watermark): Promise { this._loadingService.start(); - await firstValueFrom(this._watermarkService.deleteWatermark(watermark.id)); + await firstValueFrom(this._watermarkService.deleteWatermark(this.#dossierTemplateId, watermark.id)); + this.entitiesService.setEntities(this._watermarksMapService.get(this.#dossierTemplateId)); this._toaster.success(_('watermarks-listing.action.delete-success')); - await this._loadData(); this._loadingService.stop(); } } diff --git a/apps/red-ui/src/app/modules/admin/screens/watermarks-listing/watermarks-listing-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/watermarks-listing/watermarks-listing-screen.component.html deleted file mode 100644 index 51a35dd1a..000000000 --- a/apps/red-ui/src/app/modules/admin/screens/watermarks-listing/watermarks-listing-screen.component.html +++ /dev/null @@ -1,105 +0,0 @@ -
- - -
-
- - - -
- -
-
-
- - -
- -
-
- - - - - - -
-
- {{ watermark.name }} -
- -
- -
- -
- -
- -
-
- {{ watermark.dateAdded | date: 'd MMM yyyy' }} -
-
- -
-
- {{ watermark.dateModified | date: 'd MMM yyyy' }} -
-
- -
-
- - - -
-
-
-
diff --git a/apps/red-ui/src/app/modules/file-preview/services/stamp.service.ts b/apps/red-ui/src/app/modules/file-preview/services/stamp.service.ts index 91a7617e3..b1ad58a52 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/stamp.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/stamp.service.ts @@ -5,11 +5,10 @@ import { NGXLogger } from 'ngx-logger'; import { ViewModeService } from './view-mode.service'; import { TranslateService } from '@ngx-translate/core'; import { Core } from '@pdftron/webviewer'; -import { firstValueFrom } from 'rxjs'; -import { WatermarkService } from '@services/entity-services/watermark.service'; import { PdfViewer } from '../../pdf-viewer/services/pdf-viewer.service'; import { REDDocumentViewer } from '../../pdf-viewer/services/document-viewer.service'; -import { LicenseService } from '../../../services/license.service'; +import { LicenseService } from '@services/license.service'; +import { WatermarksMapService } from '@services/entity-services/watermarks-map.service'; import PDFNet = Core.PDFNet; @Injectable() @@ -21,7 +20,7 @@ export class StampService { private readonly _logger: NGXLogger, private readonly _viewModeService: ViewModeService, private readonly _translateService: TranslateService, - private readonly _watermarkService: WatermarkService, + private readonly _watermarksMapService: WatermarksMapService, private readonly _licenseService: LicenseService, ) {} @@ -44,7 +43,7 @@ export class StampService { if (this._viewModeService.isRedacted) { const dossier = this._state.dossier; if (dossier.previewWatermarkId) { - await this._stampPreview(pdfDoc, dossier.dossierTemplateId); + await this._stampPreview(pdfDoc, dossier.dossierTemplateId, dossier.previewWatermarkId); } } else { await this._stampExcludedPages(pdfDoc, file.excludedPages); @@ -70,8 +69,8 @@ export class StampService { } } - private async _stampPreview(document: PDFNet.PDFDoc, dossierTemplateId: string): Promise { - const watermark = await firstValueFrom(this._watermarkService.getWatermark(dossierTemplateId)); + private async _stampPreview(document: PDFNet.PDFDoc, dossierTemplateId: string, watermarkId: string): Promise { + const watermark = this._watermarksMapService.get(dossierTemplateId, watermarkId); await stampPDFPage( document, this._pdf.PDFNet, diff --git a/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/download-package/edit-dossier-download-package.component.html b/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/download-package/edit-dossier-download-package.component.html index ffd39571b..d4ed31b75 100644 --- a/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/download-package/edit-dossier-download-package.component.html +++ b/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/download-package/edit-dossier-download-package.component.html @@ -15,13 +15,19 @@ >
- - + + + +
diff --git a/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/download-package/edit-dossier-download-package.component.ts b/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/download-package/edit-dossier-download-package.component.ts index ca6fb0fd6..1db6d6a20 100644 --- a/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/download-package/edit-dossier-download-package.component.ts +++ b/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/download-package/edit-dossier-download-package.component.ts @@ -7,7 +7,6 @@ import { ReportTemplateService } from '@services/report-template.service'; import { PermissionsService } from '@services/permissions.service'; import { firstValueFrom } from 'rxjs'; import { DossiersService } from '@services/dossiers/dossiers.service'; -import { UpdateWatermarkIdsEvent } from '@components/dossier-watermark-selector/dossier-watermark-selector.component'; @Component({ selector: 'redaction-edit-dossier-download-package', @@ -47,7 +46,7 @@ export class EditDossierDownloadPackageComponent implements OnInit, EditDossierS } for (const key of Object.keys(this.form.getRawValue())) { - if (key.startsWith('watermark') || key.startsWith('previewWatermark')) { + if (key.toLowerCase().includes('watermark')) { if (this.dossier[key] !== this.form.get(key).value) { return true; } @@ -107,8 +106,8 @@ export class EditDossierDownloadPackageComponent implements OnInit, EditDossierS this.form.reset({ downloadFileTypes: this.dossier.downloadFileTypes, reportTemplateIds: this.dossier.reportTemplateIds, - watermarkId: [this.dossier.watermarkId], - previewWatermarkId: [this.dossier.previewWatermarkId], + watermarkId: this.dossier.watermarkId, + previewWatermarkId: this.dossier.previewWatermarkId, }); } @@ -128,9 +127,4 @@ export class EditDossierDownloadPackageComponent implements OnInit, EditDossierS }, ); } - - updateWatermarkIds(event: UpdateWatermarkIdsEvent) { - this.form.get('watermarkId').setValue(event.watermarkId); - this.form.get('previewWatermarkId').setValue(event.previewWatermarkId); - } } diff --git a/apps/red-ui/src/app/modules/shared/components/dossier-watermark-selector/watermark-selector.component.html b/apps/red-ui/src/app/modules/shared/components/dossier-watermark-selector/watermark-selector.component.html new file mode 100644 index 000000000..87c95f517 --- /dev/null +++ b/apps/red-ui/src/app/modules/shared/components/dossier-watermark-selector/watermark-selector.component.html @@ -0,0 +1,19 @@ +
+
+ + {{ label }} + + + + + + {{ watermarksMap.get(value)?.name }} + + + + + {{ watermark.name }} + + +
+
diff --git a/apps/red-ui/src/app/components/dossier-watermark-selector/dossier-watermark-selector.component.scss b/apps/red-ui/src/app/modules/shared/components/dossier-watermark-selector/watermark-selector.component.scss similarity index 100% rename from apps/red-ui/src/app/components/dossier-watermark-selector/dossier-watermark-selector.component.scss rename to apps/red-ui/src/app/modules/shared/components/dossier-watermark-selector/watermark-selector.component.scss diff --git a/apps/red-ui/src/app/modules/shared/components/dossier-watermark-selector/watermark-selector.component.ts b/apps/red-ui/src/app/modules/shared/components/dossier-watermark-selector/watermark-selector.component.ts new file mode 100644 index 000000000..85bb4a7f3 --- /dev/null +++ b/apps/red-ui/src/app/modules/shared/components/dossier-watermark-selector/watermark-selector.component.ts @@ -0,0 +1,81 @@ +import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { FormFieldComponent, shareLast } from '@iqser/common-ui'; +import { filter, map, tap } from 'rxjs/operators'; +import { NG_VALIDATORS, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { Watermark } from '@red/domain'; +import { WatermarksMapService } from '@services/entity-services/watermarks-map.service'; +import { MatCheckboxChange } from '@angular/material/checkbox'; + +@Component({ + selector: 'redaction-watermark-selector [dossierTemplateId] [label]', + templateUrl: './watermark-selector.component.html', + styleUrls: ['./watermark-selector.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + multi: true, + useExisting: WatermarkSelectorComponent, + }, + { + provide: NG_VALIDATORS, + multi: true, + useExisting: WatermarkSelectorComponent, + }, + ], +}) +export class WatermarkSelectorComponent extends FormFieldComponent implements OnChanges { + @Input() dossierTemplateId: string; + @Input() label: string; + readonly watermarks$: Observable; + watermarksMap = new Map(); + #watermarks: Watermark[] = []; + readonly #dossierTemplateId$ = new BehaviorSubject(null); + + constructor(private readonly _watermarksMapService: WatermarksMapService) { + super(); + this.watermarks$ = this.#dossierTemplateId$.pipe( + filter(dossierTemplateId => !!dossierTemplateId), + map(dossierTemplateId => this._watermarksMapService.get(dossierTemplateId)), + tap(watermarks => { + this.#watermarks = watermarks; + this.watermarksMap.clear(); + watermarks.forEach(watermark => this.watermarksMap.set(watermark.id, watermark)); + }), + tap(watermarks => { + if (!watermarks.length) { + this.selectWatermark(null); + this.setDisabledState(true); + } else { + this.setDisabledState(false); + if (this.value && this.touched) { + this.selectWatermark(watermarks[0].id); + } + } + }), + shareLast(), + ); + } + + changeChecked($event: MatCheckboxChange): void { + const { checked } = $event; + if (!checked || this.#watermarks.length === 0) { + this.selectWatermark(null); + } else { + this.selectWatermark(this.#watermarks[0].id); + } + } + + selectWatermark(watermarkId: string): void { + this.markAsTouched(); + this._value = watermarkId; + this.onChange(this._value); + } + + ngOnChanges(changes: SimpleChanges) { + if (changes.dossierTemplateId) { + this.#dossierTemplateId$.next(this.dossierTemplateId); + } + } +} diff --git a/apps/red-ui/src/app/modules/shared/dialogs/add-dossier-dialog/add-dossier-dialog.component.html b/apps/red-ui/src/app/modules/shared/dialogs/add-dossier-dialog/add-dossier-dialog.component.html index 7a661dc1c..5c1e3844e 100644 --- a/apps/red-ui/src/app/modules/shared/dialogs/add-dossier-dialog/add-dossier-dialog.component.html +++ b/apps/red-ui/src/app/modules/shared/dialogs/add-dossier-dialog/add-dossier-dialog.component.html @@ -47,8 +47,19 @@ >
- - + + + + +
@@ -92,10 +103,10 @@ diff --git a/apps/red-ui/src/app/modules/shared/dialogs/add-dossier-dialog/add-dossier-dialog.component.ts b/apps/red-ui/src/app/modules/shared/dialogs/add-dossier-dialog/add-dossier-dialog.component.ts index 3ae34e23b..5d3435e9d 100644 --- a/apps/red-ui/src/app/modules/shared/dialogs/add-dossier-dialog/add-dossier-dialog.component.ts +++ b/apps/red-ui/src/app/modules/shared/dialogs/add-dossier-dialog/add-dossier-dialog.component.ts @@ -11,7 +11,6 @@ import { firstValueFrom } from 'rxjs'; import dayjs from 'dayjs'; import { Router } from '@angular/router'; import { DossiersDialogService } from '../../../shared-dossiers/services/dossiers-dialog.service'; -import { UpdateWatermarkIdsEvent } from '@components/dossier-watermark-selector/dossier-watermark-selector.component'; interface DialogData { readonly dossierTemplateId?: string; @@ -67,17 +66,11 @@ export class AddDossierDialogComponent extends BaseDialogComponent implements On } async ngOnInit(): Promise { - this.dossierTemplateId = this.form.get('dossierTemplateId').value; - await this.dossierTemplateChanged(this.dossierTemplateId); + await this.dossierTemplateChanged(this.form.get('dossierTemplateId').value); } reportTemplateValueMapper = (reportTemplate: IReportTemplate) => reportTemplate.templateId; - updateWatermarkIds(event: UpdateWatermarkIdsEvent) { - this.form.get('watermarkId').setValue(event.watermarkId); - this.form.get('previewWatermarkId').setValue(event.previewWatermarkId); - } - async save(options?: SaveOptions) { this._loadingService.start(); const savedDossier = await firstValueFrom(this._activeDossiersService.createOrUpdate(this._formToObject())); @@ -94,7 +87,9 @@ export class AddDossierDialogComponent extends BaseDialogComponent implements On this._loadingService.stop(); } - async dossierTemplateChanged(dossierTemplateId) { + async dossierTemplateChanged(dossierTemplateId: string) { + this.dossierTemplateId = dossierTemplateId; + // get current selected dossierTemplate const dossierTemplate = this.dossierTemplates.find(r => r.dossierTemplateId === dossierTemplateId); diff --git a/apps/red-ui/src/app/modules/shared/shared.module.ts b/apps/red-ui/src/app/modules/shared/shared.module.ts index 787a6f98d..02f0b6fa5 100644 --- a/apps/red-ui/src/app/modules/shared/shared.module.ts +++ b/apps/red-ui/src/app/modules/shared/shared.module.ts @@ -23,20 +23,20 @@ import { TypeFilterComponent } from './components/type-filter/type-filter.compon import { TeamMembersComponent } from './components/team-members/team-members.component'; import { EditorComponent } from './components/editor/editor.component'; import { ExpandableFileActionsComponent } from './components/expandable-file-actions/expandable-file-actions.component'; -import { ProcessingIndicatorComponent } from '@shared/components/processing-indicator/processing-indicator.component'; -import { DossierStateComponent } from '@shared/components/dossier-state/dossier-state.component'; +import { ProcessingIndicatorComponent } from './components/processing-indicator/processing-indicator.component'; +import { DossierStateComponent } from './components/dossier-state/dossier-state.component'; import { FileStatsComponent } from './components/file-stats/file-stats.component'; -import { FileNameColumnComponent } from '@shared/components/file-name-column/file-name-column.component'; -import { DossierNameColumnComponent } from '@shared/components/dossier-name-column/dossier-name-column.component'; +import { FileNameColumnComponent } from './components/file-name-column/file-name-column.component'; +import { DossierNameColumnComponent } from './components/dossier-name-column/dossier-name-column.component'; import { MAT_DATE_FORMATS } from '@angular/material/core'; -import { DossiersTypeSwitchComponent } from '@shared/components/dossiers-type-switch/dossiers-type-switch.component'; +import { DossiersTypeSwitchComponent } from './components/dossiers-type-switch/dossiers-type-switch.component'; import { TranslateModule } from '@ngx-translate/core'; import { RouterModule } from '@angular/router'; -import { AddDossierDialogComponent } from '@shared/dialogs/add-dossier-dialog/add-dossier-dialog.component'; -import { SharedDialogService } from '@shared/services/dialog.service'; -import { DossierWatermarkSelectorComponent } from '@components/dossier-watermark-selector/dossier-watermark-selector.component'; -import { AddEditEntityComponent } from '@shared/components/add-edit-entity/add-edit-entity.component'; +import { AddDossierDialogComponent } from './dialogs/add-dossier-dialog/add-dossier-dialog.component'; +import { SharedDialogService } from './services/dialog.service'; +import { AddEditEntityComponent } from './components/add-edit-entity/add-edit-entity.component'; import { ColorPickerModule } from 'ngx-color-picker'; +import { WatermarkSelectorComponent } from './components/dossier-watermark-selector/watermark-selector.component'; const buttons = [FileDownloadBtnComponent, UserButtonComponent]; @@ -58,7 +58,7 @@ const components = [ FileNameColumnComponent, DossiersTypeSwitchComponent, AddDossierDialogComponent, - DossierWatermarkSelectorComponent, + WatermarkSelectorComponent, AddEditEntityComponent, ...buttons, diff --git a/apps/red-ui/src/app/services/dossier-templates/dossier-templates.service.ts b/apps/red-ui/src/app/services/dossier-templates/dossier-templates.service.ts index 2b019a522..2922875c4 100644 --- a/apps/red-ui/src/app/services/dossier-templates/dossier-templates.service.ts +++ b/apps/red-ui/src/app/services/dossier-templates/dossier-templates.service.ts @@ -9,6 +9,7 @@ import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { DictionaryService } from '../entity-services/dictionary.service'; import { DefaultColorsService } from '@services/entity-services/default-colors.service'; +import { WatermarkService } from '@services/entity-services/watermark.service'; const DOSSIER_TEMPLATE_CONFLICT_MSG = _('dossier-templates-listing.error.conflict'); const GENERIC_MSG = _('dossier-templates-listing.error.generic'); @@ -26,6 +27,7 @@ export class DossierTemplatesService extends EntitiesService templates)); } return of(templates); diff --git a/apps/red-ui/src/app/services/entity-services/watermark.service.ts b/apps/red-ui/src/app/services/entity-services/watermark.service.ts index 1f2af26c3..5d296d215 100644 --- a/apps/red-ui/src/app/services/entity-services/watermark.service.ts +++ b/apps/red-ui/src/app/services/entity-services/watermark.service.ts @@ -1,8 +1,9 @@ import { Injectable } from '@angular/core'; -import { GenericService, QueryParam, RequiredParam, Validate } from '@iqser/common-ui'; -import { IWatermark } from '@red/domain'; -import { Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; +import { GenericService, mapEach, QueryParam, RequiredParam, Validate } from '@iqser/common-ui'; +import { IWatermark, Watermark } from '@red/domain'; +import { forkJoin, Observable } from 'rxjs'; +import { map, switchMap, tap } from 'rxjs/operators'; +import { WatermarksMapService } from '@services/entity-services/watermarks-map.service'; interface IsUsedResponse { value: boolean; @@ -14,25 +15,40 @@ interface IsUsedResponse { export class WatermarkService extends GenericService { protected readonly _defaultModelPath = 'watermark'; - @Validate() - saveWatermark(@RequiredParam() body: IWatermark) { - return this._post(body, `${this._defaultModelPath}`); + constructor(private readonly _watermarksMapService: WatermarksMapService) { + super(); } @Validate() - deleteWatermark(@RequiredParam() watermarkId: string) { - return super.delete({}, `${this._defaultModelPath}/${watermarkId}`); + deleteWatermark(@RequiredParam() dossierTemplateId: string, @RequiredParam() watermarkId: string): Observable { + return super + .delete(null, `${this._defaultModelPath}/${watermarkId}`) + .pipe(switchMap(() => this.loadForDossierTemplate(dossierTemplateId))); } @Validate() - getWatermark(@RequiredParam() watermarkId: string) { - return this._getOne([watermarkId]); + saveWatermark(@RequiredParam() body: IWatermark): Observable { + return this._post(body, `${this._defaultModelPath}`).pipe( + switchMap(watermark => + this.loadForDossierTemplate(watermark.dossierTemplateId).pipe( + map(() => this._watermarksMapService.get(watermark.dossierTemplateId, watermark.id.toString())), + ), + ), + ); } @Validate() - getWatermarks(@RequiredParam() dossierTemplateId: string): Observable { + loadForDossierTemplate(@RequiredParam() dossierTemplateId: string): Observable { const queryParams: QueryParam[] = [{ key: 'dossierTemplateId', value: dossierTemplateId }]; - return this.getAll(this._defaultModelPath, queryParams); + return this.getAll(this._defaultModelPath, queryParams).pipe( + mapEach(entity => new Watermark(entity)), + tap(entities => this._watermarksMapService.set(dossierTemplateId, entities.sort(this.sortByStatusFn))), + ); + } + + @Validate() + loadAll(@RequiredParam() dossierTemplateIds: string[]): Observable { + return forkJoin(dossierTemplateIds.map(id => this.loadForDossierTemplate(id))).pipe(map(arrays => [].concat(...arrays))); } @Validate() @@ -40,4 +56,11 @@ export class WatermarkService extends GenericService { const queryParams: QueryParam[] = [{ key: 'watermarkId', value: watermarkId }]; return this.getAll(`${this._defaultModelPath}/used`, queryParams).pipe(map(result => result.value)); } + + sortByStatusFn = (a: Watermark, b: Watermark) => { + if (a.enabled === b.enabled) { + return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1; + } + return a.enabled ? -1 : 1; + }; } diff --git a/apps/red-ui/src/app/services/entity-services/watermarks-map.service.ts b/apps/red-ui/src/app/services/entity-services/watermarks-map.service.ts new file mode 100644 index 000000000..ed55b3931 --- /dev/null +++ b/apps/red-ui/src/app/services/entity-services/watermarks-map.service.ts @@ -0,0 +1,8 @@ +import { Injectable } from '@angular/core'; +import { DOSSIER_TEMPLATE_ID, IWatermark, Watermark } from '@red/domain'; +import { EntitiesMapService } from '@iqser/common-ui'; + +@Injectable({ providedIn: 'root' }) +export class WatermarksMapService extends EntitiesMapService { + protected readonly _primaryKey = DOSSIER_TEMPLATE_ID; +} diff --git a/libs/common-ui b/libs/common-ui index 345454be9..477e8ea5a 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit 345454be9d260a3fbb27e9e5b57902dda2e350e0 +Subproject commit 477e8ea5ae97244703dbfe04a4ee98daa8d5f185 diff --git a/libs/red-domain/src/lib/dossiers/dossier.model.ts b/libs/red-domain/src/lib/dossiers/dossier.model.ts index 78edaac1d..939cdb268 100644 --- a/libs/red-domain/src/lib/dossiers/dossier.model.ts +++ b/libs/red-domain/src/lib/dossiers/dossier.model.ts @@ -19,8 +19,8 @@ export class Dossier implements IDossier, IListable { readonly hardDeletedTime?: string; readonly softDeletedTime?: string; readonly startDate?: string; - readonly watermarkId: number; - readonly previewWatermarkId: number; + readonly watermarkId: string; + readonly previewWatermarkId: string; readonly archivedTime: string; readonly hasReviewers: boolean; readonly routerLink: string; diff --git a/libs/red-domain/src/lib/dossiers/dossier.request.ts b/libs/red-domain/src/lib/dossiers/dossier.request.ts index d31e01c90..2e65c95ba 100644 --- a/libs/red-domain/src/lib/dossiers/dossier.request.ts +++ b/libs/red-domain/src/lib/dossiers/dossier.request.ts @@ -56,9 +56,9 @@ export interface IDossierRequest { /** * Watermark id that will be applied to the redacted files. */ - readonly watermarkId?: number; + readonly watermarkId?: string; /** * Watermark id that will be applied to the preview files. */ - readonly previewWatermarkId?: number; + readonly previewWatermarkId?: string; } diff --git a/libs/red-domain/src/lib/dossiers/dossier.ts b/libs/red-domain/src/lib/dossiers/dossier.ts index 04c081e33..d8ebe113b 100644 --- a/libs/red-domain/src/lib/dossiers/dossier.ts +++ b/libs/red-domain/src/lib/dossiers/dossier.ts @@ -17,7 +17,7 @@ export interface IDossier { readonly reportTemplateIds: List; readonly softDeletedTime?: string; readonly startDate?: string; - readonly watermarkId: number; - readonly previewWatermarkId: number; + readonly watermarkId: string; + readonly previewWatermarkId: string; readonly archivedTime: string; } diff --git a/libs/red-domain/src/lib/watermarks/watermark.model.ts b/libs/red-domain/src/lib/watermarks/watermark.model.ts index 7cc6100dc..e63a8072c 100644 --- a/libs/red-domain/src/lib/watermarks/watermark.model.ts +++ b/libs/red-domain/src/lib/watermarks/watermark.model.ts @@ -1,10 +1,10 @@ import { IWatermark, WatermarkOrientation } from './watermark'; -import { IListable } from '@iqser/common-ui'; +import { Entity } from '@iqser/common-ui'; -export class Watermark implements IListable, IWatermark { +export class Watermark extends Entity { readonly id: string; readonly dossierTemplateId: string; - enabled: boolean; + readonly enabled: boolean; readonly fontSize: number; readonly fontType: string; readonly hexColor: string; @@ -16,12 +16,15 @@ export class Watermark implements IListable, IWatermark { readonly dateAdded?: string; readonly dateModified?: string; + readonly routerLink = undefined; + constructor(watermark: IWatermark) { - this.id = watermark.id; + super(watermark); + this.id = watermark.id.toString(); this.dossierTemplateId = watermark.dossierTemplateId; this.enabled = watermark.enabled; this.fontSize = watermark.fontSize; - this.fontType = watermark.fontType; + this.fontType = watermark.fontType === 'arial' ? 'helvetica' : watermark.fontType; this.hexColor = watermark.hexColor; this.opacity = watermark.opacity; this.orientation = watermark.orientation;