+ @if (!isImageHint) {
+
+ }
-
-
-
-
+ @if (!isHintDialog && !isDocumine) {
+
+
+
+
+
+
+ @for (option of legalOptions; track option) {
+
+ {{ option.label }}
+
+ }
+
+
+
+
+
+
+
+
+ }
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 667823634..df634df2e 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
@@ -25,6 +25,11 @@ import { MatFormField } from '@angular/material/form-field';
import { MatOption, MatSelect, MatSelectTrigger } from '@angular/material/select';
import { MatTooltip } from '@angular/material/tooltip';
import { TranslateModule } from '@ngx-translate/core';
+import { DetailsRadioOption } from '@common-ui/inputs/details-radio/details-radio-option';
+import { ForceAnnotationOption, RedactOrHintOption } from '../../utils/dialog-types';
+import { getForceAnnotationOptions, getRedactOrHintOptions } from '../../utils/dialog-options';
+import { DetailsRadioComponent } from '@common-ui/inputs/details-radio/details-radio.component';
+import { SystemDefaults } from '../../../account/utils/dialog-defaults';
export interface LegalBasisOption {
label?: string;
@@ -55,10 +60,12 @@ const DOCUMINE_LEGAL_BASIS = 'n-a.';
CircleButtonComponent,
NgForOf,
HelpButtonComponent,
+ DetailsRadioComponent,
],
})
export class ForceAnnotationDialogComponent extends BaseDialogComponent implements OnInit {
readonly isDocumine = getConfig().IS_DOCUMINE;
+ readonly options: DetailsRadioOption[];
readonly tableColumns: ValueColumn[] = [{ label: 'Value' }, { label: 'Type' }];
readonly tableData: ValueColumn[][] = this._data.annotations.map(redaction => [
@@ -76,6 +83,7 @@ export class ForceAnnotationDialogComponent extends BaseDialogComponent implemen
private readonly _data: { readonly dossier: Dossier; readonly hint: boolean; annotations: AnnotationWrapper[] },
) {
super(_dialogRef);
+ this.options = getForceAnnotationOptions(this.isDocumine, this.isHintDialog);
this.form = this.#getForm();
}
@@ -128,6 +136,7 @@ export class ForceAnnotationDialogComponent extends BaseDialogComponent implemen
return this._formBuilder.group({
reason: this._data.hint ? ['Forced Hint'] : [null, !this.isDocumine ? Validators.required : null],
comment: [null],
+ option: this.options.find(o => o.value === SystemDefaults.FORCE_REDACTION_DEFAULT),
});
}
@@ -136,6 +145,8 @@ export class ForceAnnotationDialogComponent extends BaseDialogComponent implemen
request.legalBasis = !this.isDocumine ? this.form.get('reason').value.legalBasis : DOCUMINE_LEGAL_BASIS;
request.comment = this.form.get('comment').value;
+ request.reason = this.form.get('reason').value.description;
+ request.option = this.form.get('option').value.value;
return request;
}
diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.ts
index 970bd01d9..c4630f766 100644
--- a/apps/red-ui/src/app/modules/file-preview/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.ts
+++ b/apps/red-ui/src/app/modules/file-preview/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.ts
@@ -32,6 +32,8 @@ export interface LegalBasisOption {
description?: string;
}
+export const NON_READABLE_CONTENT = 'non-readable content';
+
@Component({
templateUrl: './manual-annotation-dialog.component.html',
styleUrls: ['./manual-annotation-dialog.component.scss'],
@@ -196,7 +198,7 @@ export class ManualAnnotationDialogComponent extends BaseDialogComponent impleme
? [this.isFalsePositiveRequest ? 'false_positive' : null, Validators.required]
: [this.manualRedactionTypeExists ? SuperTypes.ManualRedaction : null, Validators.required],
comment: [null],
- classification: ['non-readable content'],
+ classification: [NON_READABLE_CONTENT],
multiplePages: '',
});
}
diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/redact-recommendation-dialog/redact-recommendation-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/redact-recommendation-dialog/redact-recommendation-dialog.component.ts
index b6efec032..85a109583 100644
--- a/apps/red-ui/src/app/modules/file-preview/dialogs/redact-recommendation-dialog/redact-recommendation-dialog.component.ts
+++ b/apps/red-ui/src/app/modules/file-preview/dialogs/redact-recommendation-dialog/redact-recommendation-dialog.component.ts
@@ -22,7 +22,13 @@ import {
ValueColumn,
} from '../../components/selected-annotations-table/selected-annotations-table.component';
import { getRedactOrHintOptions } from '../../utils/dialog-options';
-import { RedactOrHintOption, RedactOrHintOptions, RedactRecommendationData, RedactRecommendationResult } from '../../utils/dialog-types';
+import {
+ RedactOrHintOption,
+ RedactOrHintOptions,
+ RedactRecommendationData,
+ RedactRecommendationResult,
+ ResizeOptions,
+} from '../../utils/dialog-types';
import { LegalBasisOption } from '../manual-redaction-dialog/manual-annotation-dialog.component';
@Component({
@@ -147,6 +153,7 @@ export class RedactRecommendationDialogComponent
this.close({
redaction,
isMulti: this.isMulti,
+ bulkLocal: this.form.controls.option.value.value === ResizeOptions.IN_DOCUMENT,
});
}
diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/redact-text-dialog/redact-text-dialog.component.scss b/apps/red-ui/src/app/modules/file-preview/dialogs/redact-text-dialog/redact-text-dialog.component.scss
index 22fe3116d..64afce14d 100644
--- a/apps/red-ui/src/app/modules/file-preview/dialogs/redact-text-dialog/redact-text-dialog.component.scss
+++ b/apps/red-ui/src/app/modules/file-preview/dialogs/redact-text-dialog/redact-text-dialog.component.scss
@@ -1,5 +1,5 @@
.dialog-content {
- height: 493px;
+ height: 530px;
overflow-y: auto;
}
diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/redact-text-dialog/redact-text-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/redact-text-dialog/redact-text-dialog.component.ts
index ceea04f86..63332bb0a 100644
--- a/apps/red-ui/src/app/modules/file-preview/dialogs/redact-text-dialog/redact-text-dialog.component.ts
+++ b/apps/red-ui/src/app/modules/file-preview/dialogs/redact-text-dialog/redact-text-dialog.component.ts
@@ -21,8 +21,9 @@ import { firstValueFrom, Observable } from 'rxjs';
import { map, tap } from 'rxjs/operators';
import { SystemDefaultOption, SystemDefaults } from '../../../account/utils/dialog-defaults';
import { getRedactOrHintOptions } from '../../utils/dialog-options';
-import { RedactOrHintOption, RedactOrHintOptions, RedactTextData, RedactTextResult } from '../../utils/dialog-types';
+import { RedactOrHintOption, RedactOrHintOptions, RedactTextData, RedactTextResult, ResizeOptions } from '../../utils/dialog-types';
import { LegalBasisOption } from '../manual-redaction-dialog/manual-annotation-dialog.component';
+import { enhanceManualRedactionRequest, EnhanceRequestData } from '../../utils/enhance-manual-redaction-request.utils';
const MAXIMUM_TEXT_AREA_WIDTH = 421;
@@ -165,16 +166,17 @@ export class RedactTextDialogComponent
if (!this.#applyToAllDossiers) {
const selectedDictionaryType = this.form.controls.dictionary.value;
const selectedDictionary = this.dictionaries.find(d => d.type === selectedDictionaryType);
- this.options[1].extraOption.disabled = selectedDictionary.dossierDictionaryOnly;
+ this.options[2].extraOption.disabled = selectedDictionary.dossierDictionaryOnly;
}
}
save(): void {
- this.#enhanceManualRedaction(this.data.manualRedactionEntryWrapper.manualRedactionEntry);
const redaction = this.data.manualRedactionEntryWrapper.manualRedactionEntry;
+ enhanceManualRedactionRequest(redaction, this.#enhanceRequestData);
this.close({
redaction,
dictionary: this.dictionaries.find(d => d.type === this.form.controls.dictionary.value),
+ bulkLocal: this.form.controls.option.value.value === ResizeOptions.IN_DOCUMENT,
});
}
@@ -188,14 +190,18 @@ export class RedactTextDialogComponent
#setupValidators(option: RedactOrHintOption) {
switch (option) {
- case RedactOrHintOptions.IN_DOSSIER:
- this.form.controls.reason.clearValidators();
- this.form.controls.dictionary.addValidators(Validators.required);
- break;
case RedactOrHintOptions.ONLY_HERE:
this.form.controls.dictionary.clearValidators();
this.form.controls.reason.addValidators(Validators.required);
break;
+ case RedactOrHintOptions.IN_DOCUMENT:
+ this.form.controls.dictionary.clearValidators();
+ this.form.controls.reason.addValidators(Validators.required);
+ break;
+ case RedactOrHintOptions.IN_DOSSIER:
+ this.form.controls.reason.clearValidators();
+ this.form.controls.dictionary.addValidators(Validators.required);
+ break;
}
this.form.controls.reason.updateValueAndValidity();
@@ -222,36 +228,9 @@ export class RedactTextDialogComponent
}
}
- #enhanceManualRedaction(addRedactionRequest: IAddRedactionRequest) {
- addRedactionRequest.type = this.form.controls.dictionary.value;
- addRedactionRequest.section = null;
- addRedactionRequest.value = this.form.controls.selectedText.value;
-
- const legalOption: LegalBasisOption = this.form.controls.reason.value;
- if (legalOption) {
- addRedactionRequest.reason = legalOption.description;
- addRedactionRequest.legalBasis = legalOption.legalBasis;
- }
-
- const selectedType = this.dictionaries.find(d => d.type === addRedactionRequest.type);
-
- if (selectedType) {
- addRedactionRequest.addToDictionary = selectedType.hasDictionary;
- } else {
- addRedactionRequest.addToDictionary = this.dictionaryRequest && addRedactionRequest.type !== 'dossier_redaction';
- }
-
- if (!addRedactionRequest.reason) {
- addRedactionRequest.reason = 'Dictionary Request';
- }
- const commentValue = this.form.controls.comment.value;
- addRedactionRequest.comment = commentValue ? { text: commentValue } : null;
- addRedactionRequest.addToAllDossiers = this.data.isApprover && this.dictionaryRequest && this.#applyToAllDossiers;
- }
-
#resetValues() {
this.#applyToAllDossiers = this.applyToAll;
- this.options[1].extraOption.checked = this.#applyToAllDossiers;
+ this.options[2].extraOption.checked = this.#applyToAllDossiers;
if (this.dictionaryRequest) {
this.form.controls.reason.setValue(null);
this.form.controls.dictionary.setValue(null);
@@ -263,4 +242,17 @@ export class RedactTextDialogComponent
#getOption(option: RedactOrHintOption): DetailsRadioOption {
return this.options.find(o => o.value === option);
}
+
+ get #enhanceRequestData(): EnhanceRequestData {
+ return {
+ type: this.form.controls.dictionary.value,
+ selectedText: this.form.controls.selectedText.value,
+ reason: this.form.controls.reason.value,
+ dictionaries: this.dictionaries,
+ dictionaryRequest: this.dictionaryRequest,
+ comment: this.form.controls.comment.value,
+ isApprover: this.data.isApprover,
+ applyToAllDossiers: this.#applyToAllDossiers,
+ };
+ }
}
diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/remove-redaction-dialog/remove-redaction-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/remove-redaction-dialog/remove-redaction-dialog.component.ts
index 720f709f4..8b6812666 100644
--- a/apps/red-ui/src/app/modules/file-preview/dialogs/remove-redaction-dialog/remove-redaction-dialog.component.ts
+++ b/apps/red-ui/src/app/modules/file-preview/dialogs/remove-redaction-dialog/remove-redaction-dialog.component.ts
@@ -26,7 +26,13 @@ import {
} from '../../components/selected-annotations-table/selected-annotations-table.component';
import { DialogHelpModeKeys } from '../../utils/constants';
import { getRemoveRedactionOptions } from '../../utils/dialog-options';
-import { RemoveRedactionData, RemoveRedactionOption, RemoveRedactionOptions, RemoveRedactionResult } from '../../utils/dialog-types';
+import {
+ RemoveRedactionData,
+ RemoveRedactionOption,
+ RemoveRedactionOptions,
+ RemoveRedactionResult,
+ ResizeOptions,
+} from '../../utils/dialog-types';
@Component({
templateUrl: './remove-redaction-dialog.component.html',
@@ -128,19 +134,6 @@ export class RemoveRedactionDialogComponent extends IqserDialogComponent<
super();
}
- get helpButtonKey() {
- if (this.hint) {
- return DialogHelpModeKeys.HINT_REMOVE;
- }
- if (this.recommendation) {
- return DialogHelpModeKeys.RECOMMENDATION_REMOVE;
- }
- if (this.skipped) {
- return DialogHelpModeKeys.SKIPPED_REMOVE;
- }
- return DialogHelpModeKeys.REDACTION_REMOVE;
- }
-
get hasFalsePositiveOption() {
return !!this.options.find(option => option.value === RemoveRedactionOptions.FALSE_POSITIVE);
}
@@ -168,7 +161,10 @@ export class RemoveRedactionDialogComponent extends IqserDialogComponent<
}
save(): void {
- this.close(this.form.getRawValue());
+ this.close({
+ ...this.form.getRawValue(),
+ bulkLocal: this.form.controls.option.value.value === ResizeOptions.IN_DOCUMENT,
+ });
}
#getOption(option: RemoveRedactionOption): DetailsRadioOption {
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 958ee18f9..7701d687c 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
@@ -468,6 +468,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
const add$ = this._manualRedactionService.addAnnotation([result.redaction], this.dossierId, this.fileId, {
hint,
dictionaryLabel: result.dictionary?.label,
+ bulkLocal: result.bulkLocal,
});
const addAndReload$ = add$.pipe(
diff --git a/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts b/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts
index bf0907324..9bdb9b7db 100644
--- a/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts
+++ b/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts
@@ -8,9 +8,11 @@ import { Core } from '@pdftron/webviewer';
import {
DictionaryEntryTypes,
EarmarkOperation,
+ type IBulkLocalRemoveRequest,
ILegalBasisChangeRequest,
IRecategorizationRequest,
IRectangle,
+ type IRemoveRedactionRequest,
IResizeRequest,
} from '@red/domain';
import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service';
@@ -31,6 +33,7 @@ import { ResizeRedactionDialogComponent } from '../dialogs/resize-redaction-dial
import {
EditRedactionData,
EditRedactResult,
+ ForceAnnotationOptions,
RemoveRedactionData,
RemoveRedactionOptions,
RemoveRedactionPermissions,
@@ -43,6 +46,7 @@ import { FilePreviewDialogService } from './file-preview-dialog.service';
import { FilePreviewStateService } from './file-preview-state.service';
import { ManualRedactionService } from './manual-redaction.service';
import { SkippedService } from './skipped.service';
+import { NON_READABLE_CONTENT } from '../dialogs/manual-redaction-dialog/manual-annotation-dialog.component';
@Injectable()
export class AnnotationActionsService {
@@ -77,14 +81,29 @@ export class AnnotationActionsService {
const { dossierId, fileId } = this._state;
const data = { dossier: this._state.dossier(), annotations, hint };
this._dialogService.openDialog('forceAnnotation', data, (request: ILegalBasisChangeRequest) => {
- this.#processObsAndEmit(
- this._manualRedactionService.bulkForce(
+ let obs$;
+ if (request.option === ForceAnnotationOptions.ONLY_HERE) {
+ obs$ = this._manualRedactionService.bulkForce(
annotations.map(a => ({ ...request, annotationId: a.id })),
dossierId,
fileId,
annotations[0].isIgnoredHint,
- ),
- ).then();
+ );
+ } else {
+ const addAnnotationRequest = annotations.map(a => ({
+ comment: { text: request.comment },
+ legalBasis: request.legalBasis,
+ reason: request.reason,
+ positions: a.positions,
+ type: a.type,
+ value: a.value,
+ }));
+ obs$ = this._manualRedactionService.addAnnotation(addAnnotationRequest, dossierId, fileId, {
+ hint,
+ bulkLocal: true,
+ });
+ }
+ this.#processObsAndEmit(obs$).then();
});
}
@@ -192,7 +211,13 @@ export class AnnotationActionsService {
this.cancelResize(recommendations[0]).then();
}
- const request$ = this._manualRedactionService.addRecommendation(recommendations, result.redaction, dossierId, fileId);
+ const request$ = this._manualRedactionService.addRecommendation(
+ recommendations,
+ result.redaction,
+ dossierId,
+ fileId,
+ result.bulkLocal,
+ );
return this.#processObsAndEmit(request$);
}
@@ -425,17 +450,20 @@ export class AnnotationActionsService {
#removeRedaction(redactions: AnnotationWrapper[], dialogResult: RemoveRedactionResult) {
const removeFromDictionary = dialogResult.option.value === RemoveRedactionOptions.IN_DOSSIER;
const includeUnprocessed = redactions.every(redaction => this.#includeUnprocessed(redaction, true));
- const body = redactions.map(redaction => ({
- annotationId: redaction.id,
- comment: dialogResult.comment,
- removeFromDictionary,
- removeFromAllDossiers: !!dialogResult.option.extraOption?.checked || !!dialogResult.applyToAllDossiers,
- }));
+ const body = this.#getRemoveRedactionBody(redactions, dialogResult);
// todo: might not be correct, probably shouldn't get to this point if they are not all the same
const isHint = redactions.every(r => r.isHint);
const { dossierId, fileId } = this._state;
this.#processObsAndEmit(
- this._manualRedactionService.removeRedaction(body, dossierId, fileId, removeFromDictionary, isHint, includeUnprocessed),
+ this._manualRedactionService.removeRedaction(
+ body,
+ dossierId,
+ fileId,
+ removeFromDictionary,
+ isHint,
+ includeUnprocessed,
+ dialogResult.bulkLocal,
+ ),
).then();
}
@@ -505,4 +533,35 @@ export class AnnotationActionsService {
}
return false;
}
+
+ #getRemoveRedactionBody(
+ redactions: AnnotationWrapper[],
+ dialogResult: RemoveRedactionResult,
+ ): List | IBulkLocalRemoveRequest {
+ if (dialogResult.bulkLocal) {
+ const redaction = redactions[0];
+ if (redaction.value === NON_READABLE_CONTENT) {
+ return {
+ value: redaction.value,
+ rectangle: true,
+ position: redaction.entry.positions[0],
+ originTypes: [redaction.entry.type],
+ pageNumbers: [redaction.pageNumber],
+ };
+ }
+
+ return {
+ value: redaction.value,
+ rectangle: false,
+ };
+ }
+
+ return redactions.map(redaction => ({
+ annotationId: redaction.id,
+ value: redaction.value,
+ comment: dialogResult.comment,
+ removeFromDictionary: dialogResult.option.value === RemoveRedactionOptions.IN_DOSSIER,
+ removeFromAllDossiers: !!dialogResult.option.extraOption?.checked || !!dialogResult.applyToAllDossiers,
+ }));
+ }
}
diff --git a/apps/red-ui/src/app/modules/file-preview/services/manual-redaction.service.ts b/apps/red-ui/src/app/modules/file-preview/services/manual-redaction.service.ts
index dd90f6be4..36504f8db 100644
--- a/apps/red-ui/src/app/modules/file-preview/services/manual-redaction.service.ts
+++ b/apps/red-ui/src/app/modules/file-preview/services/manual-redaction.service.ts
@@ -8,6 +8,7 @@ import { type ManualRedactionEntryType } from '@models/file/manual-redaction-ent
import type {
DictionaryActions,
IAddRedactionRequest,
+ IBulkLocalRemoveRequest,
ILegalBasisChangeRequest,
IManualAddResponse,
IRecategorizationRequest,
@@ -39,6 +40,7 @@ function getMessage(action: ManualRedactionActions, isDictionary = false, error
export class ManualRedactionService extends GenericService {
protected readonly _defaultModelPath = 'manualRedaction';
readonly #bulkRedaction = `${this._defaultModelPath}/bulk/redaction`;
+ readonly #bulkLocal = `${this._defaultModelPath}/bulk-local`;
constructor(
private readonly _toaster: Toaster,
@@ -48,7 +50,13 @@ export class ManualRedactionService extends GenericService {
super();
}
- addRecommendation(annotations: AnnotationWrapper[], redaction: IAddRedactionRequest, dossierId: string, fileId: string) {
+ addRecommendation(
+ annotations: AnnotationWrapper[],
+ redaction: IAddRedactionRequest,
+ dossierId: string,
+ fileId: string,
+ bulkLocal: boolean = false,
+ ) {
const recommendations: List = annotations.map(annotation => ({
addToDictionary: redaction.addToDictionary,
addToAllDossiers: redaction.addToAllDossiers,
@@ -59,7 +67,7 @@ export class ManualRedactionService extends GenericService {
type: redaction.type ?? annotation.type,
comment: redaction.comment,
}));
- return this.addAnnotation(recommendations, dossierId, fileId);
+ return this.addAnnotation(recommendations, dossierId, fileId, { bulkLocal });
}
recategorizeRedactions(
@@ -80,14 +88,14 @@ export class ManualRedactionService extends GenericService {
requests: List,
dossierId: string,
fileId: string,
- options?: { hint?: boolean; dictionaryLabel?: string },
+ options?: { hint?: boolean; dictionaryLabel?: string; bulkLocal?: boolean },
) {
const toast = requests[0].addToDictionary
? this.#showAddToDictionaryToast(requests, options?.dictionaryLabel)
: this.#showToast(options?.hint ? 'force-hint' : 'add');
const canAddRedaction = this._iqserPermissionsService.has(Roles.redactions.write);
if (canAddRedaction) {
- return this.add(requests, dossierId, fileId).pipe(toast);
+ return this.add(requests, dossierId, fileId, options.bulkLocal).pipe(toast);
}
return of(undefined);
@@ -102,14 +110,15 @@ export class ManualRedactionService extends GenericService {
}
removeRedaction(
- body: List,
+ body: List | IBulkLocalRemoveRequest,
dossierId: string,
fileId: string,
removeFromDictionary = false,
isHint = false,
includeUnprocessed = false,
+ bulkLocal = false,
) {
- return this.remove(body, dossierId, fileId, includeUnprocessed).pipe(
+ return this.remove(body, dossierId, fileId, includeUnprocessed, bulkLocal).pipe(
this.#showToast(!isHint ? 'remove' : 'remove-hint', removeFromDictionary),
);
}
@@ -127,8 +136,9 @@ export class ManualRedactionService extends GenericService {
}
}
- add(body: List, dossierId: string, fileId: string) {
- return this._post(body, `${this.#bulkRedaction}/add/${dossierId}/${fileId}`).pipe(this.#log('Add', body));
+ add(body: List, dossierId: string, fileId: string, bulkLocal = false) {
+ const bulkPath = bulkLocal ? this.#bulkLocal : this.#bulkRedaction;
+ return this._post(bulkLocal ? body[0] : body, `${bulkPath}/add/${dossierId}/${fileId}`).pipe(this.#log('Add', body));
}
recategorize(body: List, dossierId: string, fileId: string, includeUnprocessed = false) {
@@ -142,8 +152,15 @@ export class ManualRedactionService extends GenericService {
return super.delete(annotationIds, url).pipe(this.#log('Undo', annotationIds));
}
- remove(body: List, dossierId: string, fileId: string, includeUnprocessed = false) {
- return this._post(body, `${this.#bulkRedaction}/remove/${dossierId}/${fileId}?includeUnprocessed=${includeUnprocessed}`).pipe(
+ remove(
+ body: List | IBulkLocalRemoveRequest,
+ dossierId: string,
+ fileId: string,
+ includeUnprocessed = false,
+ bulkLocal = false,
+ ) {
+ const bulkPath = bulkLocal ? this.#bulkLocal : this.#bulkRedaction;
+ return this._post(body, `${bulkPath}/remove/${dossierId}/${fileId}?includeUnprocessed=${includeUnprocessed}`).pipe(
this.#log('Remove', body),
);
}
diff --git a/apps/red-ui/src/app/modules/file-preview/utils/dialog-options.ts b/apps/red-ui/src/app/modules/file-preview/utils/dialog-options.ts
index 7aff7bccd..35dd23be6 100644
--- a/apps/red-ui/src/app/modules/file-preview/utils/dialog-options.ts
+++ b/apps/red-ui/src/app/modules/file-preview/utils/dialog-options.ts
@@ -7,6 +7,7 @@ import { removeAnnotationTranslations } from '@translations/remove-annotation-tr
import { removeRedactionTranslations } from '@translations/remove-redaction-translations';
import { resizeRedactionTranslations } from '@translations/resize-redaction-translations';
import {
+ ForceAnnotationOption,
RedactOrHintOption,
RedactOrHintOptions,
RemoveRedactionData,
@@ -17,6 +18,7 @@ import {
} from './dialog-types';
const PIN_ICON = 'red:push-pin';
+const DOCUMENT_ICON = 'iqser:document';
const FOLDER_ICON = 'red:folder';
const REMOVE_FROM_DICT_ICON = 'red:remove-from-dict';
@@ -77,6 +79,15 @@ export const getRedactOrHintOptions = (
return options;
}
+ if (!isHint) {
+ options.push({
+ label: redactTextTranslations.inDocument.label,
+ description: redactTextTranslations.inDocument.description,
+ icon: DOCUMENT_ICON,
+ value: ResizeOptions.IN_DOCUMENT,
+ });
+ }
+
options.push({
label: translations.inDossier.label,
description: translations.inDossier.description,
@@ -156,6 +167,13 @@ export const getRemoveRedactionOptions = (
icon: PIN_ICON,
value: RemoveRedactionOptions.ONLY_HERE,
});
+
+ options.push({
+ label: removeRedactionTranslations.IN_DOCUMENT.label,
+ description: removeRedactionTranslations.IN_DOCUMENT.description,
+ icon: DOCUMENT_ICON,
+ value: RemoveRedactionOptions.IN_DOCUMENT,
+ });
}
if (permissions.canRemoveFromDictionary) {
options.push({
@@ -217,3 +235,24 @@ export const getRemoveRedactionOptions = (
}
return options;
};
+
+export const getForceAnnotationOptions = (isDocumine: boolean, isHint: boolean): DetailsRadioOption[] => {
+ if (isDocumine || isHint) {
+ return [];
+ }
+
+ return [
+ {
+ label: redactTextTranslations.onlyHere.label,
+ description: redactTextTranslations.onlyHere.description,
+ icon: PIN_ICON,
+ value: ResizeOptions.ONLY_HERE,
+ },
+ {
+ label: redactTextTranslations.inDocument.label,
+ description: redactTextTranslations.inDocument.description,
+ icon: DOCUMENT_ICON,
+ value: ResizeOptions.IN_DOCUMENT,
+ },
+ ];
+};
diff --git a/apps/red-ui/src/app/modules/file-preview/utils/dialog-types.ts b/apps/red-ui/src/app/modules/file-preview/utils/dialog-types.ts
index 8fcac6603..d7efb27eb 100644
--- a/apps/red-ui/src/app/modules/file-preview/utils/dialog-types.ts
+++ b/apps/red-ui/src/app/modules/file-preview/utils/dialog-types.ts
@@ -5,16 +5,25 @@ import { Dictionary, Dossier, File, IAddRedactionRequest, IManualRedactionEntry
export const RedactOrHintOptions = {
ONLY_HERE: 'ONLY_HERE',
+ IN_DOCUMENT: 'IN_DOCUMENT',
IN_DOSSIER: 'IN_DOSSIER',
} as const;
export type RedactOrHintOption = keyof typeof RedactOrHintOptions;
+export const ForceAnnotationOptions = {
+ ONLY_HERE: 'ONLY_HERE',
+ IN_DOCUMENT: 'IN_DOCUMENT',
+} as const;
+
+export type ForceAnnotationOption = keyof typeof ForceAnnotationOptions;
+
export const ResizeOptions = RedactOrHintOptions;
export type ResizeRedactionOption = RedactOrHintOption;
export const RemoveRedactionOptions = {
ONLY_HERE: 'ONLY_HERE',
+ IN_DOCUMENT: 'IN_DOCUMENT',
IN_DOSSIER: 'IN_DOSSIER',
FALSE_POSITIVE: 'FALSE_POSITIVE',
DO_NOT_RECOMMEND: 'DO_NOT_RECOMMEND',
@@ -46,6 +55,7 @@ export type AddHintData = RedactTextData;
export interface RedactTextResult {
redaction: IManualRedactionEntry;
dictionary: Dictionary;
+ bulkLocal?: boolean;
}
export type RedactRecommendationData = EditRedactionData;
@@ -53,6 +63,7 @@ export type RedactRecommendationData = EditRedactionData;
export interface RedactRecommendationResult {
redaction: IAddRedactionRequest;
isMulti: boolean;
+ bulkLocal: boolean;
}
export interface EditRedactResult {
@@ -112,6 +123,7 @@ export interface RemoveRedactionResult {
comment: string;
option: DetailsRadioOption;
applyToAllDossiers?: boolean;
+ bulkLocal?: boolean;
}
export type RemoveAnnotationResult = RemoveRedactionResult;
diff --git a/apps/red-ui/src/app/modules/file-preview/utils/enhance-manual-redaction-request.utils.ts b/apps/red-ui/src/app/modules/file-preview/utils/enhance-manual-redaction-request.utils.ts
new file mode 100644
index 000000000..25291fd22
--- /dev/null
+++ b/apps/red-ui/src/app/modules/file-preview/utils/enhance-manual-redaction-request.utils.ts
@@ -0,0 +1,40 @@
+import { Dictionary, IAddRedactionRequest, SuperType } from '@red/domain';
+import { LegalBasisOption } from '../dialogs/manual-redaction-dialog/manual-annotation-dialog.component';
+
+export interface EnhanceRequestData {
+ readonly type: SuperType | null;
+ readonly selectedText: string;
+ readonly reason: LegalBasisOption;
+ readonly dictionaries: Dictionary[];
+ readonly dictionaryRequest: boolean;
+ readonly comment: string;
+ readonly isApprover: boolean;
+ readonly applyToAllDossiers: boolean;
+}
+
+export const enhanceManualRedactionRequest = (addRedactionRequest: IAddRedactionRequest, data: EnhanceRequestData) => {
+ addRedactionRequest.type = data.type;
+ addRedactionRequest.section = null;
+ addRedactionRequest.value = data.selectedText;
+
+ const legalOption: LegalBasisOption = data.reason;
+ if (legalOption) {
+ addRedactionRequest.reason = legalOption.description;
+ addRedactionRequest.legalBasis = legalOption.legalBasis;
+ }
+
+ const selectedType = data.dictionaries.find(d => d.type === addRedactionRequest.type);
+
+ if (selectedType) {
+ addRedactionRequest.addToDictionary = selectedType.hasDictionary;
+ } else {
+ addRedactionRequest.addToDictionary = data.dictionaryRequest && addRedactionRequest.type !== 'dossier_redaction';
+ }
+
+ if (!addRedactionRequest.reason) {
+ addRedactionRequest.reason = 'Dictionary Request';
+ }
+ const commentValue = data.comment;
+ addRedactionRequest.comment = commentValue ? { text: commentValue } : null;
+ addRedactionRequest.addToAllDossiers = data.isApprover && data.dictionaryRequest && data.applyToAllDossiers;
+};
diff --git a/apps/red-ui/src/app/translations/redact-text-translations.ts b/apps/red-ui/src/app/translations/redact-text-translations.ts
index 76bfadb81..a5166ca86 100644
--- a/apps/red-ui/src/app/translations/redact-text-translations.ts
+++ b/apps/red-ui/src/app/translations/redact-text-translations.ts
@@ -9,11 +9,15 @@ export interface DialogOption {
extraOptionDescription?: string;
}
-export const redactTextTranslations: Record<'onlyHere' | 'inDossier', DialogOption> = {
+export const redactTextTranslations: Record<'onlyHere' | 'inDocument' | 'inDossier', DialogOption> = {
onlyHere: {
label: _('redact-text.dialog.content.options.only-here.label'),
description: _('redact-text.dialog.content.options.only-here.description'),
},
+ inDocument: {
+ label: _('redact-text.dialog.content.options.in-document.label'),
+ description: _('redact-text.dialog.content.options.in-document.description'),
+ },
inDossier: {
label: _('redact-text.dialog.content.options.in-dossier.label'),
description: _('redact-text.dialog.content.options.in-dossier.description'),
diff --git a/apps/red-ui/src/app/translations/remove-annotation-translations.ts b/apps/red-ui/src/app/translations/remove-annotation-translations.ts
index 478c9de8d..e6cd09f1a 100644
--- a/apps/red-ui/src/app/translations/remove-annotation-translations.ts
+++ b/apps/red-ui/src/app/translations/remove-annotation-translations.ts
@@ -8,6 +8,10 @@ export const removeAnnotationTranslations: { [key in RemoveAnnotationOption]: Di
description: _('remove-annotation.dialog.content.options.only-here.description'),
descriptionBulk: _('remove-annotation.dialog.content.options.only-here.description-bulk'),
},
+ IN_DOCUMENT: {
+ label: _('remove-annotation.dialog.content.options.in-document.label'),
+ description: _('remove-annotation.dialog.content.options.in-document.description'),
+ },
IN_DOSSIER: {
label: _('remove-annotation.dialog.content.options.in-dossier.label'),
labelBulk: _('remove-annotation.dialog.content.options.in-dossier.label-bulk'),
diff --git a/apps/red-ui/src/app/translations/remove-redaction-translations.ts b/apps/red-ui/src/app/translations/remove-redaction-translations.ts
index 41d5f8b86..910415bca 100644
--- a/apps/red-ui/src/app/translations/remove-redaction-translations.ts
+++ b/apps/red-ui/src/app/translations/remove-redaction-translations.ts
@@ -8,6 +8,10 @@ export const removeRedactionTranslations: { [key in RemoveRedactionOption]: Dial
description: _('remove-redaction.dialog.content.options.only-here.description'),
descriptionBulk: _('remove-redaction.dialog.content.options.only-here.description-bulk'),
},
+ IN_DOCUMENT: {
+ label: _('remove-redaction.dialog.content.options.in-document.label'),
+ description: _('remove-redaction.dialog.content.options.in-document.description'),
+ },
IN_DOSSIER: {
label: _('remove-redaction.dialog.content.options.in-dossier.label'),
labelBulk: _('remove-redaction.dialog.content.options.in-dossier.label-bulk'),
diff --git a/apps/red-ui/src/assets/config/config.json b/apps/red-ui/src/assets/config/config.json
index 5f6c0ce6e..deb14e6da 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://dan2.iqser.cloud",
+ "API_URL": "https://dan1.iqser.cloud",
"APP_NAME": "RedactManager",
"IS_DOCUMINE": false,
"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://dan2.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 aa1b41c55..6378ab8d2 100644
--- a/apps/red-ui/src/assets/i18n/redact/de.json
+++ b/apps/red-ui/src/assets/i18n/redact/de.json
@@ -2074,6 +2074,10 @@
"edit-text": "Text bearbeiten",
"legal-basis": "Rechtsgrundlage",
"options": {
+ "in-document": {
+ "description": "",
+ "label": ""
+ },
"in-dossier": {
"description": "Fügen Sie die Schwärzung zu jedem Dokument in {dossierName} hinzu.",
"extraOptionLabel": "In alle aktiven und zukünftigen Dossiers übernehmen",
@@ -2113,6 +2117,10 @@
"description-bulk": "",
"label": "In diesem Kontext aus dem Dossier entfernen"
},
+ "in-document": {
+ "description": "",
+ "label": ""
+ },
"in-dossier": {
"description": "Annotieren Sie den Begriff in diesem Dossier nicht.",
"description-bulk": "",
@@ -2153,6 +2161,10 @@
"extraOptionLabel": "In alle aktiven und zukünftigen Dossiers übernehmen",
"label": "In diesem Kontext aus Dossier entfernen"
},
+ "in-document": {
+ "description": "",
+ "label": ""
+ },
"in-dossier": {
"description": "Der Begriff wird in keinem Dokument dieses Dossiers {type, select, hint{annotiert} other{automatisch geschwärzt}}.",
"description-bulk": "Die ausgewählten Begriffe werden in diesem Dossier nicht {type, select, hint{annotiert} other{automatisch geschwärzt}}.",
diff --git a/apps/red-ui/src/assets/i18n/redact/en.json b/apps/red-ui/src/assets/i18n/redact/en.json
index 2520c4e6a..cd5b0a83b 100644
--- a/apps/red-ui/src/assets/i18n/redact/en.json
+++ b/apps/red-ui/src/assets/i18n/redact/en.json
@@ -2074,6 +2074,10 @@
"edit-text": "Edit text",
"legal-basis": "Legal basis",
"options": {
+ "in-document": {
+ "description": "Add redaction for each occurrence of the term in this document.",
+ "label": "Redact in document"
+ },
"in-dossier": {
"description": "Add redaction in every document in {dossierName}.",
"extraOptionLabel": "Apply to all active and future dossiers",
@@ -2113,6 +2117,10 @@
"description-bulk": "",
"label": "Remove from dossier in this context"
},
+ "in-document": {
+ "description": "",
+ "label": ""
+ },
"in-dossier": {
"description": "Do not annotate the term in this dossier.",
"description-bulk": "",
@@ -2153,6 +2161,10 @@
"extraOptionLabel": "Apply to all active and future dossiers",
"label": "Remove from dossier in this context"
},
+ "in-document": {
+ "description": "Do not auto-redact the selected term in any pages of this document.",
+ "label": "Remove from document"
+ },
"in-dossier": {
"description": "Do not {type, select, hint{annotate} other{auto-redact}} the selected term in any document of this dossier.",
"description-bulk": "Do not {type, select, hint{annotate} other{auto-redact}} the selected terms in this dossier.",
diff --git a/apps/red-ui/src/assets/i18n/scm/de.json b/apps/red-ui/src/assets/i18n/scm/de.json
index 9c5487add..81e9103ce 100644
--- a/apps/red-ui/src/assets/i18n/scm/de.json
+++ b/apps/red-ui/src/assets/i18n/scm/de.json
@@ -2074,6 +2074,10 @@
"edit-text": "",
"legal-basis": "Legal basis",
"options": {
+ "in-document": {
+ "description": "",
+ "label": ""
+ },
"in-dossier": {
"description": "Add redaction in every document in {dossierName}.",
"extraOptionLabel": "Apply to all dossiers",
@@ -2113,6 +2117,10 @@
"description-bulk": "The selected items should not be annotated in their respective contexts.",
"label": "False positive"
},
+ "in-document": {
+ "description": "",
+ "label": ""
+ },
"in-dossier": {
"description": "Do not annotate ''{value}'' as ''{type}'' in any dossier.",
"description-bulk": "Do not annotate the selected terms as their respective types in any dossier.",
@@ -2153,6 +2161,10 @@
"extraOptionLabel": "Apply to all dossiers",
"label": "False positive"
},
+ "in-document": {
+ "description": "",
+ "label": ""
+ },
"in-dossier": {
"description": "Do not {type} \"{value}\" in any document of the current dossier.",
"description-bulk": "",
diff --git a/apps/red-ui/src/assets/i18n/scm/en.json b/apps/red-ui/src/assets/i18n/scm/en.json
index b5c317bd4..78af81ffd 100644
--- a/apps/red-ui/src/assets/i18n/scm/en.json
+++ b/apps/red-ui/src/assets/i18n/scm/en.json
@@ -2074,6 +2074,10 @@
"edit-text": "",
"legal-basis": "Legal basis",
"options": {
+ "in-document": {
+ "description": "Add redaction for each occurrence of the term in this document.",
+ "label": "Redact in document"
+ },
"in-dossier": {
"description": "Add redaction in every document in {dossierName}.",
"extraOptionLabel": "Apply to all dossiers",
@@ -2113,6 +2117,10 @@
"description-bulk": "The selected items should not be annotated in their respective contexts.",
"label": "False positive"
},
+ "in-document": {
+ "description": "",
+ "label": ""
+ },
"in-dossier": {
"description": "Do not annotate ''{value}'' as ''{type}'' in any dossier.",
"description-bulk": "Do not annotate the selected terms as their respective types in any dossier.",
@@ -2153,6 +2161,10 @@
"extraOptionLabel": "Apply to all dossiers",
"label": "False positive"
},
+ "in-document": {
+ "description": "",
+ "label": ""
+ },
"in-dossier": {
"description": "Do not {type} \"{value}\" in any document of the current dossier.",
"description-bulk": "",
diff --git a/libs/red-domain/src/lib/legal-basis/legal-basis-change.request.ts b/libs/red-domain/src/lib/legal-basis/legal-basis-change.request.ts
index e1d95b092..de3e9f2e1 100644
--- a/libs/red-domain/src/lib/legal-basis/legal-basis-change.request.ts
+++ b/libs/red-domain/src/lib/legal-basis/legal-basis-change.request.ts
@@ -1,5 +1,9 @@
+import { ForceAnnotationOption } from '../../../../../apps/red-ui/src/app/modules/file-preview/utils/dialog-types';
+
export interface ILegalBasisChangeRequest {
annotationId?: string;
comment?: string;
legalBasis?: string;
+ reason?: string;
+ option?: ForceAnnotationOption;
}
diff --git a/libs/red-domain/src/lib/redaction-log/remove-redaction.request.ts b/libs/red-domain/src/lib/redaction-log/remove-redaction.request.ts
index 40290994a..364198733 100644
--- a/libs/red-domain/src/lib/redaction-log/remove-redaction.request.ts
+++ b/libs/red-domain/src/lib/redaction-log/remove-redaction.request.ts
@@ -1,5 +1,19 @@
+import { IEntityLogEntryPosition } from './entity-log-entry';
+
export interface IRemoveRedactionRequest {
annotationId?: string;
comment?: string;
removeFromDictionary?: boolean;
+ removeFromAllDossiers?: boolean;
+ value?: string;
+}
+
+export interface IBulkLocalRemoveRequest {
+ rectangle: boolean;
+ value: string;
+ caseSensitive?: boolean;
+ position?: IEntityLogEntryPosition;
+ originTypes?: string[];
+ originLegalBases?: string[];
+ pageNumbers?: number[];
}