RED-4247 - WIP on watermarks list

This commit is contained in:
Valentin Mihai 2022-06-27 18:20:56 +03:00
parent 4c03f92c62
commit e1c0f2d5e6
18 changed files with 329 additions and 27 deletions

View File

@ -15,12 +15,15 @@ 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 } from '@red/domain';
import { DOSSIER_TEMPLATE_ID, ENTITY_TYPE, WATERMARK_ID } 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 { WatermarkScreenComponent } from './screens/watermark/watermark-screen/watermark-screen.component';
import { WatermarkModule } from './screens/watermark/watermark.module';
const dossierTemplateIdRoutes: Routes = [
{
@ -69,13 +72,26 @@ const dossierTemplateIdRoutes: Routes = [
},
},
{
path: 'watermark',
component: BaseDossierTemplateScreenComponent,
canActivate: [CompositeRouteGuard],
data: {
routeGuards: [AuthGuard, RedRoleGuard],
},
loadChildren: () => import('./screens/watermark/watermark.module').then(m => m.WatermarkModule),
path: 'watermarks',
children: [
{
path: '',
component: WatermarksListingScreenComponent,
canActivate: [CompositeRouteGuard],
data: {
routeGuards: [AuthGuard, RedRoleGuard],
},
},
{
path: `:${WATERMARK_ID}`,
component: WatermarkScreenComponent,
canActivate: [CompositeRouteGuard],
loadChildren: () => import('./screens/watermark/watermark.module').then(m => m.WatermarkModule),
data: {
routeGuards: [AuthGuard, RedRoleGuard],
},
},
],
},
{
path: 'reports',

View File

@ -59,7 +59,7 @@ export class AdminSideNavComponent implements OnInit {
hideIf: !this.userPreferenceService.areDevFeaturesEnabled,
},
{ screen: 'default-colors', label: _('admin-side-nav.default-colors') },
{ screen: 'watermark', label: _('admin-side-nav.watermark') },
{ screen: 'watermarks', label: _('admin-side-nav.watermarks') },
{ screen: 'file-attributes', label: _('admin-side-nav.file-attributes') },
{ screen: 'dossier-attributes', label: _('admin-side-nav.dossier-attributes') },
{ screen: 'dossier-states', label: _('admin-side-nav.dossier-states') },

View File

@ -46,6 +46,7 @@ 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';
const dialogs = [
AddEditCloneDossierTemplateDialogComponent,
@ -73,6 +74,7 @@ const screens = [
GeneralConfigScreenComponent,
DossierAttributesListingScreenComponent,
DossierStatesListingScreenComponent,
WatermarksListingScreenComponent,
];
const components = [

View File

@ -4,7 +4,7 @@ import WebViewer, { WebViewerInstance } from '@pdftron/webviewer';
import { HttpClient } from '@angular/common/http';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { Debounce, IconButtonTypes, LoadingService, Toaster } from '@iqser/common-ui';
import { DOSSIER_TEMPLATE_ID, IWatermark, WatermarkOrientation, WatermarkOrientations } from '@red/domain';
import { DOSSIER_TEMPLATE_ID, IWatermark, 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';
@ -15,12 +15,19 @@ import { ActivatedRoute } from '@angular/router';
import { LicenseService } from '../../../../../services/license.service';
export const DEFAULT_WATERMARK: IWatermark = {
id: null,
dossierTemplateId: null,
text: null,
name: null,
enabled: false,
hexColor: '#dd4d50',
opacity: 70,
fontSize: 11,
fontType: 'sans-serif',
orientation: WatermarkOrientations.DIAGONAL,
createdBy: null,
dateAdded: null,
dateModified: null,
} as const;
@Component({
@ -32,8 +39,9 @@ export class WatermarkScreenComponent implements OnInit {
readonly iconButtonTypes = IconButtonTypes;
readonly form: UntypedFormGroup = this._getForm();
readonly #dossierTemplateId: string;
readonly #watermarkId: string;
private _instance: WebViewerInstance;
private _watermark: IWatermark = {};
private _watermark: IWatermark = {} as IWatermark;
@ViewChild('viewer', { static: true })
private _viewer: ElementRef;
@ -51,6 +59,7 @@ export class WatermarkScreenComponent implements OnInit {
) {
this._loadingService.start();
this.#dossierTemplateId = route.snapshot.paramMap.get(DOSSIER_TEMPLATE_ID);
this.#watermarkId = route.snapshot.paramMap.get(WATERMARK_ID);
}
get changed(): boolean {
@ -78,8 +87,8 @@ export class WatermarkScreenComponent implements OnInit {
const watermark: IWatermark = this.form.getRawValue();
const observable = watermark.text
? this._watermarkService.saveWatermark(watermark, this.#dossierTemplateId)
: this._watermarkService.deleteWatermark(this.#dossierTemplateId);
? this._watermarkService.saveWatermark(watermark)
: this._watermarkService.deleteWatermark(this.#watermarkId);
try {
await firstValueFrom(
@ -112,10 +121,12 @@ export class WatermarkScreenComponent implements OnInit {
}
private _loadWatermark(): Observable<IWatermark> {
return this._watermarkService.getWatermark(this.#dossierTemplateId).pipe(
return this._watermarkService.getWatermark(this.#watermarkId).pipe(
catchError(() => of(DEFAULT_WATERMARK)),
tap(watermark => {
this._watermark = watermark;
console.log('watermark: ', this._watermark);
delete watermark.id;
this.form.setValue({ ...watermark });
this._loadViewer();
}),
@ -195,6 +206,9 @@ export class WatermarkScreenComponent implements OnInit {
const defaultFormControl = [{ ...defaultValue }, Validators.required];
return this._formBuilder.group({
name: [{ ...defaultValue }],
enabled: [{ ...defaultValue }],
dossierTemplateId: [{ ...defaultValue }],
text: [{ ...defaultValue }],
hexColor: [...defaultFormControl],
opacity: [...defaultFormControl],

View File

@ -0,0 +1,105 @@
<section>
<div class="page-header">
<redaction-dossier-template-breadcrumbs class="flex-1"></redaction-dossier-template-breadcrumbs>
<div class="actions flex-1">
<redaction-dossier-template-actions></redaction-dossier-template-actions>
<iqser-circle-button
[routerLink]="['../..']"
[tooltip]="'common.close' | translate"
icon="iqser:close"
tooltipPosition="below"
></iqser-circle-button>
</div>
</div>
<div class="content-inner">
<div class="overlay-shadow"></div>
<redaction-admin-side-nav type="dossierTemplates"></redaction-admin-side-nav>
<div class="content-container">
<iqser-table
[bulkActions]="bulkActions"
[headerTemplate]="headerTemplate"
[itemSize]="80"
[noDataText]="'watermarks-listing.no-data.title' | translate"
[selectionEnabled]="true"
[tableColumnConfigs]="tableColumnConfigs"
emptyColumnWidth="1fr"
noDataIcon="red:attribute"
></iqser-table>
</div>
</div>
</section>
<ng-template #headerTemplate>
<div class="table-header-actions">
<iqser-icon-button
*ngIf="currentUser.isAdmin"
[label]="'watermarks-listing.add-new' | translate"
[type]="iconButtonTypes.primary"
icon="iqser:plus"
></iqser-icon-button>
</div>
</ng-template>
<ng-template #bulkActions>
<iqser-circle-button
(click)="openConfirmDeleteWatermarkDialog($event)"
*ngIf="currentUser.isAdmin && (listingService.areSomeSelected$ | async)"
[tooltip]="'watermarks-listing.bulk-actions.delete' | translate"
[type]="circleButtonTypes.dark"
icon="iqser:trash"
></iqser-circle-button>
</ng-template>
<ng-template #tableItemTemplate let-entity="entity">
<div *ngIf="cast(entity) as watermark">
<div class="label cell">
<span>{{ watermark.name }}</span>
</div>
<div class="center cell">
<mat-slide-toggle (toggleChange)="toggleStatus(watermark)" [checked]="watermark.enabled" color="primary"></mat-slide-toggle>
</div>
<div class="cell user-column">
<redaction-initials-avatar
[defaultValue]="'unknown' | translate"
[user]="watermark.createdBy || 'system'"
></redaction-initials-avatar>
</div>
<div class="cell">
<div class="small-label">
{{ watermark.dateAdded | date: 'd MMM yyyy' }}
</div>
</div>
<div class="cell">
<div class="small-label">
{{ watermark.dateModified | date: 'd MMM yyyy' }}
</div>
</div>
<div class="cell">
<div class="action-buttons">
<iqser-circle-button
[routerLink]="watermark.routerLink"
[tooltip]="'watermarks-listing.action.edit' | translate"
[type]="circleButtonTypes.dark"
icon="iqser:edit"
></iqser-circle-button>
<iqser-circle-button
(action)="openConfirmDeleteWatermarkDialog($event)"
[tooltip]="'watermarks-listing.action.delete' | translate"
[type]="circleButtonTypes.dark"
icon="iqser:trash"
></iqser-circle-button>
</div>
</div>
</div>
</ng-template>

View File

@ -0,0 +1,72 @@
import { ChangeDetectionStrategy, Component, forwardRef, Injector, OnInit } from '@angular/core';
import {
CircleButtonTypes,
DefaultListingServices,
IconButtonTypes,
ListingComponent,
LoadingService,
TableColumnConfig,
} from '@iqser/common-ui';
import { DOSSIER_TEMPLATE_ID, User, Watermark } from '@red/domain';
import { UserService } 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 { ActivatedRoute } from '@angular/router';
@Component({
templateUrl: './watermarks-listing-screen.component.html',
styleUrls: ['./watermarks-listing-screen.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => WatermarksListingScreenComponent) }],
})
export class WatermarksListingScreenComponent extends ListingComponent<Watermark> implements OnInit {
private readonly _dossierTemplateId: string;
readonly iconButtonTypes = IconButtonTypes;
readonly circleButtonTypes = CircleButtonTypes;
readonly currentUser: User;
readonly tableColumnConfigs: TableColumnConfig<Watermark>[] = [
{ label: _('watermarks-listing.table-col-names.name'), width: '2fr' },
{ label: _('watermarks-listing.table-col-names.status'), class: 'flex-center' },
{ label: _('watermarks-listing.table-col-names.created-by'), class: 'user-column' },
{ label: _('watermarks-listing.table-col-names.created-on') },
{ label: _('watermarks-listing.table-col-names.modified-on') },
];
readonly tableHeaderLabel: string = _('watermarks-listing.table-header.title');
constructor(
protected readonly _injector: Injector,
private readonly _route: ActivatedRoute,
private readonly _userService: UserService,
private readonly _loadingService: LoadingService,
private readonly _watermarkService: WatermarkService,
) {
super(_injector);
this.currentUser = _userService.currentUser;
this._dossierTemplateId = _route.snapshot.paramMap.get(DOSSIER_TEMPLATE_ID);
}
async ngOnInit(): Promise<void> {
await this._loadData();
}
private async _loadData(): Promise<void> {
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) {}
this._loadingService.stop();
}
openAddEditWatermarkDialog(event: MouseEvent): void {}
openConfirmDeleteWatermarkDialog(event: MouseEvent): void {}
toggleStatus(watermark: Watermark): void {}
}

View File

@ -1,6 +1,7 @@
import { Injectable, Injector } from '@angular/core';
import { GenericService, RequiredParam, Validate } from '@iqser/common-ui';
import { GenericService, QueryParam, RequiredParam, Validate } from '@iqser/common-ui';
import { IWatermark } from '@red/domain';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root',
@ -11,17 +12,23 @@ export class WatermarkService extends GenericService<IWatermark> {
}
@Validate()
saveWatermark(@RequiredParam() body: IWatermark, @RequiredParam() dossierTemplateId: string) {
return this._post(body, `${this._defaultModelPath}/${dossierTemplateId}`);
saveWatermark(@RequiredParam() body: IWatermark) {
return this._post(body, `${this._defaultModelPath}`);
}
@Validate()
deleteWatermark(@RequiredParam() dossierTemplateId: string) {
return super.delete({}, `${this._defaultModelPath}/${dossierTemplateId}`);
deleteWatermark(@RequiredParam() watermarkId: string) {
return super.delete({}, `${this._defaultModelPath}/${watermarkId}`);
}
@Validate()
getWatermark(@RequiredParam() dossierTemplateId: string) {
return this._getOne([dossierTemplateId]);
getWatermark(@RequiredParam() watermarkId: string) {
return this._getOne([watermarkId]);
}
@Validate()
getWatermarks(@RequiredParam() dossierTemplateId: string): Observable<IWatermark[]> {
const queryParams: QueryParam[] = [{ key: 'dossierTemplateId', value: dossierTemplateId }];
return this.getAll<IWatermark[]>(this._defaultModelPath, queryParams);
}
}

View File

@ -1,7 +1,7 @@
{
"ADMIN_CONTACT_NAME": null,
"ADMIN_CONTACT_URL": null,
"API_URL": "https://dev-08.iqser.cloud/redaction-gateway-v1",
"API_URL": "https://dev-04.iqser.cloud/redaction-gateway-v1",
"APP_NAME": "RedactManager",
"AUTO_READ_TIME": 3,
"BACKEND_APP_VERSION": "4.4.40",
@ -16,7 +16,7 @@
"MAX_RETRIES_ON_SERVER_ERROR": 3,
"OAUTH_CLIENT_ID": "redaction",
"OAUTH_IDP_HINT": null,
"OAUTH_URL": "https://dev-08.iqser.cloud/auth/realms/redaction",
"OAUTH_URL": "https://dev-04.iqser.cloud/auth/realms/redaction",
"RECENT_PERIOD_IN_HOURS": 24,
"SELECTION_MODE": "structural",
"MANUAL_BASE_URL": "https://docs.redactmanager.com/preview"

View File

@ -186,7 +186,7 @@
"rule-editor": "",
"settings": "Einstellungen",
"user-management": "",
"watermark": ""
"watermarks": ""
},
"annotation-actions": {
"accept-recommendation": {
@ -2084,6 +2084,29 @@
},
"title": "Wasserzeichen"
},
"watermarks-listing": {
"action": {
"delete": "",
"edit": ""
},
"add-new": "",
"bulk-actions": {
"delete": ""
},
"no-data": {
"title": ""
},
"table-col-names": {
"created-by": "",
"created-on": "",
"modified-on": "",
"name": "",
"status": ""
},
"table-header": {
"title": ""
}
},
"workflow": {
"selection": {
"all": "Alle",

View File

@ -186,7 +186,7 @@
"rule-editor": "Rule Editor",
"settings": "Settings",
"user-management": "User Management",
"watermark": "Watermark"
"watermarks": "Watermarks"
},
"annotation-actions": {
"accept-recommendation": {
@ -2084,6 +2084,29 @@
},
"title": "Watermark"
},
"watermarks-listing": {
"action": {
"delete": "Delete",
"edit": "Edit"
},
"add-new": "New Watermark",
"bulk-actions": {
"delete": "Delete Selected Watermarks"
},
"no-data": {
"title": "There are no watermarks yet."
},
"table-col-names": {
"created-by": "Created by",
"created-on": "Created on",
"modified-on": "Modified on",
"name": "Name",
"status": "Status"
},
"table-header": {
"title": "Watermarks"
}
},
"workflow": {
"selection": {
"all": "All",

View File

@ -26,3 +26,4 @@ export * from './lib/text-highlight';
export * from './lib/permissions';
export * from './lib/license';
export * from './lib/digital-signature';
export * from './lib/watermarks';

View File

@ -8,3 +8,4 @@ export type DossierTemplateStatus = keyof typeof DossierTemplateStatuses;
export const DOSSIER_TEMPLATE_ID = 'dossierTemplateId';
export const ENTITY_TYPE = 'entity';
export const WATERMARK_ID = 'watermarkId';

View File

@ -3,7 +3,7 @@ import { IFileAttributeConfig } from './file-attribute-config';
export interface IFileAttributesConfig {
delimiter?: string;
encoding?: string;
keyColumn?: string
keyColumn?: string;
filenameMappingColumnHeaderName?: string;
fileAttributeConfigs?: IFileAttributeConfig[];
}

View File

@ -2,7 +2,6 @@ export * from './sorters/status-sorter';
export * from './breadcrumb-types';
export * from './types';
export * from './rules';
export * from './watermark';
export * from './default-color-type';
export * from './colors';
export * from './view-mode';

View File

@ -0,0 +1,2 @@
export * from './watermark';
export * from './watermark.model';

View File

@ -0,0 +1,30 @@
import { IWatermark } from './watermark';
import { IListable } from '@iqser/common-ui';
export class Watermark implements IListable, IWatermark {
readonly id: string;
readonly dossierTemplateId: string;
readonly name: string;
readonly enabled: boolean;
readonly createdBy: string;
readonly dateAdded: string;
readonly dateModified: string;
constructor(watermarkConfig: IWatermark) {
this.id = watermarkConfig.id;
this.dossierTemplateId = watermarkConfig.dossierTemplateId;
this.name = watermarkConfig.name;
this.enabled = watermarkConfig.enabled;
this.createdBy = watermarkConfig.createdBy;
this.dateAdded = watermarkConfig.dateAdded || '2022-06-20T16:23:49.351Z';
this.dateModified = watermarkConfig.dateModified || '2022-06-20T16:23:49.351Z';
}
get searchKey(): string {
return this.name;
}
get routerLink(): string {
return `/main/admin/dossier-templates/${this.dossierTemplateId}/watermarks/${this.id}`;
}
}

View File

@ -1,10 +1,17 @@
export interface IWatermark {
id: string;
dossierTemplateId: string;
enabled: boolean;
fontSize?: number;
fontType?: string;
hexColor?: string;
opacity?: number;
orientation?: WatermarkOrientation;
text?: string;
name: string;
createdBy: string;
dateAdded: string;
dateModified: string;
}
export const WatermarkOrientations = {