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 b0f171a0f..f34a45611 100644 --- a/apps/red-ui/src/app/modules/admin/admin.module.ts +++ b/apps/red-ui/src/app/modules/admin/admin.module.ts @@ -8,7 +8,6 @@ import { EntitiesListingScreenComponent } from './screens/entities-listing/entit import { DigitalSignatureScreenComponent } from './screens/digital-signature/digital-signature-screen.component'; import { UserListingScreenComponent } from './screens/user-listing/user-listing-screen.component'; import { DossierTemplateBreadcrumbsComponent } from './shared/components/dossier-template-breadcrumbs/dossier-template-breadcrumbs.component'; -import { AddEditCloneDossierTemplateDialogComponent } from './dialogs/add-edit-dossier-template-dialog/add-edit-clone-dossier-template-dialog.component'; import { AddEntityDialogComponent } from './dialogs/add-entity-dialog/add-entity-dialog.component'; import { EditColorDialogComponent } from './dialogs/edit-color-dialog/edit-color-dialog.component'; import { AdminDialogService } from './services/admin-dialog.service'; @@ -57,9 +56,10 @@ import { DossierTemplateActionsComponent } from './shared/components/dossier-tem import { IqserUsersModule } from '@iqser/common-ui/lib/users'; import { SelectComponent } from '@shared/components/select/select.component'; import { PaginationComponent } from '@common-ui/pagination/pagination.component'; +import { AddCloneDossierTemplateDialogComponent } from './dialogs/add-clone-dossier-template-dialog/add-clone-dossier-template-dialog.component'; const dialogs = [ - AddEditCloneDossierTemplateDialogComponent, + AddCloneDossierTemplateDialogComponent, AddEntityDialogComponent, EditColorDialogComponent, SmtpAuthDialogComponent, diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-clone-dossier-template-dialog/add-clone-dossier-template-dialog.component.html b/apps/red-ui/src/app/modules/admin/dialogs/add-clone-dossier-template-dialog/add-clone-dossier-template-dialog.component.html new file mode 100644 index 000000000..eb1b24f9f --- /dev/null +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-clone-dossier-template-dialog/add-clone-dossier-template-dialog.component.html @@ -0,0 +1,48 @@ +
+
+ +
+
+
+ + +
+ +
+ + +
+
+ +
+ + + +
+
+ + +
diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-clone-dossier-template-dialog/add-clone-dossier-template-dialog.component.scss b/apps/red-ui/src/app/modules/admin/dialogs/add-clone-dossier-template-dialog/add-clone-dossier-template-dialog.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-clone-dossier-template-dialog/add-clone-dossier-template-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/add-clone-dossier-template-dialog/add-clone-dossier-template-dialog.component.ts new file mode 100644 index 000000000..f3805d392 --- /dev/null +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-clone-dossier-template-dialog/add-clone-dossier-template-dialog.component.ts @@ -0,0 +1,101 @@ +import { HttpStatusCode } from '@angular/common/http'; +import { Component, Inject } from '@angular/core'; +import { Validators } from '@angular/forms'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { BaseDialogComponent, getConfig, SaveOptions } from '@iqser/common-ui'; +import { DossierTemplate } from '@red/domain'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; +import { Router } from '@angular/router'; + +export interface CloneTemplateData { + dossierTemplateId?: string; +} + +@Component({ + templateUrl: './add-clone-dossier-template-dialog.component.html', + styleUrls: ['./add-clone-dossier-template-dialog.component.scss'], +}) +export class AddCloneDossierTemplateDialogComponent extends BaseDialogComponent { + readonly dossierTemplate?: DossierTemplate; + readonly isDocumine = getConfig().IS_DOCUMINE; + readonly translateParams: { type: string; dossierTemplateName?: string }; + + constructor( + private readonly _dossierTemplatesService: DossierTemplatesService, + private readonly _router: Router, + protected readonly _dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) readonly data: CloneTemplateData, + ) { + super(_dialogRef); + this.dossierTemplate = this._dossierTemplatesService.find(this.data.dossierTemplateId); + + this.translateParams = { + type: this.dossierTemplate ? 'clone' : 'create', + dossierTemplateName: this.dossierTemplate?.name, + }; + + this.form = this.#getForm(); + this.initialFormValue = this.form.getRawValue(); + } + + override get disabled(): boolean { + // Ignore 'changed' value, doesn't make sense in this context + return !this.valid || this._hasErrors(); + } + + async save(options?: SaveOptions): Promise { + let dossierTemplate: DossierTemplate; + this._loadingService.start(); + const body = { + ...this.dossierTemplate, + ...this.form.getRawValue(), + }; + try { + if (this.dossierTemplate) { + dossierTemplate = await this._dossierTemplatesService.clone(this.dossierTemplate.id, body); + } else { + dossierTemplate = await this._dossierTemplatesService.createOrUpdate(body); + } + if (options?.nextAction) { + await this._router.navigate([dossierTemplate.routerLink]); + } + this._dialogRef.close(true); + } catch (error) { + if (error.status === HttpStatusCode.Conflict) { + this._toaster.error(_('add-edit-clone-dossier-template.error.conflict'), { error }); + } else { + this._toaster.rawError(error.error.message); + } + } + this._loadingService.stop(); + } + + #getForm() { + return this._formBuilder.group({ + name: [this.dossierTemplate ? this.#getCloneName(this.dossierTemplate) : undefined, Validators.required], + description: [this.dossierTemplate?.description], + }); + } + + #getCloneName(initialTemplate: DossierTemplate): string { + const templateName = initialTemplate.name.trim(); + let nameOfClonedTemplate: string = templateName.split('Copy of ').filter(n => n)[0]; + nameOfClonedTemplate = nameOfClonedTemplate.split(/\(\s*\d+\s*\)$/)[0].trim(); + const allTemplatesNames = this._dossierTemplatesService.all.map(t => t.name); + + let clonesCount = 0; + for (const name of allTemplatesNames) { + const splitName = name.split(nameOfClonedTemplate); + const suffixRegExp = new RegExp(/^\(\s*\d+\s*\)$/); + if (splitName[0] === 'Copy of ' && (splitName[1].trim().match(suffixRegExp) || splitName[1] === '')) { + clonesCount++; + } + } + + if (clonesCount >= 1) { + return `Copy of ${nameOfClonedTemplate} (${clonesCount})`; + } + return `Copy of ${nameOfClonedTemplate}`; + } +} diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-clone-dossier-template-dialog.component.html b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-clone-dossier-template-dialog.component.html deleted file mode 100644 index 8d93d72aa..000000000 --- a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-clone-dossier-template-dialog.component.html +++ /dev/null @@ -1,159 +0,0 @@ -
-
- -
-
-
- - -
- -
- - -
- -
-
- - {{ 'add-edit-clone-dossier-template.form.valid-from' | translate }} - - - - {{ 'add-edit-clone-dossier-template.form.valid-to' | translate }} - -
- -
-
- - - - - - - -
- -
- - - - - - - -
-
-
- -
-

- {{ 'add-edit-clone-dossier-template.form.apply-updates-default.heading' | translate }} -

-
- - {{ 'add-edit-clone-dossier-template.form.apply-updates-default.description' | translate }} - -
-
- -
-
-

{{ 'download-includes' | translate }}

- -
- -
-
- -
-

- {{ 'add-edit-clone-dossier-template.form.upload-settings.heading' | translate }} -

-
- - {{ 'add-edit-clone-dossier-template.form.upload-settings.ocr-by-default' | translate }} - -
-
- - {{ 'add-edit-clone-dossier-template.form.upload-settings.remove-watermark' | translate }} - -
-
-
- -
-

{{ 'add-edit-clone-dossier-template.form.hidden-text.heading' | translate }}

-
-
- - {{ 'add-edit-clone-dossier-template.form.hidden-text.title' | translate }} - -
{{ 'add-edit-clone-dossier-template.form.hidden-text.description' | translate }}
-
-
- - {{ 'add-edit-clone-dossier-template.form.image-metadata.title' | translate }} - -
{{ 'add-edit-clone-dossier-template.form.image-metadata.description' | translate }}
-
-
- - {{ 'add-edit-clone-dossier-template.form.overlapping-elements.title' | translate }} - -
- {{ 'add-edit-clone-dossier-template.form.overlapping-elements.description' | translate }} -
-
-
-
-
- -
- - - -
-
- - -
diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-clone-dossier-template-dialog.component.scss b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-clone-dossier-template-dialog.component.scss deleted file mode 100644 index fc21cb238..000000000 --- a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-clone-dossier-template-dialog.component.scss +++ /dev/null @@ -1,58 +0,0 @@ -.validity { - width: 230px; - display: flex; - - > div { - display: flex; - flex-direction: column; - margin-top: 16px; - - mat-checkbox { - margin-right: 16px; - height: 100%; - align-items: center; - display: flex; - min-height: 42px; - } - - .iqser-input-group { - min-height: 42px; - justify-content: center; - } - } -} - -redaction-select { - flex: 1; -} - -.download-includes { - margin: 16px 0 10px; - font-weight: 500; -} - -.hidden-elements { - display: flex; - gap: 40px; - - .iqser-input-group { - margin-top: 0; - flex: 1; - - mat-checkbox { - font-weight: 500; - } - - .info { - margin-left: 24px; - } - } -} - -.half-flex-basis { - flex-basis: 50%; -} - -.pl-75 { - padding: 0 0 0 75px; -} diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-clone-dossier-template-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-clone-dossier-template-dialog.component.ts deleted file mode 100644 index d7b154c2c..000000000 --- a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-clone-dossier-template-dialog.component.ts +++ /dev/null @@ -1,173 +0,0 @@ -import { HttpStatusCode } from '@angular/common/http'; -import { Component, Inject } from '@angular/core'; -import { AbstractControl, Validators } from '@angular/forms'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -import { BaseDialogComponent, getConfig } from '@iqser/common-ui'; -import { DossierTemplate, IDossierTemplate } from '@red/domain'; -import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; -import { downloadTypesTranslations } from '@translations/download-types-translations'; -import { applyIntervalConstraints } from '@utils/date-inputs-utils'; -import dayjs, { Dayjs } from 'dayjs'; - -interface EditCloneTemplateData { - dossierTemplateId: string; - clone?: boolean; -} - -const downloadTypes = ['ORIGINAL', 'PREVIEW', 'DELTA_PREVIEW', 'REDACTED'].map(type => ({ - key: type, - label: downloadTypesTranslations[type], -})); - -@Component({ - templateUrl: './add-edit-clone-dossier-template-dialog.component.html', - styleUrls: ['./add-edit-clone-dossier-template-dialog.component.scss'], -}) -export class AddEditCloneDossierTemplateDialogComponent extends BaseDialogComponent { - readonly isDocumine = getConfig().IS_DOCUMINE; - hasValidFrom: boolean; - hasValidTo: boolean; - readonly downloadTypes = downloadTypes; - readonly dossierTemplate: DossierTemplate; - private _previousValidFrom: Dayjs; - private _previousValidTo: Dayjs; - private _lastValidFrom: Dayjs; - private _lastValidTo: Dayjs; - - get disabled(): boolean { - if (!this.data?.clone) { - return super.disabled; - } - return !this.valid; - } - - get translateParams() { - return { - type: this.dossierTemplate ? (this.data.clone ? 'clone' : 'edit') : 'create', - name: this.dossierTemplate?.name, - }; - } - - constructor( - private readonly _dossierTemplatesService: DossierTemplatesService, - protected readonly _dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) readonly data: EditCloneTemplateData, - ) { - super(_dialogRef, !!data && !data.clone); - this.dossierTemplate = this._dossierTemplatesService.find(this.data?.dossierTemplateId); - this.form = this.#getForm(); - this.initialFormValue = this.form.getRawValue(); - this.hasValidFrom = !!this.dossierTemplate?.validFrom; - this.hasValidTo = !!this.dossierTemplate?.validTo; - - this._previousValidFrom = this._lastValidFrom = this.form.get('validFrom').value; - this._previousValidTo = this._lastValidTo = this.form.get('validTo').value; - } - - toggleHasValid(extremity: string) { - if (extremity === 'from') { - this.hasValidFrom = !this.hasValidFrom; - this.form.controls['validFrom'].setValue(this.hasValidFrom ? this._lastValidFrom : null); - } else { - this.hasValidTo = !this.hasValidTo; - this.form.controls['validTo'].setValue(this.hasValidTo ? this._lastValidTo : null); - } - this.applyValidityIntervalConstraints(); - } - - async save() { - this._loadingService.start(); - const dossierTemplate = { - dossierTemplateId: this.dossierTemplate?.dossierTemplateId, - ...this.form.getRawValue(), - validFrom: this.hasValidFrom ? this.form.get('validFrom').value : null, - validTo: this.hasValidTo ? this.form.get('validTo').value : null, - } as IDossierTemplate; - - try { - if (this.data?.clone) { - await this._dossierTemplatesService.clone(this.dossierTemplate.id, dossierTemplate); - } else { - await this._dossierTemplatesService.createOrUpdate(dossierTemplate); - } - this._dialogRef.close(true); - } catch (error) { - if (error.status === HttpStatusCode.Conflict) { - this._toaster.error(_('add-edit-clone-dossier-template.error.conflict'), { error }); - } else { - this._toaster.rawError(error.error.message); - } - } - this._loadingService.stop(); - } - - applyValidityIntervalConstraints(): void { - const formValue = this.form.value; - applyIntervalConstraints(formValue, this._previousValidFrom, this._previousValidTo, this.form, 'validFrom', 'validTo'); - - this._previousValidFrom = this.form.get('validFrom').value; - this._previousValidTo = this.form.get('validTo').value; - this._lastValidFrom = this._previousValidFrom || this._lastValidFrom; - this._lastValidTo = this._previousValidTo || this._lastValidTo; - } - - #getForm() { - return this._formBuilder.group({ - name: [this.#getCloneName(), Validators.required], - description: [this.dossierTemplate?.description], - validFrom: [ - this.dossierTemplate?.validFrom ? dayjs(this.dossierTemplate?.validFrom) : null, - this.#requiredIfValidator(() => this.hasValidFrom), - ], - validTo: [ - this.dossierTemplate?.validTo ? dayjs(this.dossierTemplate?.validTo) : null, - this.#requiredIfValidator(() => this.hasValidTo), - ], - applyDictionaryUpdatesToAllDossiersByDefault: [this.dossierTemplate?.applyDictionaryUpdatesToAllDossiersByDefault], - ocrByDefault: [this.dossierTemplate?.ocrByDefault], - removeWatermark: [this.dossierTemplate?.removeWatermark], - downloadFileTypes: [this.dossierTemplate?.downloadFileTypes || ['PREVIEW', 'REDACTED']], - keepHiddenText: [this.dossierTemplate?.keepHiddenText], - keepImageMetadata: [this.dossierTemplate?.keepImageMetadata], - keepOverlappingObjects: [this.dossierTemplate?.keepOverlappingObjects], - }); - } - - #getCloneName(): string { - if (!this.data?.clone) { - return this.dossierTemplate?.name; - } - - const templateName = this.dossierTemplate.name.trim(); - let nameOfClonedTemplate: string = templateName.split('Copy of ').filter(n => n)[0]; - nameOfClonedTemplate = nameOfClonedTemplate.split(/\(\s*\d+\s*\)$/)[0].trim(); - const allTemplatesNames = this._dossierTemplatesService.all.map(t => t.name); - - let clonesCount = 0; - for (const name of allTemplatesNames) { - const splitName = name.split(nameOfClonedTemplate); - const suffixRegExp = new RegExp(/^\(\s*\d+\s*\)$/); - if (splitName[0] === 'Copy of ' && (splitName[1].trim().match(suffixRegExp) || splitName[1] === '')) { - clonesCount++; - } - } - - if (clonesCount >= 1) { - return `Copy of ${nameOfClonedTemplate} (${clonesCount})`; - } - return `Copy of ${nameOfClonedTemplate}`; - } - - #requiredIfValidator(predicate) { - return (formControl: AbstractControl) => { - if (!formControl.parent) { - return null; - } - if (predicate()) { - return Validators.required(formControl); - } - return null; - }; - } -} diff --git a/apps/red-ui/src/app/modules/admin/screens/dossier-templates-listing/dossier-templates-listing-screen/dossier-templates-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/dossier-templates-listing/dossier-templates-listing-screen/dossier-templates-listing-screen.component.ts index 40c043d22..fa61c02bf 100644 --- a/apps/red-ui/src/app/modules/admin/screens/dossier-templates-listing/dossier-templates-listing-screen/dossier-templates-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/dossier-templates-listing/dossier-templates-listing-screen/dossier-templates-listing-screen.component.ts @@ -63,7 +63,7 @@ export class DossierTemplatesListingScreenComponent extends ListingComponent d.dossierTemplateId)) { diff --git a/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-details/dossier-template-details.component.html b/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-details/dossier-template-details.component.html new file mode 100644 index 000000000..0e328765d --- /dev/null +++ b/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-details/dossier-template-details.component.html @@ -0,0 +1,54 @@ +
+ +
{{ ctx.dossierTemplate.name }}
+ +
+
+
+ + +
+ +
+
+ + {{ translations[ctx.dossierTemplate.dossierTemplateStatus] | translate }} +
+ +
+ + {{ 'dossier-template-info-screen.entities' | translate: { count: ctx.stats.numberOfDictionaries } }} +
+ +
+ + +
+ +
+ + +
+ +
+ + {{ 'dossier-template-info-screen.entries' | translate: { count: ctx.stats.numberOfEntries } }} +
+ +
+ + +
+ +
+ + +
+
+
+
+
diff --git a/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-details/dossier-template-details.component.scss b/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-details/dossier-template-details.component.scss new file mode 100644 index 000000000..dd00e21c8 --- /dev/null +++ b/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-details/dossier-template-details.component.scss @@ -0,0 +1,20 @@ +@use 'common-mixins'; + +.stats-subtitle { + display: grid; + grid-template-columns: repeat(3, max-content); + grid-row-gap: 8px; + grid-column-gap: 8px; + height: fit-content; +} + +.info-wrapper { + display: flex; + align-items: center; +} + +.created-by-wrapper { + border-right: 1px solid var(--iqser-separator); + padding-right: 24px; + margin-right: 24px; +} diff --git a/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-details/dossier-template-details.component.ts b/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-details/dossier-template-details.component.ts new file mode 100644 index 000000000..2ddbd44f7 --- /dev/null +++ b/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-details/dossier-template-details.component.ts @@ -0,0 +1,36 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { ContextComponent } from '@iqser/common-ui/lib/utils'; +import { type DossierTemplate, type DossierTemplateStats } from '@red/domain'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; +import { DossierTemplateStatsService } from '@services/entity-services/dossier-template-stats.service'; +import { dossierTemplateStatusTranslations } from '@translations/dossier-template-status-translations'; + +interface Context { + readonly dossierTemplate: DossierTemplate; + readonly stats: DossierTemplateStats; +} + +@Component({ + selector: 'redaction-dossier-template-details', + templateUrl: './dossier-template-details.component.html', + styleUrls: ['./dossier-template-details.component.scss'], +}) +export class DossierTemplateDetailsComponent extends ContextComponent implements OnInit { + readonly translations = dossierTemplateStatusTranslations; + + @Input({ required: true }) dossierTemplateId: string; + + constructor( + private readonly _dossierTemplatesService: DossierTemplatesService, + private readonly _dossierTemplateStatsService: DossierTemplateStatsService, + ) { + super(); + } + + ngOnInit() { + super._initContext({ + dossierTemplate: this._dossierTemplatesService.getEntityChanged$(this.dossierTemplateId), + stats: this._dossierTemplateStatsService.watch$(this.dossierTemplateId), + }); + } +} diff --git a/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-info-screen/dossier-template-info-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-info-screen/dossier-template-info-screen.component.html new file mode 100644 index 000000000..94e7dc00a --- /dev/null +++ b/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-info-screen/dossier-template-info-screen.component.html @@ -0,0 +1,150 @@ +
+
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ + {{ 'add-edit-clone-dossier-template.form.valid-from' | translate }} + + +
+ + + + + + + +
+
+ +
+ + {{ 'add-edit-clone-dossier-template.form.valid-to' | translate }} + +
+ + + + + + + +
+
+
+ +
+
+ {{ 'add-edit-clone-dossier-template.form.apply-updates-default.heading' | translate }} +
+
+ + {{ 'add-edit-clone-dossier-template.form.apply-updates-default.description' | translate }} + +
+
+ +
+
{{ 'download-includes' | translate }}
+ + +
+ +
+
+ {{ 'add-edit-clone-dossier-template.form.upload-settings.heading' | translate }} +
+
+ + {{ 'add-edit-clone-dossier-template.form.upload-settings.ocr-by-default' | translate }} + +
+
+ + {{ 'add-edit-clone-dossier-template.form.upload-settings.remove-watermark' | translate }} + +
+
+ +
+
{{ 'add-edit-clone-dossier-template.form.hidden-text.heading' | translate }}
+
+ + {{ 'add-edit-clone-dossier-template.form.hidden-text.title' | translate }} + +
{{ 'add-edit-clone-dossier-template.form.hidden-text.description' | translate }}
+
+
+ + {{ 'add-edit-clone-dossier-template.form.image-metadata.title' | translate }} + +
{{ 'add-edit-clone-dossier-template.form.image-metadata.description' | translate }}
+
+
+ + {{ 'add-edit-clone-dossier-template.form.overlapping-elements.title' | translate }} + +
+ {{ 'add-edit-clone-dossier-template.form.overlapping-elements.description' | translate }} +
+
+
+
+ +
+ +
+
+
diff --git a/apps/red-ui/src/app/modules/admin/screens/info/info-screen/dossier-template-info-screen.component.scss b/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-info-screen/dossier-template-info-screen.component.scss similarity index 51% rename from apps/red-ui/src/app/modules/admin/screens/info/info-screen/dossier-template-info-screen.component.scss rename to apps/red-ui/src/app/modules/admin/screens/info/dossier-template-info-screen/dossier-template-info-screen.component.scss index 857abc06a..d16588a5d 100644 --- a/apps/red-ui/src/app/modules/admin/screens/info/info-screen/dossier-template-info-screen.component.scss +++ b/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-info-screen/dossier-template-info-screen.component.scss @@ -1,25 +1,13 @@ @use 'common-mixins'; -:host { - display: flex; - flex-grow: 1; - overflow: hidden; -} - .content-container { - flex: 1; - padding: 30px; + display: flex; + justify-content: center; + background-color: var(--iqser-alt-background); overflow: auto; @include common-mixins.scroll-bar; } -.heading { - display: flex; - align-items: center; - margin-top: 40px; - margin-bottom: 8px; -} - .stats-subtitle { margin-top: 16px; display: grid; @@ -28,6 +16,23 @@ grid-column-gap: 40px; } -.template-description { - margin-top: 10px; +.validity { + display: flex; + min-height: 42px; + gap: 40px; + + > div { + display: flex; + align-items: center; + gap: 8px; + } +} + +redaction-select { + flex: 1; +} + +.hidden-elements .info { + margin-left: 24px; + margin-top: 4px; } diff --git a/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-info-screen/dossier-template-info-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-info-screen/dossier-template-info-screen.component.ts new file mode 100644 index 000000000..3cf61bb37 --- /dev/null +++ b/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-info-screen/dossier-template-info-screen.component.ts @@ -0,0 +1,139 @@ +import { Component, OnInit, signal, untracked, WritableSignal } from '@angular/core'; +import { BaseFormComponent, getConfig, IconButtonTypes, LoadingService, Toaster } from '@iqser/common-ui'; +import { getParam } from '@iqser/common-ui/lib/utils'; +import { DOSSIER_TEMPLATE_ID, type DossierTemplate, IDossierTemplate } from '@red/domain'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; +import { dossierTemplateStatusTranslations } from '@translations/dossier-template-status-translations'; +import dayjs, { Dayjs } from 'dayjs'; +import { HttpStatusCode } from '@angular/common/http'; +import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { applyIntervalConstraints } from '@utils/date-inputs-utils'; +import { AbstractControl, UntypedFormBuilder, Validators } from '@angular/forms'; +import { downloadTypesTranslations } from '@translations/download-types-translations'; +import { Observable } from 'rxjs'; + +const downloadTypes = ['ORIGINAL', 'PREVIEW', 'DELTA_PREVIEW', 'REDACTED'].map(type => ({ + key: type, + label: downloadTypesTranslations[type], +})); + +@Component({ + templateUrl: './dossier-template-info-screen.component.html', + styleUrls: ['./dossier-template-info-screen.component.scss'], +}) +export class DossierTemplateInfoScreenComponent extends BaseFormComponent implements OnInit { + readonly translations = dossierTemplateStatusTranslations; + readonly iconButtonTypes = IconButtonTypes; + readonly isDocumine = getConfig().IS_DOCUMINE; + readonly downloadTypes = downloadTypes; + + readonly dossierTemplate$: Observable; + readonly dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); + readonly hasValidFrom: WritableSignal; + readonly hasValidTo: WritableSignal; + private _previousValidFrom: Dayjs; + private _previousValidTo: Dayjs; + private _lastValidFrom: Dayjs; + private _lastValidTo: Dayjs; + + constructor( + private readonly _dossierTemplatesService: DossierTemplatesService, + private readonly _loadingService: LoadingService, + private readonly _toaster: Toaster, + private readonly _formBuilder: UntypedFormBuilder, + ) { + super(); + this.dossierTemplate$ = this._dossierTemplatesService.get(this.dossierTemplateId); + this.form = this.#getForm(this._dossierTemplatesService.find(this.dossierTemplateId)); + this.initialFormValue = this.form.getRawValue(); + + this.hasValidFrom = signal(!!this.form.get('validFrom').value); + this.hasValidTo = signal(!!this.form.get('validTo').value); + + this._previousValidFrom = this._lastValidFrom = this.form.get('validFrom').value; + this._previousValidTo = this._lastValidTo = this.form.get('validTo').value; + } + + ngOnInit() { + this._loadingService.stop(); + } + + toggleHasValid(extremity: 'from' | 'to') { + if (extremity === 'from') { + const prevValue = untracked(this.hasValidFrom); + this.hasValidFrom.set(!prevValue); + this.form.controls['validFrom'].setValue(!prevValue ? this._lastValidFrom : null); + } else { + const prevValue = untracked(this.hasValidTo); + this.hasValidTo.set(!prevValue); + this.form.controls['validTo'].setValue(!prevValue ? this._lastValidTo : null); + } + this.applyValidityIntervalConstraints(); + } + + async save() { + this._loadingService.start(); + const dossierTemplate = { + dossierTemplateId: this.dossierTemplateId, + ...this.form.getRawValue(), + validFrom: this.hasValidFrom() ? this.form.get('validFrom').value : null, + validTo: this.hasValidTo() ? this.form.get('validTo').value : null, + } as IDossierTemplate; + + try { + await this._dossierTemplatesService.createOrUpdate(dossierTemplate); + this.initialFormValue = this.form.getRawValue(); + } catch (error) { + if (error.status === HttpStatusCode.Conflict) { + this._toaster.error(_('add-edit-clone-dossier-template.error.conflict'), { error }); + } else { + this._toaster.rawError(error.error.message); + } + } + this._loadingService.stop(); + } + + applyValidityIntervalConstraints(): void { + const formValue = this.form.value; + applyIntervalConstraints(formValue, this._previousValidFrom, this._previousValidTo, this.form, 'validFrom', 'validTo'); + + this._previousValidFrom = this.form.get('validFrom').value; + this._previousValidTo = this.form.get('validTo').value; + this._lastValidFrom = this._previousValidFrom || this._lastValidFrom; + this._lastValidTo = this._previousValidTo || this._lastValidTo; + } + + #getForm(dossierTemplate: DossierTemplate) { + return this._formBuilder.group({ + name: [dossierTemplate.name, Validators.required], + description: [dossierTemplate?.description], + validFrom: [ + dossierTemplate?.validFrom ? dayjs(dossierTemplate?.validFrom) : null, + this.#requiredIfValidator(() => this.hasValidFrom()), + ], + validTo: [ + dossierTemplate?.validTo ? dayjs(dossierTemplate?.validTo) : null, + this.#requiredIfValidator(() => this.hasValidTo()), + ], + applyDictionaryUpdatesToAllDossiersByDefault: [dossierTemplate?.applyDictionaryUpdatesToAllDossiersByDefault], + ocrByDefault: [dossierTemplate?.ocrByDefault], + removeWatermark: [dossierTemplate?.removeWatermark], + downloadFileTypes: [dossierTemplate?.downloadFileTypes || ['PREVIEW', 'REDACTED']], + keepHiddenText: [dossierTemplate?.keepHiddenText], + keepImageMetadata: [dossierTemplate?.keepImageMetadata], + keepOverlappingObjects: [dossierTemplate?.keepOverlappingObjects], + }); + } + + #requiredIfValidator(predicate: () => boolean) { + return (formControl: AbstractControl) => { + if (!formControl.parent) { + return null; + } + if (predicate()) { + return Validators.required(formControl); + } + return null; + }; + } +} diff --git a/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-info.module.ts b/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-info.module.ts index 6c2f49351..adb906247 100644 --- a/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-info.module.ts +++ b/apps/red-ui/src/app/modules/admin/screens/info/dossier-template-info.module.ts @@ -1,16 +1,18 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { DossierTemplateInfoScreenComponent } from './info-screen/dossier-template-info-screen.component'; +import { DossierTemplateInfoScreenComponent } from './dossier-template-info-screen/dossier-template-info-screen.component'; import { RouterModule } from '@angular/router'; import { SharedModule } from '@shared/shared.module'; -import { HasScrollbarDirective, IqserHelpModeModule } from '@iqser/common-ui'; +import { CircleButtonComponent, HasScrollbarDirective, IconButtonComponent, IqserHelpModeModule } from '@iqser/common-ui'; import { TranslateModule } from '@ngx-translate/core'; import { IqserUsersModule } from '@iqser/common-ui/lib/users'; +import { SelectComponent } from '@shared/components/select/select.component'; +import { DossierTemplateDetailsComponent } from './dossier-template-details/dossier-template-details.component'; const routes = [{ path: '', component: DossierTemplateInfoScreenComponent }]; @NgModule({ - declarations: [DossierTemplateInfoScreenComponent], + declarations: [DossierTemplateInfoScreenComponent, DossierTemplateDetailsComponent], imports: [ RouterModule.forChild(routes), CommonModule, @@ -19,6 +21,9 @@ const routes = [{ path: '', component: DossierTemplateInfoScreenComponent }]; TranslateModule, IqserHelpModeModule, HasScrollbarDirective, + CircleButtonComponent, + IconButtonComponent, + SelectComponent, ], }) export class DossierTemplateInfoModule {} diff --git a/apps/red-ui/src/app/modules/admin/screens/info/info-screen/dossier-template-info-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/info/info-screen/dossier-template-info-screen.component.html deleted file mode 100644 index ab6d52248..000000000 --- a/apps/red-ui/src/app/modules/admin/screens/info/info-screen/dossier-template-info-screen.component.html +++ /dev/null @@ -1,46 +0,0 @@ -
-
{{ ctx.dossierTemplate.name }}
- -
- - - -
-
- - {{ translations[ctx.dossierTemplate.dossierTemplateStatus] | translate }} -
- -
- - {{ 'dossier-template-info-screen.entities' | translate : { count: ctx.stats.numberOfDictionaries } }} -
- -
- - -
- -
- - -
- -
- - {{ 'dossier-template-info-screen.entries' | translate : { count: ctx.stats.numberOfEntries } }} -
- -
- - -
- -
- - -
-
- -
{{ ctx.dossierTemplate.description }}
-
diff --git a/apps/red-ui/src/app/modules/admin/screens/info/info-screen/dossier-template-info-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/info/info-screen/dossier-template-info-screen.component.ts deleted file mode 100644 index bf9ccf1cd..000000000 --- a/apps/red-ui/src/app/modules/admin/screens/info/info-screen/dossier-template-info-screen.component.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Component, inject, OnInit } from '@angular/core'; -import { LoadingService } from '@iqser/common-ui'; -import { ContextComponent, getParam } from '@iqser/common-ui/lib/utils'; -import { DOSSIER_TEMPLATE_ID, type DossierTemplate, type DossierTemplateStats } from '@red/domain'; -import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; -import { DossierTemplateStatsService } from '@services/entity-services/dossier-template-stats.service'; -import { dossierTemplateStatusTranslations } from '@translations/dossier-template-status-translations'; - -interface Context { - readonly dossierTemplate: DossierTemplate; - readonly stats: DossierTemplateStats; -} - -@Component({ - templateUrl: './dossier-template-info-screen.component.html', - styleUrls: ['./dossier-template-info-screen.component.scss'], -}) -export class DossierTemplateInfoScreenComponent extends ContextComponent implements OnInit { - readonly #loadingService = inject(LoadingService); - readonly translations = dossierTemplateStatusTranslations; - - constructor(dossierTemplatesService: DossierTemplatesService, dossierTemplateStatsService: DossierTemplateStatsService) { - super(); - const dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); - super._initContext({ - dossierTemplate: dossierTemplatesService.getEntityChanged$(dossierTemplateId), - stats: dossierTemplateStatsService.watch$(dossierTemplateId), - }); - } - - ngOnInit() { - this.#loadingService.stop(); - } -} diff --git a/apps/red-ui/src/app/modules/admin/services/admin-dialog.service.ts b/apps/red-ui/src/app/modules/admin/services/admin-dialog.service.ts index 36f0984b6..f627f6b78 100644 --- a/apps/red-ui/src/app/modules/admin/services/admin-dialog.service.ts +++ b/apps/red-ui/src/app/modules/admin/services/admin-dialog.service.ts @@ -1,7 +1,6 @@ import { Injectable, TemplateRef } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { AddEntityDialogComponent } from '../dialogs/add-entity-dialog/add-entity-dialog.component'; -import { AddEditCloneDossierTemplateDialogComponent } from '../dialogs/add-edit-dossier-template-dialog/add-edit-clone-dossier-template-dialog.component'; import { EditColorDialogComponent } from '../dialogs/edit-color-dialog/edit-color-dialog.component'; import { SmtpAuthDialogComponent } from '../dialogs/smtp-auth-dialog/smtp-auth-dialog.component'; import { AddEditUserDialogComponent } from '../dialogs/add-edit-user-dialog/add-edit-user-dialog.component'; @@ -23,6 +22,7 @@ import { IDossierAttributeConfig, IFileAttributeConfig, IReportTemplate } from ' import { ReportTemplateService } from '@services/report-template.service'; import { ConfigureCertificateDialogComponent } from '../dialogs/configure-digital-signature-dialog/configure-certificate-dialog.component'; import { AuditInfoDialogComponent } from '../dialogs/audit-info-dialog/audit-info-dialog.component'; +import { AddCloneDossierTemplateDialogComponent } from '../dialogs/add-clone-dossier-template-dialog/add-clone-dossier-template-dialog.component'; type DialogType = | 'confirm' @@ -30,7 +30,7 @@ type DialogType = | 'editColor' | 'addEditUser' | 'smtpAuthConfig' - | 'addEditCloneDossierTemplate' + | 'addCloneDossierTemplate' | 'auditInfo' | 'uploadDictionary' | 'configureCertificate'; @@ -58,9 +58,9 @@ export class AdminDialogService extends DialogService { component: SmtpAuthDialogComponent, dialogConfig: { autoFocus: true }, }, - addEditCloneDossierTemplate: { - component: AddEditCloneDossierTemplateDialogComponent, - dialogConfig: { width: '950px', autoFocus: true }, + addCloneDossierTemplate: { + component: AddCloneDossierTemplateDialogComponent, + dialogConfig: { autoFocus: true }, }, uploadDictionary: { component: UploadDictionaryDialogComponent, diff --git a/apps/red-ui/src/app/modules/admin/shared/components/dossier-template-actions/dossier-template-actions.component.html b/apps/red-ui/src/app/modules/admin/shared/components/dossier-template-actions/dossier-template-actions.component.html index 14e22b2bb..c20f6e637 100644 --- a/apps/red-ui/src/app/modules/admin/shared/components/dossier-template-actions/dossier-template-actions.component.html +++ b/apps/red-ui/src/app/modules/admin/shared/components/dossier-template-actions/dossier-template-actions.component.html @@ -8,15 +8,15 @@ > diff --git a/apps/red-ui/src/app/modules/admin/shared/components/dossier-template-actions/dossier-template-actions.component.ts b/apps/red-ui/src/app/modules/admin/shared/components/dossier-template-actions/dossier-template-actions.component.ts index 468cb8e48..266e53a0c 100644 --- a/apps/red-ui/src/app/modules/admin/shared/components/dossier-template-actions/dossier-template-actions.component.ts +++ b/apps/red-ui/src/app/modules/admin/shared/components/dossier-template-actions/dossier-template-actions.component.ts @@ -1,10 +1,10 @@ import { NgIf } from '@angular/common'; import { Component, Input, OnInit } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; +import { ActivatedRoute, Router, RouterLink } from '@angular/router'; import { CircleButtonComponent, IqserHelpModeModule, LoadingService } from '@iqser/common-ui'; import { getCurrentUser } from '@iqser/common-ui/lib/users'; import { TranslateModule } from '@ngx-translate/core'; -import { DOSSIER_TEMPLATE_ID, type User } from '@red/domain'; +import { DOSSIER_TEMPLATE_ID, DossierTemplate, type User } from '@red/domain'; import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { firstValueFrom } from 'rxjs'; import { AdminDialogService } from '../../../services/admin-dialog.service'; @@ -14,12 +14,13 @@ import { AdminDialogService } from '../../../services/admin-dialog.service'; templateUrl: './dossier-template-actions.component.html', styleUrls: ['./dossier-template-actions.component.scss'], standalone: true, - imports: [NgIf, IqserHelpModeModule, CircleButtonComponent, TranslateModule], + imports: [NgIf, IqserHelpModeModule, CircleButtonComponent, TranslateModule, RouterLink], }) export class DossierTemplateActionsComponent implements OnInit { @Input() dossierTemplateId: string; readonly currentUser = getCurrentUser(); + dossierTemplate: DossierTemplate; constructor( private readonly _router: Router, @@ -31,10 +32,11 @@ export class DossierTemplateActionsComponent implements OnInit { ngOnInit() { this.dossierTemplateId ??= this._route.snapshot.paramMap.get(DOSSIER_TEMPLATE_ID); + this.dossierTemplate = this._dossierTemplatesService.find(this.dossierTemplateId); } - openEditCloneDossierTemplateDialog(clone: boolean = false) { - this._dialogService.openDialog('addEditCloneDossierTemplate', { dossierTemplateId: this.dossierTemplateId, clone }); + openCloneDossierTemplateDialog() { + this._dialogService.openDialog('addCloneDossierTemplate', { dossierTemplateId: this.dossierTemplateId }); } openDeleteDossierTemplateDialog() { diff --git a/apps/red-ui/src/app/modules/pdf-viewer/services/document-viewer.service.ts b/apps/red-ui/src/app/modules/pdf-viewer/services/document-viewer.service.ts index 4e6679ea3..fc85b35ce 100644 --- a/apps/red-ui/src/app/modules/pdf-viewer/services/document-viewer.service.ts +++ b/apps/red-ui/src/app/modules/pdf-viewer/services/document-viewer.service.ts @@ -105,9 +105,9 @@ export class REDDocumentViewer { this.#pdf.instance.UI.setAnnotationContentOverlayHandler(() => (current ? undefined : false)); } - init(document: DocumentViewer) { + init(document: DocumentViewer, zOrderFlag: number) { this.#document = document; - this.#listenForDocEvents(); + this.#listenForDocEvents(zOrderFlag); this.keyUp$ = this.#keyUp$; } @@ -160,7 +160,7 @@ export class REDDocumentViewer { } } - #listenForDocEvents() { + #listenForDocEvents(zOrderFlag: number) { this.#document.addEventListener('textSelected', (quads: Quad, selectedText: string, pageNumber: number) => { this.selectedText$.next(selectedText); this.#disableTextPopupIfCompareMode(pageNumber); @@ -180,6 +180,8 @@ export class REDDocumentViewer { this.#document.addEventListener('documentLoaded', () => { this.#logger.info('[PDF] Document loaded'); + this.document.setTextExtractorProcessingFlags([zOrderFlag]); + this.#pdf.runWithCleanup(() => { this.#flattenAnnotations().then(); this.#setCurrentPage(); diff --git a/apps/red-ui/src/app/modules/pdf-viewer/services/webviewer-loaded.guard.ts b/apps/red-ui/src/app/modules/pdf-viewer/services/webviewer-loaded.guard.ts index 2f6491588..06166a4fc 100644 --- a/apps/red-ui/src/app/modules/pdf-viewer/services/webviewer-loaded.guard.ts +++ b/apps/red-ui/src/app/modules/pdf-viewer/services/webviewer-loaded.guard.ts @@ -35,7 +35,7 @@ export function webViewerLoadedGuard(): CanActivateFn | ResolveFn { } annotationManager.init(instance.Core.annotationManager); - documentViewer.init(instance.Core.documentViewer); + documentViewer.init(instance.Core.documentViewer, instance.Core.TextExtractorProcessingFlags.EXTRACT_USING_ZORDER); viewerHeaderService.init(); return !!pdf.instance; diff --git a/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/edit-dossier-dialog.component.html b/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/edit-dossier-dialog.component.html index e4961c79b..82dc74088 100644 --- a/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/edit-dossier-dialog.component.html +++ b/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/edit-dossier-dialog.component.html @@ -1,18 +1,18 @@ -
+
-
+
{{ item.sideNavTitle || item.title | translate }} @@ -22,46 +22,46 @@
-
-
- {{ activeNavItem.title | translate }} +
+
+ {{ activeNavItem().title | translate }}
-
+
{{ 'readonly' | translate }}
- +
; + + readonly activeNav: WritableSignal
; + readonly dossier: Signal; + readonly navItems: Signal; + readonly activeNavItem: Signal; + readonly activeComponent: Signal; + readonly noPaddingTab: Signal; + readonly showHeading: Signal; + readonly showActionButtons: Signal; + @ViewChild(EditDossierGeneralInfoComponent) generalInfoComponent: EditDossierGeneralInfoComponent; @ViewChild(EditDossierDownloadPackageComponent) downloadPackageComponent: EditDossierDownloadPackageComponent; @ViewChild(EditDossierDictionaryComponent) dictionaryComponent: EditDossierDictionaryComponent; @ViewChild(EditDossierTeamComponent) membersComponent: EditDossierTeamComponent; @ViewChild(EditDossierAttributesComponent) attributesComponent: EditDossierAttributesComponent; - readonly #currentUser = getCurrentUser(); - #dossier: Dossier; constructor( - readonly iqserPermissionsService: IqserPermissionsService, private readonly _dossiersService: DossiersService, private readonly _permissionsService: PermissionsService, protected readonly _dialogRef: MatDialogRef, @@ -61,72 +63,43 @@ export class EditDossierDialogComponent extends BaseDialogComponent implements A readonly configService: ConfigService, ) { super(_dialogRef, true); - this.dossier$ = this._dossiersService.getEntityChanged$(this._data.dossierId).pipe( - tap(dossier => { - this.#dossier = dossier; - this._initializeNavItems(); - }), - ); - this.activeNav = this._data.section || 'dossierInfo'; - } - - get activeNavItem(): NavItem { - return this.navItems.find(item => item.key === this.activeNav); - } - - get activeComponent(): EditDossierSectionInterface { - return { - dossierInfo: this.generalInfoComponent, - downloadPackage: this.downloadPackageComponent, - dossierDictionary: this.dictionaryComponent, - members: this.membersComponent, - dossierAttributes: this.attributesComponent, - }[this.activeNav]; - } - - get noPaddingTab(): boolean { - return ['dossierAttributes', 'dossierDictionary'].includes(this.activeNav); - } - - get showHeading(): boolean { - return !['dossierAttributes', 'dossierDictionary'].includes(this.activeNav); - } - - get showActionButtons(): boolean { - return ( - (['dossierDictionary'].includes(this.activeNav) && this._permissionsService.canEditDossierDictionary(this.#dossier)) || - (['members'].includes(this.activeNav) && - this.#currentUser.isManager && - this.iqserPermissionsService.has(Roles.dossiers.edit)) || - this._permissionsService.canEditDossier(this.#dossier) - ); + this.dossier = toSignal(this._dossiersService.getEntityChanged$(this._data.dossierId)); + this.navItems = computed(() => this._getNavItems(this.dossier())); + this.activeNav = signal(this._data.section || 'dossierInfo'); + this.activeNavItem = computed(() => this.navItems().find(item => item.key === this.activeNav())); + this.activeComponent = computed(() => this._getActiveComponent(this.activeNav())); + this.noPaddingTab = computed(() => ['dossierAttributes', 'dossierDictionary'].includes(this.activeNav())); + this.showHeading = computed(() => !['dossierAttributes', 'dossierDictionary'].includes(this.activeNav())); + this.showActionButtons = computed(() => !this.activeNavItem().readonly); } get changed(): boolean { - return this.activeComponent?.changed; + return this.activeComponent()?.changed; } get valid(): boolean { - return this.activeComponent?.valid; + return this.activeComponent()?.valid; } get disabled(): boolean { - return this.activeComponent?.disabled; + return this.activeComponent()?.disabled; } ngAfterViewInit() { - if (!this.#dossier.ownerId) { + if (!untracked(this.dossier).ownerId) { this._toaster.error(_('edit-dossier-dialog.missing-owner')); } } async save(options?: SaveOptions) { this._loadingService.start(); - const result = await this.activeComponent.save(); + const result = await untracked(this.activeComponent).save(); this._loadingService.stop(); if (result.success) { - this._toaster.success(_('edit-dossier-dialog.change-successful'), { params: { dossierName: this.#dossier.dossierName } }); + this._toaster.success(_('edit-dossier-dialog.change-successful'), { + params: { dossierName: untracked(this.dossier).dossierName }, + }); } if (result.success && options?.closeAfterSave) { @@ -135,7 +108,7 @@ export class EditDossierDialogComponent extends BaseDialogComponent implements A } revert() { - this.activeComponent.revert(); + untracked(this.activeComponent).revert(); } changeTab(key: Section) { @@ -146,34 +119,44 @@ export class EditDossierDialogComponent extends BaseDialogComponent implements A } else { this.revert(); } - this.activeNav = key; + this.activeNav.set(key); }); } else { - this.activeNav = key; + this.activeNav.set(key); } } - private _initializeNavItems(): void { - this.navItems = [ + private _getActiveComponent(section: Section): EditDossierSectionInterface { + return { + dossierInfo: this.generalInfoComponent, + downloadPackage: this.downloadPackageComponent, + dossierDictionary: this.dictionaryComponent, + members: this.membersComponent, + dossierAttributes: this.attributesComponent, + }[section]; + } + + private _getNavItems(dossier: Dossier): NavItem[] { + return [ { key: 'dossierInfo', title: _('edit-dossier-dialog.nav-items.general-info'), sideNavTitle: _('edit-dossier-dialog.nav-items.dossier-info'), - readonly: !this.#dossier.isActive || !this._permissionsService.canEditDossier(this.#dossier), + readonly: !this._permissionsService.canEditDossier(dossier), helpModeKey: 'edit_dossier_dossier_info_DIALOG', }, { key: 'downloadPackage', title: _('edit-dossier-dialog.nav-items.choose-download'), sideNavTitle: _('edit-dossier-dialog.nav-items.download-package'), - readonly: !this._permissionsService.canEditDossier(this.#dossier), + readonly: !this._permissionsService.canEditDossier(dossier), helpModeKey: 'edit_dossier_download_package_DIALOG', }, { key: 'dossierDictionary', sideNavTitle: _('edit-dossier-dialog.nav-items.dictionary'), title: _('edit-dossier-dialog.nav-items.dossier-dictionary'), - readonly: !this._permissionsService.canEditDossierDictionary(this.#dossier), + readonly: !this._permissionsService.canEditDossierDictionary(dossier), helpModeKey: 'edit_dossier_dossier_dictionary_DIALOG', hide: this.configService.values.IS_DOCUMINE, }, @@ -181,13 +164,13 @@ export class EditDossierDialogComponent extends BaseDialogComponent implements A key: 'members', title: _('edit-dossier-dialog.nav-items.team-members'), sideNavTitle: _('edit-dossier-dialog.nav-items.members'), - readonly: !this._permissionsService.canEditTeamMembers(this.#dossier), + readonly: !this._permissionsService.canEditTeamMembers(dossier), helpModeKey: 'edit_dossier_members_DIALOG', }, { key: 'dossierAttributes', title: _('edit-dossier-dialog.nav-items.dossier-attributes'), - readonly: !this._permissionsService.canEditDossierAttributes(this.#dossier), + readonly: !this._permissionsService.canEditDossierAttributes(dossier), helpModeKey: 'edit_dossier_dossier_attributes_DIALOG', }, ]; 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 56a0eb045..1e5f43d09 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 @@ -106,14 +106,14 @@
{ diff --git a/apps/red-ui/src/app/services/permissions.service.ts b/apps/red-ui/src/app/services/permissions.service.ts index 05e98f73d..0786aa785 100644 --- a/apps/red-ui/src/app/services/permissions.service.ts +++ b/apps/red-ui/src/app/services/permissions.service.ts @@ -302,7 +302,14 @@ export class PermissionsService { } canEditDossier(dossier: Dossier): boolean { - return this._iqserPermissionsService.has(Roles.dossiers.edit) && this.isManager() && !!dossier?.ownerId; + const dossierTemplate = this._dossierTemplatesService.find(dossier.dossierTemplateId); + return ( + this._iqserPermissionsService.has(Roles.dossiers.edit) && + this.isManager() && + !!dossier?.ownerId && + dossier.isActive && + dossierTemplate.isActive + ); } canEditDossierDictionary(dossier: Dossier): boolean { diff --git a/apps/red-ui/src/assets/i18n/redact/de.json b/apps/red-ui/src/assets/i18n/redact/de.json index c92861f44..ad22e3a79 100644 --- a/apps/red-ui/src/assets/i18n/redact/de.json +++ b/apps/red-ui/src/assets/i18n/redact/de.json @@ -26,6 +26,11 @@ "title": "Add annotation" } }, + "add-clone-dossier-template": { + "save": "", + "save-and-edit": "", + "title": "" + }, "add-dossier-dialog": { "actions": { "save": "Speichern", @@ -87,8 +92,7 @@ "valid-from": "Gültig ab", "valid-to": "Gültig bis" }, - "save": "Dossier-Vorlage speichern", - "title": "{type, select, edit{Dossier-Vorlage {name} bearbeiten} create{Dossier-Vorlage erstellen} clone{} other{}}" + "save": "Dossier-Vorlage speichern" }, "add-edit-dossier-attribute": { "error": { @@ -1020,6 +1024,7 @@ "entities": "{count} {count, plural, one{entity} other{entities}}", "entries": "{count} {count, plural, one{entry} other{entries}}", "modified-on": "Modified on: {date}", + "title": "", "valid-from": "Valid from: {date}", "valid-to": "Valid to: {date}" }, @@ -1645,7 +1650,7 @@ "clicking-anywhere-on": "Klicken Sie auf eine beliebige Stelle des Bildschirms um zu sehen, welche Bereiche interaktiv sind. Wenn Sie mit der Maus über einen interaktiven Bereich fahren, verändert sich der Mauszeiger, um Ihnen zu zeigen, ob ein Element interaktiv ist.", "instructions": "Hilfe-Modus-Anleitungen öffnen", "options": { - "do-not-show-again": "" + "do-not-show-again": "Do not show again" }, "welcome-to-help-mode": " Willkommen im Hilfe-Modus!
Klicken Sie auf interaktive Elemente, um in einem neuen Tab Infos dazu zu erhalten.
" }, @@ -1970,7 +1975,7 @@ }, "form": { "auto-expand-filters-on-action": "Auto-expand filters on my actions", - "help-mode-dialog": "", + "help-mode-dialog": "Help Mode Dialog", "load-all-annotations-warning": "Warning regarding loading all annotations at once in file preview", "open-structured-view-by-default": "Display structured component management modal by default", "table-extraction-type": "Table extraction type" @@ -1979,8 +1984,7 @@ "title": "Edit preferences", "warnings-description": "Selecting the 'Do not show this message again' checkbox will skip the warning dialog the next time you trigger it.", "warnings-label": "Prompts and dialogs", - "warnings-subtitle": "Do not show again options", - "warnings-title": "Prompts and dialogs settings" + "warnings-subtitle": "Do not show again options" }, "processing-status": { "ocr": "OCR", @@ -2267,6 +2271,9 @@ }, "title": "Authentifizierung aktivieren" }, + "table-header": { + "selected-count": "" + }, "tenant-resolve": { "contact-administrator": "Cannot remember the workspace? Please contact your administrator.", "header": { diff --git a/apps/red-ui/src/assets/i18n/redact/en.json b/apps/red-ui/src/assets/i18n/redact/en.json index a698d6731..2b66573c3 100644 --- a/apps/red-ui/src/assets/i18n/redact/en.json +++ b/apps/red-ui/src/assets/i18n/redact/en.json @@ -26,6 +26,11 @@ "title": "Add annotation" } }, + "add-clone-dossier-template": { + "save": "{type, select, clone{Clone} other{Save}}", + "save-and-edit": "{type, select, clone{Clone} other{Save}} and edit", + "title": "{type, select, clone{Clone {dossierTemplateName}} other{Create dossier template}}" + }, "add-dossier-dialog": { "actions": { "save": "Save", @@ -87,8 +92,7 @@ "valid-from": "Valid from", "valid-to": "Valid to" }, - "save": "Save dossier template", - "title": "{type, select, edit{Edit {name}} create{Create} clone{Clone} other{}} dossier template" + "save": "Save dossier template" }, "add-edit-dossier-attribute": { "error": { @@ -1021,6 +1025,7 @@ "entities": "{count} {count, plural, one{entity} other{entities}}", "entries": "{count} {count, plural, one{entry} other{entries}}", "modified-on": "Modified on: {date}", + "title": "Edit dossier template", "valid-from": "Valid from: {date}", "valid-to": "Valid to: {date}" }, @@ -1980,8 +1985,7 @@ "title": "Edit preferences", "warnings-description": "Selecting the 'Do not show this message again' checkbox will skip the warning dialog the next time you trigger it.", "warnings-label": "Prompts and dialogs", - "warnings-subtitle": "Do not show again options", - "warnings-title": "Prompts and dialogs settings" + "warnings-subtitle": "Do not show again options" }, "processing-status": { "ocr": "OCR", @@ -2268,6 +2272,9 @@ }, "title": "Enable authentication" }, + "table-header": { + "selected-count": "{count} selected" + }, "tenant-resolve": { "contact-administrator": "Cannot remember the workspace? Please contact your administrator.", "header": { diff --git a/apps/red-ui/src/assets/i18n/scm/de.json b/apps/red-ui/src/assets/i18n/scm/de.json index 464198d20..d35779937 100644 --- a/apps/red-ui/src/assets/i18n/scm/de.json +++ b/apps/red-ui/src/assets/i18n/scm/de.json @@ -26,6 +26,11 @@ "title": "Add annotation" } }, + "add-clone-dossier-template": { + "save": "", + "save-and-edit": "", + "title": "" + }, "add-dossier-dialog": { "actions": { "save": "Speichern", @@ -87,8 +92,7 @@ "valid-from": "Gültig ab", "valid-to": "Gültig bis" }, - "save": "Dossier-Vorlage speichern", - "title": "{type, select, edit{Dossier-Vorlage {name} bearbeiten} create{Dossier-Vorlage erstellen} clone{} other{}}" + "save": "Dossier-Vorlage speichern" }, "add-edit-dossier-attribute": { "error": { @@ -1020,6 +1024,7 @@ "entities": "{count} {count, plural, one{entity} other{entities}}", "entries": "{count} {count, plural, one{entry} other{entries}}", "modified-on": "Modified on: {date}", + "title": "", "valid-from": "Valid from: {date}", "valid-to": "Valid to: {date}" }, @@ -1645,7 +1650,7 @@ "clicking-anywhere-on": "Klicken Sie auf eine beliebige Stelle des Bildschirms um zu sehen, welche Bereiche interaktiv sind. Wenn Sie mit der Maus über einen interaktiven Bereich fahren, verändert sich der Mauszeiger, um Ihnen zu zeigen, ob ein Element interaktiv ist.", "instructions": "Hilfe-Modus-Anleitungen öffnen", "options": { - "do-not-show-again": "" + "do-not-show-again": "Do not show again" }, "welcome-to-help-mode": " Willkommen im Hilfe-Modus!
Klicken Sie auf interaktive Elemente, um in einem neuen Tab Infos dazu zu erhalten.
" }, @@ -1970,7 +1975,7 @@ }, "form": { "auto-expand-filters-on-action": "Auto expand filters on my actions", - "help-mode-dialog": "", + "help-mode-dialog": "Help Mode Dialog", "load-all-annotations-warning": "Warning regarding loading all annotations at once in file preview", "open-structured-view-by-default": "Display Component View by default when opening a document", "table-extraction-type": "Table extraction type" @@ -1979,8 +1984,7 @@ "title": "Edit preferences", "warnings-description": "Selecting the 'Do not show this message again' checkbox will skip the warning dialog the next time you trigger it.", "warnings-label": "Prompts and dialogs", - "warnings-subtitle": "Do not show again options", - "warnings-title": "Prompts and dialogs settings" + "warnings-subtitle": "Do not show again options" }, "processing-status": { "ocr": "OCR", @@ -2267,6 +2271,9 @@ }, "title": "Authentifizierung aktivieren" }, + "table-header": { + "selected-count": "" + }, "tenant-resolve": { "contact-administrator": "Cannot remember the workspace? Please contact your administrator.", "header": { diff --git a/apps/red-ui/src/assets/i18n/scm/en.json b/apps/red-ui/src/assets/i18n/scm/en.json index cc0d3ace5..192bbe8f5 100644 --- a/apps/red-ui/src/assets/i18n/scm/en.json +++ b/apps/red-ui/src/assets/i18n/scm/en.json @@ -26,6 +26,11 @@ "title": "Add annotation" } }, + "add-clone-dossier-template": { + "save": "{type, select, clone{Clone} other{Save}}", + "save-and-edit": "{type, select, clone{Clone} other{Save}} and edit", + "title": "{type, select, clone{Clone {dossierTemplateName}} other{Create dossier template}}" + }, "add-dossier-dialog": { "actions": { "save": "Save", @@ -87,8 +92,7 @@ "valid-from": "Valid from", "valid-to": "Valid to" }, - "save": "Save dossier template", - "title": "{type, select, edit{Edit {name}} create{Create} clone{Clone} other{}} dossier template" + "save": "Save dossier template" }, "add-edit-dossier-attribute": { "error": { @@ -1021,6 +1025,7 @@ "entities": "{count} {count, plural, one{entity} other{entities}}", "entries": "{count} {count, plural, one{entry} other{entries}}", "modified-on": "Modified on: {date}", + "title": "Edit dossier template", "valid-from": "Valid from: {date}", "valid-to": "Valid to: {date}" }, @@ -1980,8 +1985,7 @@ "title": "Edit preferences", "warnings-description": "Selecting the 'Do not show this message again' checkbox will skip the warning dialog the next time you trigger it.", "warnings-label": "Prompts and dialogs", - "warnings-subtitle": "Do not show again options", - "warnings-title": "Prompts and dialogs settings" + "warnings-subtitle": "Do not show again options" }, "processing-status": { "ocr": "OCR", @@ -2268,6 +2272,9 @@ }, "title": "Enable authentication" }, + "table-header": { + "selected-count": "{count} selected" + }, "tenant-resolve": { "contact-administrator": "Cannot remember the workspace? Please contact your administrator.", "header": { diff --git a/libs/red-domain/src/lib/dossier-templates/dossier-template.model.ts b/libs/red-domain/src/lib/dossier-templates/dossier-template.model.ts index 24403da76..b3e249e92 100644 --- a/libs/red-domain/src/lib/dossier-templates/dossier-template.model.ts +++ b/libs/red-domain/src/lib/dossier-templates/dossier-template.model.ts @@ -60,8 +60,4 @@ export class DossierTemplate implements IDossierTemplate, IListable { get routerLink(): string { return `/main/admin/dossier-templates/${this.dossierTemplateId}`; } - - get dossiersRouterLink(): string { - return `/main/${this.dossierTemplateId}/dossiers`; - } }