diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/force-redaction-dialog/force-annotation-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/force-redaction-dialog/force-annotation-dialog.component.ts
index 3925d5752..7a151a4f6 100644
--- a/apps/red-ui/src/app/modules/file-preview/dialogs/force-redaction-dialog/force-annotation-dialog.component.ts
+++ b/apps/red-ui/src/app/modules/file-preview/dialogs/force-redaction-dialog/force-annotation-dialog.component.ts
@@ -53,6 +53,10 @@ export class ForceAnnotationDialogComponent extends BaseDialogComponent implemen
this.form = this.#getForm();
}
+ get isImageHint() {
+ return this._data.annotations.every(annotation => annotation.IMAGE_HINT);
+ }
+
get isHintDialog() {
return this._data.hint;
}
diff --git a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts
index 436f34efb..ea41e52b8 100644
--- a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts
+++ b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts
@@ -173,14 +173,17 @@ export class FilePreviewScreenComponent
}
});
+ effect(() => {
+ this._viewModeService.viewMode();
+ this.updateViewMode().then();
+ });
+
effect(() => {
this.state.updateExcludedPagesStyle();
- if (this._viewModeService.viewMode()) {
- this.updateViewMode().then();
- if (_documentViewer.loaded()) {
- this._logger.info('[PDF] Stamp pdf');
- this._stampService.stampPDF().then();
- }
+ this._viewModeService.viewMode();
+ if (_documentViewer.loaded()) {
+ this._logger.info('[PDF] Stamp pdf');
+ this._stampService.stampPDF().then();
}
});
}
diff --git a/apps/red-ui/src/app/modules/file-preview/services/annotation-processing.service.ts b/apps/red-ui/src/app/modules/file-preview/services/annotation-processing.service.ts
index 42d467dd9..3941d297d 100644
--- a/apps/red-ui/src/app/modules/file-preview/services/annotation-processing.service.ts
+++ b/apps/red-ui/src/app/modules/file-preview/services/annotation-processing.service.ts
@@ -3,7 +3,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { getConfig } from '@iqser/common-ui';
import { Filter, handleCheckedValue, IFilter, INestedFilter, NestedFilter } from '@iqser/common-ui/lib/filtering';
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
-import { annotationDefaultColorConfig } from '@red/domain';
+import { annotationDefaultColorConfig, LogEntryEngines } from '@red/domain';
import { DefaultColorsService } from '@services/entity-services/default-colors.service';
import { ViewedPagesMapService } from '@services/files/viewed-pages-map.service';
import { annotationTypesTranslations } from '@translations/annotation-types-translations';
@@ -19,7 +19,6 @@ import {
} from '../utils/sort-by-page-rotation.utils';
import { FileDataService } from './file-data.service';
import { FilePreviewStateService } from './file-preview-state.service';
-import { Engines } from '../components/annotation-details/annotation-details.component';
@Injectable()
export class AnnotationProcessingService {
@@ -52,7 +51,7 @@ export class AnnotationProcessingService {
checked: false,
topLevelFilter: true,
checker: (annotation: AnnotationWrapper) =>
- annotation?.hasRedactionChanges && annotation?.engines?.includes(Engines.MANUAL),
+ annotation?.hasRedactionChanges && annotation?.engines?.includes(LogEntryEngines.MANUAL),
},
{
id: 'unseen-pages',
diff --git a/apps/red-ui/src/app/modules/file-preview/services/file-preview-state.service.ts b/apps/red-ui/src/app/modules/file-preview/services/file-preview-state.service.ts
index 11d386628..6f584dd5d 100644
--- a/apps/red-ui/src/app/modules/file-preview/services/file-preview-state.service.ts
+++ b/apps/red-ui/src/app/modules/file-preview/services/file-preview-state.service.ts
@@ -1,10 +1,10 @@
import { HttpEvent, HttpEventType, HttpProgressEvent, HttpResponse } from '@angular/common/http';
-import { computed, effect, inject, Injectable, signal, Signal } from '@angular/core';
+import { computed, effect, inject, Injectable, signal, Signal, WritableSignal } from '@angular/core';
import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
import { LoadingService, wipeCache } from '@iqser/common-ui';
import { getParam } from '@iqser/common-ui/lib/utils';
import { TranslateService } from '@ngx-translate/core';
-import { Dictionary, Dossier, DOSSIER_ID, DOSSIER_TEMPLATE_ID, File, FILE_ID } from '@red/domain';
+import { Dictionary, Dossier, DOSSIER_ID, DOSSIER_TEMPLATE_ID, File, FILE_ID, ViewModes } from '@red/domain';
import { DossiersService } from '@services/dossiers/dossiers.service';
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
import { DossierDictionariesMapService } from '@services/entity-services/dossier-dictionaries-map.service';
@@ -44,7 +44,8 @@ export class FilePreviewStateService {
readonly dossierId = getParam(DOSSIER_ID);
readonly dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID);
readonly fileId = getParam(FILE_ID);
- readonly updateExcludedPagesStyle = computed(() => this.file().excludedPages);
+ readonly excludedPages: WritableSignal;
+ readonly updateExcludedPagesStyle = computed(() => this.excludedPages());
readonly isEditingReviewer = signal(false);
constructor(
@@ -61,6 +62,7 @@ export class FilePreviewStateService {
this.dossier = toSignal(dossiersServiceResolver().getEntityChanged$(this.dossierId));
this.file$ = inject(FilesMapService).watch$(this.dossierId, this.fileId);
this.file = toSignal(this.file$);
+ this.excludedPages = signal(this.file().excludedPages);
this.isWritable = computed(() => {
const isWritable = this._permissionsService.canPerformAnnotationActions(this.file(), this.dossier());
this._logger.info('[FILE] Is writeable:', isWritable);
@@ -80,7 +82,9 @@ export class FilePreviewStateService {
effect(
() => {
if (this._viewModeService.isEarmarks() && !this.file().hasHighlights) {
- this._viewModeService.switchToStandard();
+ if (this._viewModeService.viewMode() !== ViewModes.STANDARD) {
+ this._viewModeService.switchToStandard();
+ }
}
},
{ allowSignalWrites: true },
diff --git a/apps/red-ui/src/app/modules/file-preview/services/pdf-annotation-actions.service.ts b/apps/red-ui/src/app/modules/file-preview/services/pdf-annotation-actions.service.ts
index c2086fa7f..deac10928 100644
--- a/apps/red-ui/src/app/modules/file-preview/services/pdf-annotation-actions.service.ts
+++ b/apps/red-ui/src/app/modules/file-preview/services/pdf-annotation-actions.service.ts
@@ -81,8 +81,11 @@ export class PdfAnnotationActionsService {
}
if (permissions.canForceRedaction && annotationChangesAllowed) {
- const forceRedactionButton = this.#getButton('thumb-up', _('annotation-actions.force-redaction.label'), () =>
- this.#annotationActionsService.forceAnnotation(annotations),
+ const isImageHint = annotations.every(annotation => annotation.IMAGE_HINT);
+ const forceRedactionButton = this.#getButton(
+ isImageHint ? 'general/pdftron-action-add-redaction' : 'thumb-up',
+ _('annotation-actions.force-redaction.label'),
+ () => this.#annotationActionsService.forceAnnotation(annotations),
);
availableActions.push(forceRedactionButton);
}
diff --git a/apps/red-ui/src/app/modules/icons/icons.module.ts b/apps/red-ui/src/app/modules/icons/icons.module.ts
index a2b7a8376..dab2ac28d 100644
--- a/apps/red-ui/src/app/modules/icons/icons.module.ts
+++ b/apps/red-ui/src/app/modules/icons/icons.module.ts
@@ -86,6 +86,7 @@ export class IconsModule {
'visibility',
'visibility-off',
'warning',
+ 'pdftron-action-add-redaction',
];
for (const icon of icons) {
diff --git a/apps/red-ui/src/app/modules/pdf-viewer/services/tooltips.service.ts b/apps/red-ui/src/app/modules/pdf-viewer/services/tooltips.service.ts
index e29c09630..0282bbf72 100644
--- a/apps/red-ui/src/app/modules/pdf-viewer/services/tooltips.service.ts
+++ b/apps/red-ui/src/app/modules/pdf-viewer/services/tooltips.service.ts
@@ -1,18 +1,13 @@
-import { inject, Injectable } from '@angular/core';
+import { Injectable } from '@angular/core';
import { UserPreferenceService } from '@users/user-preference.service';
-import { HeaderElements } from '../../file-preview/utils/constants';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { TranslateService } from '@ngx-translate/core';
import { PdfViewer } from './pdf-viewer.service';
import { REDDocumentViewer } from './document-viewer.service';
-import { UI_ROOT_PATH_FN } from '@common-ui/utils';
+import { HeaderElements } from '../../file-preview/utils/constants';
@Injectable()
export class TooltipsService {
- readonly #convertPath = inject(UI_ROOT_PATH_FN);
- readonly #enableIcon = this.#convertPath('/assets/icons/general/pdftron-action-enable-tooltips.svg');
- readonly #disableIcon = this.#convertPath('/assets/icons/general/pdftron-action-disable-tooltips.svg');
-
constructor(
private readonly _pdf: PdfViewer,
private readonly _documentViewer: REDDocumentViewer,
@@ -26,17 +21,23 @@ export class TooltipsService {
});
}
- get toggleTooltipsBtnIcon(): string {
- const tooltipsDisabled = this._userPreferenceService.getFilePreviewTooltipsPreference();
- return tooltipsDisabled ? this.#enableIcon : this.#disableIcon;
- }
-
async toggleTooltips(): Promise {
await this._userPreferenceService.toggleFilePreviewTooltipsPreference();
this._documentViewer.updateTooltipsVisibility();
+
+ this.updateIconState();
+
this._pdf.instance.UI.updateElement(HeaderElements.TOGGLE_TOOLTIPS, {
title: this.toggleTooltipsBtnTitle,
- img: this.toggleTooltipsBtnIcon,
});
}
+
+ updateIconState() {
+ const element = this._pdf.instance.UI.iframeWindow.document.querySelector(`[data-element=${HeaderElements.TOGGLE_TOOLTIPS}]`);
+ if (this._userPreferenceService.getFilePreviewTooltipsPreference()) {
+ element.classList.add('active');
+ } else {
+ element.classList.remove('active');
+ }
+ }
}
diff --git a/apps/red-ui/src/app/modules/pdf-viewer/services/viewer-header.service.ts b/apps/red-ui/src/app/modules/pdf-viewer/services/viewer-header.service.ts
index 78b7dee74..1a97af173 100644
--- a/apps/red-ui/src/app/modules/pdf-viewer/services/viewer-header.service.ts
+++ b/apps/red-ui/src/app/modules/pdf-viewer/services/viewer-header.service.ts
@@ -100,7 +100,7 @@ export class ViewerHeaderService {
element: HeaderElements.TOGGLE_TOOLTIPS,
dataElement: HeaderElements.TOGGLE_TOOLTIPS,
title: this._tooltipsService.toggleTooltipsBtnTitle,
- img: this._tooltipsService.toggleTooltipsBtnIcon,
+ img: this.#convertPath('/assets/icons/general/pdftron-action-enable-tooltips.svg'),
onClick: () => this._ngZone.run(() => this._tooltipsService.toggleTooltips()),
};
}
@@ -137,17 +137,6 @@ export class ViewerHeaderService {
};
}
- get #closeCompare(): IHeaderElement {
- return {
- type: 'actionButton',
- element: HeaderElements.CLOSE_COMPARE_BUTTON,
- dataElement: HeaderElements.CLOSE_COMPARE_BUTTON,
- img: this.#convertPath('/assets/icons/general/pdftron-action-close-compare.svg'),
- title: 'Leave Compare Mode',
- onClick: () => this._ngZone.run(() => this.#closeCompareMode()),
- };
- }
-
get #rotateLeft(): IHeaderElement {
return {
type: 'actionButton',
@@ -238,6 +227,17 @@ export class ViewerHeaderService {
};
}
+ get #closeCompare(): IHeaderElement {
+ return {
+ type: 'actionButton',
+ element: HeaderElements.CLOSE_COMPARE_BUTTON,
+ dataElement: HeaderElements.CLOSE_COMPARE_BUTTON,
+ img: this.#convertPath('/assets/icons/general/pdftron-action-compare.svg'),
+ title: 'Leave Compare Mode',
+ onClick: () => this._ngZone.run(() => this.#closeCompareMode()),
+ };
+ }
+
get #toggleLoadAnnotations$() {
return merge(this.expandedPanelEvent$, this._helpModeService.isHelpModeActive$).pipe(
tap(enable =>
@@ -281,7 +281,6 @@ export class ViewerHeaderService {
[HeaderElements.TOGGLE_TOOLTIPS],
[HeaderElements.TOGGLE_LAYERS],
[HeaderElements.TOGGLE_READABLE_REDACTIONS],
- [HeaderElements.SHAPE_TOOL_GROUP_BUTTON],
[
HeaderElements.ROTATE_LEFT_BUTTON,
HeaderElements.ROTATE_RIGHT_BUTTON,
@@ -290,18 +289,19 @@ export class ViewerHeaderService {
],
];
- const loadAllAnnotationsButton = this.#buttons.get(HeaderElements.LOAD_ALL_ANNOTATIONS);
- let startButtons = 10;
- let deleteCount = 14;
-
+ header.get('selectToolButton').insertAfter(this.#buttons.get(HeaderElements.SHAPE_TOOL_GROUP_BUTTON));
groups.forEach(group => this.#pushGroup(enabledItems, group));
+ const loadAllAnnotationsButton = this.#buttons.get(HeaderElements.LOAD_ALL_ANNOTATIONS);
+ let startButtons = 11;
+ let deleteCount = 15;
+
if (this.#isEnabled(HeaderElements.LOAD_ALL_ANNOTATIONS)) {
if (!header.getItems().includes(loadAllAnnotationsButton)) {
header.get('leftPanelButton').insertAfter(loadAllAnnotationsButton);
}
- startButtons = 11;
- deleteCount = 15;
+ startButtons = 12;
+ deleteCount = 16;
} else {
header.delete(HeaderElements.LOAD_ALL_ANNOTATIONS);
}
@@ -311,6 +311,11 @@ export class ViewerHeaderService {
this._pdf.instance?.UI.updateElement('selectToolButton', {
img: this.#convertPath('/assets/icons/general/pdftron-cursor.svg'),
});
+ this._tooltipsService.updateIconState();
+ const closeCompareButton = this._pdf.instance.UI.iframeWindow.document.querySelector(
+ `[data-element=${HeaderElements.CLOSE_COMPARE_BUTTON}]`,
+ );
+ closeCompareButton?.classList.add('active');
}
disableLoadAllAnnotations(): void {
diff --git a/apps/red-ui/src/app/translations/placeholders-descriptions-translations.ts b/apps/red-ui/src/app/translations/placeholders-descriptions-translations.ts
index 876acfb02..13f59a0f9 100644
--- a/apps/red-ui/src/app/translations/placeholders-descriptions-translations.ts
+++ b/apps/red-ui/src/app/translations/placeholders-descriptions-translations.ts
@@ -22,4 +22,6 @@ export const generalPlaceholdersDescriptionsTranslations = {
'redaction.justificationLegalBasis': _('reports-screen.descriptions.general.redaction.justification-legal-basis'),
'redaction.justificationText': _('reports-screen.descriptions.general.redaction.justification-text'),
'redaction.entity.displayName': _('reports-screen.descriptions.general.redaction.entity.display-name'),
+ 'redaction.isSkipped': _('reports-screen.descriptions.general.redaction.is-skipped'),
+ 'redaction.paragraphIdx': _('reports-screen.descriptions.general.redaction.paragraph-idx'),
} as const;
diff --git a/apps/red-ui/src/assets/config/config.json b/apps/red-ui/src/assets/config/config.json
index 2ccc6f6d1..441ade243 100644
--- a/apps/red-ui/src/assets/config/config.json
+++ b/apps/red-ui/src/assets/config/config.json
@@ -1,7 +1,7 @@
{
"ADMIN_CONTACT_NAME": null,
"ADMIN_CONTACT_URL": null,
- "API_URL": "https://frontend2.iqser.cloud",
+ "API_URL": "https://dan1.iqser.cloud",
"APP_NAME": "RedactManager",
"IS_DOCUMINE": true,
"RULE_EDITOR_DEV_ONLY": false,
@@ -13,7 +13,7 @@
"MAX_RETRIES_ON_SERVER_ERROR": 3,
"OAUTH_CLIENT_ID": "redaction",
"OAUTH_IDP_HINT": null,
- "OAUTH_URL": "https://frontend2.iqser.cloud/auth",
+ "OAUTH_URL": "https://dan1.iqser.cloud/auth",
"RECENT_PERIOD_IN_HOURS": 24,
"SELECTION_MODE": "structural",
"MANUAL_BASE_URL": "https://docs.redactmanager.com/preview",
diff --git a/apps/red-ui/src/assets/i18n/redact/de.json b/apps/red-ui/src/assets/i18n/redact/de.json
index 519e9fcd7..10e3c8f28 100644
--- a/apps/red-ui/src/assets/i18n/redact/de.json
+++ b/apps/red-ui/src/assets/i18n/redact/de.json
@@ -133,7 +133,7 @@
"rank": "Rank"
},
"save": "Save state",
- "success": "Dossier state {type, select, edit{has been updated} creation successful{created} other{}}.",
+ "success": "Dossier state {type, select, edit{has been updated} create{creation successful} other{}}.",
"title": "{type, select, edit{Edit {name}} create{Create} other{}} dossier state"
},
"add-edit-entity": {
diff --git a/apps/red-ui/src/assets/i18n/redact/en.json b/apps/red-ui/src/assets/i18n/redact/en.json
index dcd8dafe6..2539b3d11 100644
--- a/apps/red-ui/src/assets/i18n/redact/en.json
+++ b/apps/red-ui/src/assets/i18n/redact/en.json
@@ -133,7 +133,7 @@
"rank": "Rank"
},
"save": "Save state",
- "success": "Dossier state {type, select, edit{has been updated} creation successful{created} other{}}.",
+ "success": "Dossier state {type, select, edit{has been updated} create{creation successful} other{}}.",
"title": "{type, select, edit{Edit {name}} create{Create} other{}} dossier state"
},
"add-edit-entity": {
@@ -372,6 +372,7 @@
},
"annotation-engines": {
"dictionary": "Based on dictionary",
+ "dossier-dictionary": "Based on dossier dictionary",
"imported": "Imported",
"ner": "Based on AI",
"rule": "Based on rule"
@@ -2150,11 +2151,11 @@
"description": "Below, you will find a list of placeholders for dossier- and document-specific information. You can include these placeholders in your report templates.",
"descriptions": {
"dossier-attributes": "This placeholder gets replaced with the value of the dossier attribute {attribute}.",
- "file-attributes": "This placeholder gets replaced with the value of the file attribute {attribute}.",
+ "file-attributes": "This placeholder is replaced with the value of the file attribute {attribute}.",
"general": {
"date": {
"d-m-y": "This placeholder is replaced by the creation date of the report in the common day-month-year notation (dd.MM.yyyy), e.g. 15.10.2021.",
- "m-d-y": "This placeholder gets replaced by the creation date of the report in the American all-numeric date format (MM/dd/yyyy), e.g. 10/15/2021.",
+ "m-d-y": "This placeholder is replaced by the creation date of the report in the American all-numeric date format (MM/dd/yyyy), e.g. 10/15/2021.",
"y-m-d": "This placeholder is replaced by the creation date of the report in the international ISO 8601 format (yyyy-MM-dd), e.g. 2021-10-15."
},
"dossier": {
@@ -2168,13 +2169,15 @@
"display-name": "This placeholder is replaced by the name of the entity the redaction is based on."
},
"excerpt": "This placeholder is replaced by a text snippet that contains the redaction.",
+ "is-skipped": "The skipped redaction placeholder indicates whether a redaction is skipped or not. It can be included in a separate column of a template that also contains the '{{redaction.value'}} placeholder. The placeholder is replaced by “true” if the respective redaction is skipped, and by “false” if it is redacted (i. e., not skipped).",
"justification": "This placeholder is replaced by the justification of the redaction. It is a combination of the legal reference (justificationParagraph) and the justification text (justificationReason).",
"justification-legal-basis": "This placeholder is replaced by the legal basis for the redaction.",
"justification-paragraph": "This placeholder is replaced by the legal reference of the justification of the redaction.",
"justification-reason": "This placeholder is replaced by the justification text of the redaction.",
"justification-text": "This placeholder is replaced by the justification text.",
"page": "This placeholder is replaced by the page number of the redaction.",
- "paragraph": "This placeholder is replaced by the paragraph that contains the redaction.",
+ "paragraph": "This placeholder is replaced by the initial words of the paragraph containing the redaction.",
+ "paragraph-idx": "The placeholder is replaced by the number of the paragraph containing the redaction. Paragraphs are numbered on a per-page basis.",
"value": "This placeholder is replaced by the value that was redacted."
},
"time": {
diff --git a/apps/red-ui/src/assets/i18n/scm/en.json b/apps/red-ui/src/assets/i18n/scm/en.json
index 13e936c33..ee85d8505 100644
--- a/apps/red-ui/src/assets/i18n/scm/en.json
+++ b/apps/red-ui/src/assets/i18n/scm/en.json
@@ -372,6 +372,7 @@
},
"annotation-engines": {
"dictionary": "{isHint, select, true{Hint} other{Annotation}} based on dictionary",
+ "dossier-dictionary": "Annotation based on dossier dictionary",
"imported": "Annotation is imported",
"ner": "Annotation based on AI",
"rule": "Annotation based on rule {rule}"
@@ -1759,7 +1760,7 @@
},
"initials-avatar": {
"unassigned": "Unassigned",
- "you": ""
+ "you": "You"
},
"justifications-listing": {
"actions": {
@@ -2168,6 +2169,7 @@
"display-name": "This placeholder is replaced by the name of the entity the component is based on."
},
"excerpt": "This placeholder is replaced by a text snippet that contains the component.",
+ "is-skipped": "The skipped redaction placeholder indicates whether a redaction is skipped or not. It can be included in a separate column of a template that also contains the '{{redaction.value'}} placeholder. The placeholder is replaced by “true” if the respective redaction is skipped, and by “false” if it is redacted (i. e., not skipped).",
"justification": "This placeholder is replaced by the justification of the component. It is a combination of the legal reference (justificationParagraph) and the justification text (justificationReason).",
"justification-legal-basis": "This placeholder is replaced by the legal basis for the component.",
"justification-paragraph": "This placeholder is replaced by the legal reference of the justification of the component.",
@@ -2175,6 +2177,7 @@
"justification-text": "This placeholder is replaced by the justification text.",
"page": "This placeholder is replaced by the page number of the component.",
"paragraph": "This placeholder is replaced by the paragraph that contains the component.",
+ "paragraph-idx": "The placeholder is replaced by the number of the paragraph containing the redaction. Paragraphs are numbered on a per-page basis.",
"value": "This placeholder is replaced by the value that was extracted."
},
"time": {
diff --git a/apps/red-ui/src/assets/icons/general/pdftron-action-close-compare.svg b/apps/red-ui/src/assets/icons/general/pdftron-action-close-compare.svg
deleted file mode 100644
index 82ddb11d8..000000000
--- a/apps/red-ui/src/assets/icons/general/pdftron-action-close-compare.svg
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
diff --git a/apps/red-ui/src/assets/icons/general/pdftron-action-compare.svg b/apps/red-ui/src/assets/icons/general/pdftron-action-compare.svg
index 6765155b5..eebcf0634 100644
--- a/apps/red-ui/src/assets/icons/general/pdftron-action-compare.svg
+++ b/apps/red-ui/src/assets/icons/general/pdftron-action-compare.svg
@@ -2,7 +2,7 @@