Merge branch 'RED-7346' into 'master'

RED-7346: bulk-local edit redactions

Closes RED-7346

See merge request redactmanager/red-ui!590
This commit is contained in:
Dan Percic 2024-09-26 13:35:30 +02:00
commit d457f9a46f
15 changed files with 140 additions and 156 deletions

View File

@ -6,8 +6,8 @@
class="dialog-header heading-l" class="dialog-header heading-l"
></div> ></div>
<div class="dialog-content redaction" [class.fixed-height]="isRedacted && isImage"> <div [class.fixed-height]="isRedacted && isImage" class="dialog-content redaction">
<div class="iqser-input-group" *ngIf="!isImage && redactedTexts.length && !allRectangles"> <div *ngIf="!isImage && redactedTexts.length && !allRectangles" class="iqser-input-group">
<redaction-selected-annotations-table <redaction-selected-annotations-table
[columns]="tableColumns" [columns]="tableColumns"
[data]="tableData" [data]="tableData"
@ -15,7 +15,13 @@
></redaction-selected-annotations-table> ></redaction-selected-annotations-table>
</div> </div>
<div *ngIf="!isManualRedaction" class="iqser-input-group w-450" [class.required]="!form.controls.type.disabled"> <iqser-details-radio
*ngIf="!isImage && annotations.length === 1"
[options]="options"
formControlName="option"
></iqser-details-radio>
<div *ngIf="!isManualRedaction" [class.required]="!form.controls.type.disabled" class="iqser-input-group w-450">
<label [translate]="'edit-redaction.dialog.content.type'"></label> <label [translate]="'edit-redaction.dialog.content.type'"></label>
<mat-form-field> <mat-form-field>

View File

@ -5,7 +5,6 @@ import { MatDialogClose } from '@angular/material/dialog';
import { MatFormField } from '@angular/material/form-field'; import { MatFormField } from '@angular/material/form-field';
import { MatOption, MatSelect, MatSelectTrigger } from '@angular/material/select'; import { MatOption, MatSelect, MatSelectTrigger } from '@angular/material/select';
import { MatTooltip } from '@angular/material/tooltip'; import { MatTooltip } from '@angular/material/tooltip';
import { DetailsRadioOption } from '@common-ui/inputs/details-radio/details-radio-option';
import { import {
CircleButtonComponent, CircleButtonComponent,
HasScrollbarDirective, HasScrollbarDirective,
@ -26,10 +25,11 @@ import {
SelectedAnnotationsTableComponent, SelectedAnnotationsTableComponent,
ValueColumn, ValueColumn,
} from '../../components/selected-annotations-table/selected-annotations-table.component'; } from '../../components/selected-annotations-table/selected-annotations-table.component';
import { DialogHelpModeKeys } from '../../utils/constants';
import { getEditRedactionOptions } from '../../utils/dialog-options'; import { getEditRedactionOptions } from '../../utils/dialog-options';
import { EditRedactionData, EditRedactResult, RedactOrHintOption } from '../../utils/dialog-types'; import { EditRedactionData, EditRedactionOption, EditRedactResult } from '../../utils/dialog-types';
import { LegalBasisOption } from '../manual-redaction-dialog/manual-annotation-dialog.component'; import { LegalBasisOption } from '../manual-redaction-dialog/manual-annotation-dialog.component';
import { DetailsRadioComponent } from '@common-ui/inputs/details-radio/details-radio.component';
import { DetailsRadioOption } from '@common-ui/inputs/details-radio/details-radio-option';
interface TypeSelectOptions { interface TypeSelectOptions {
type: string; type: string;
@ -58,18 +58,16 @@ interface TypeSelectOptions {
HelpButtonComponent, HelpButtonComponent,
MatDialogClose, MatDialogClose,
HasScrollbarDirective, HasScrollbarDirective,
DetailsRadioComponent,
], ],
}) })
export class EditRedactionDialogComponent export class EditRedactionDialogComponent
extends IqserDialogComponent<EditRedactionDialogComponent, EditRedactionData, EditRedactResult> extends IqserDialogComponent<EditRedactionDialogComponent, EditRedactionData, EditRedactResult>
implements OnInit implements OnInit
{ {
readonly #dossier = inject(ActiveDossiersService).find(this.data.dossierId); readonly ignoredKeys = ['option', 'comment'];
readonly #applyToAllDossiers = this.data.applyToAllDossiers;
protected readonly roles = Roles;
readonly annotations = this.data.annotations; readonly annotations = this.data.annotations;
readonly iconButtonTypes = IconButtonTypes; readonly iconButtonTypes = IconButtonTypes;
readonly isModifyDictionary = this.annotations.every(annotation => annotation.isModifyDictionary);
readonly isImage = this.annotations.reduce((acc, next) => acc && next.isImage, true); readonly isImage = this.annotations.reduce((acc, next) => acc && next.isImage, true);
readonly redactedTexts = !this.isImage ? this.annotations.map(annotation => annotation.value).filter(value => !!value) : null; readonly redactedTexts = !this.isImage ? this.annotations.map(annotation => annotation.value).filter(value => !!value) : null;
readonly isManualRedaction = this.annotations.some(annotation => annotation.type === SuperTypes.ManualRedaction); readonly isManualRedaction = this.annotations.some(annotation => annotation.type === SuperTypes.ManualRedaction);
@ -82,13 +80,15 @@ export class EditRedactionDialogComponent
{ label: redaction.value, bold: true }, { label: redaction.value, bold: true },
{ label: redaction.typeLabel }, { label: redaction.typeLabel },
]); ]);
options: DetailsRadioOption<RedactOrHintOption>[] | undefined; options = getEditRedactionOptions();
legalOptions: LegalBasisOption[] = []; legalOptions: LegalBasisOption[] = [];
dictionaries: Dictionary[] = []; dictionaries: Dictionary[] = [];
typeSelectOptions: TypeSelectOptions[] = []; typeSelectOptions: TypeSelectOptions[] = [];
readonly form = this.#getForm(); readonly form = this.#getForm();
hasTypeChanged = false; hasTypeChanged = false;
initialReasonDisabled = this.someSkipped; initialReasonDisabled = this.someSkipped;
protected readonly roles = Roles;
readonly #dossier = inject(ActiveDossiersService).find(this.data.dossierId);
constructor( constructor(
private readonly _justificationsService: JustificationsService, private readonly _justificationsService: JustificationsService,
@ -144,16 +144,6 @@ export class EditRedactionDialogComponent
return this.annotations.length > 1; return this.annotations.length > 1;
} }
get helpButtonKey() {
if (this.isHint) {
return DialogHelpModeKeys.HINT_EDIT;
}
if (this.someSkipped) {
return DialogHelpModeKeys.SKIPPED_EDIT;
}
return DialogHelpModeKeys.REDACTION_EDIT;
}
get sameType() { get sameType() {
return this.annotations.every(annotation => annotation.type === this.annotations[0].type); return this.annotations.every(annotation => annotation.type === this.annotations[0].type);
} }
@ -179,7 +169,6 @@ export class EditRedactionDialogComponent
typeChanged() { typeChanged() {
const selectedDictionaryType = this.form.controls.type.value; const selectedDictionaryType = this.form.controls.type.value;
this.#setOptions(selectedDictionaryType);
const initialReason = this.form.get('type').value === this.initialFormValue.type && !this.initialReasonDisabled; const initialReason = this.form.get('type').value === this.initialFormValue.type && !this.initialReasonDisabled;
if (this.redactBasedTypes.includes(selectedDictionaryType) || initialReason) { if (this.redactBasedTypes.includes(selectedDictionaryType) || initialReason) {
@ -193,7 +182,7 @@ export class EditRedactionDialogComponent
} else { } else {
this.form.controls.reason.disable(); this.form.controls.reason.disable();
} }
this.form.patchValue({ reason: null, option: null }); this.form.patchValue({ reason: null });
} }
save() { save() {
@ -206,6 +195,7 @@ export class EditRedactionDialogComponent
comment: value.comment, comment: value.comment,
type: value.type, type: value.type,
value: this.allRectangles ? value.value : null, value: this.allRectangles ? value.value : null,
option: value.option.value,
}); });
} }
@ -230,22 +220,6 @@ export class EditRedactionDialogComponent
} }
} }
#setOptions(type: string, reasonChanged = false) {
const selectedDictionary = this.dictionaries.find(d => d.type === type);
this.options = getEditRedactionOptions(
this.#dossier.dossierName,
this.#applyToAllDossiers,
!!selectedDictionary?.dossierDictionaryOnly,
this.isModifyDictionary,
);
this.form.patchValue(
{
option: !this.isModifyDictionary || reasonChanged ? this.options[0] : this.options[1],
},
{ emitEvent: false },
);
}
#getForm() { #getForm() {
const sameSection = this.annotations.every(annotation => annotation.section === this.annotations[0].section); const sameSection = this.annotations.every(annotation => annotation.section === this.annotations[0].section);
return new FormGroup({ return new FormGroup({
@ -256,7 +230,7 @@ export class EditRedactionDialogComponent
disabled: this.isImported, disabled: this.isImported,
}), }),
section: new FormControl<string>({ value: sameSection ? this.annotations[0].section : null, disabled: this.isImported }), section: new FormControl<string>({ value: sameSection ? this.annotations[0].section : null, disabled: this.isImported }),
option: new FormControl<LegalBasisOption>(null), option: new FormControl<DetailsRadioOption<EditRedactionOption>>(this.options[0]),
value: new FormControl<string>(this.allRectangles ? this.annotations[0].value : null), value: new FormControl<string>(this.allRectangles ? this.annotations[0].value : null),
}); });
} }

View File

@ -24,7 +24,6 @@ import {
SelectedAnnotationsTableComponent, SelectedAnnotationsTableComponent,
ValueColumn, ValueColumn,
} from '../../components/selected-annotations-table/selected-annotations-table.component'; } from '../../components/selected-annotations-table/selected-annotations-table.component';
import { DialogHelpModeKeys } from '../../utils/constants';
import { getRemoveRedactionOptions } from '../../utils/dialog-options'; import { getRemoveRedactionOptions } from '../../utils/dialog-options';
import { import {
RemoveRedactionData, RemoveRedactionData,

View File

@ -9,6 +9,7 @@ import {
DictionaryEntryTypes, DictionaryEntryTypes,
EarmarkOperation, EarmarkOperation,
type IBulkLocalRemoveRequest, type IBulkLocalRemoveRequest,
IBulkRecategorizationRequest,
ILegalBasisChangeRequest, ILegalBasisChangeRequest,
IRecategorizationRequest, IRecategorizationRequest,
IRectangle, IRectangle,
@ -34,6 +35,7 @@ import {
EditRedactionData, EditRedactionData,
EditRedactResult, EditRedactResult,
ForceAnnotationOptions, ForceAnnotationOptions,
RedactOrHintOptions,
RemoveRedactionData, RemoveRedactionData,
RemoveRedactionOptions, RemoveRedactionOptions,
RemoveRedactionPermissions, RemoveRedactionPermissions,
@ -108,13 +110,11 @@ export class AnnotationActionsService {
} }
async editRedaction(annotations: AnnotationWrapper[]) { async editRedaction(annotations: AnnotationWrapper[]) {
const { dossierId, dossierTemplateId, fileId, file } = this._state; const { dossierId, fileId } = this._state;
const includeUnprocessed = annotations.every(annotation => this.#includeUnprocessed(annotation, true)); const includeUnprocessed = annotations.every(annotation => this.#includeUnprocessed(annotation, true));
const dossierTemplate = this._dossierTemplatesService.find(dossierTemplateId);
const data = { const data = {
annotations, annotations,
dossierId, dossierId,
applyToAllDossiers: dossierTemplate.applyDictionaryUpdatesToAllDossiersByDefault,
}; };
const result = await this.#getEditRedactionDialog(data).result(); const result = await this.#getEditRedactionDialog(data).result();
@ -122,22 +122,38 @@ export class AnnotationActionsService {
return; return;
} }
const recategorizeBody: List<IRecategorizationRequest> = annotations.map(annotation => { let recategorizeBody: List<IRecategorizationRequest> | IBulkRecategorizationRequest;
const body: IRecategorizationRequest = {
annotationId: annotation.id, if (result.option === RedactOrHintOptions.ONLY_HERE) {
type: result.type ?? annotation.type, recategorizeBody = annotations.map(annotation => {
comment: result.comment, const body: IRecategorizationRequest = {
}; annotationId: annotation.id,
if (!this.#isDocumine) { type: result.type ?? annotation.type,
return { comment: result.comment,
...body,
legalBasis: result.legalBasis,
section: result.section ?? annotation.section,
value: result.value ?? annotation.value,
}; };
} if (!this.#isDocumine) {
return body; return {
}); ...body,
legalBasis: result.legalBasis,
section: result.section ?? annotation.section,
value: result.value ?? annotation.value,
};
}
return body;
});
} else {
const originTypes = annotations.map(a => a.type);
const originLegalBases = annotations.map(a => a.legalBasis);
recategorizeBody = {
value: annotations[0].value,
type: result.type,
legalBasis: result.legalBasis,
section: result.section,
originTypes,
originLegalBases,
rectangle: false,
};
}
await this.#processObsAndEmit( await this.#processObsAndEmit(
this._manualRedactionService this._manualRedactionService
@ -147,6 +163,7 @@ export class AnnotationActionsService {
fileId, fileId,
this.#getChangedFields(annotations, result), this.#getChangedFields(annotations, result),
includeUnprocessed, includeUnprocessed,
result.option === RedactOrHintOptions.IN_DOCUMENT,
) )
.pipe(log()), .pipe(log()),
); );

View File

@ -9,6 +9,7 @@ import type {
DictionaryActions, DictionaryActions,
IAddRedactionRequest, IAddRedactionRequest,
IBulkLocalRemoveRequest, IBulkLocalRemoveRequest,
IBulkRecategorizationRequest,
ILegalBasisChangeRequest, ILegalBasisChangeRequest,
IManualAddResponse, IManualAddResponse,
IRecategorizationRequest, IRecategorizationRequest,
@ -71,15 +72,16 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
} }
recategorizeRedactions( recategorizeRedactions(
body: List<IRecategorizationRequest>, body: List<IRecategorizationRequest> | IBulkRecategorizationRequest,
dossierId: string, dossierId: string,
fileId: string, fileId: string,
successMessageParameters?: { successMessageParameters?: {
[key: string]: string; [key: string]: string;
}, },
includeUnprocessed = false, includeUnprocessed = false,
bulkLocal = false,
) { ) {
return this.recategorize(body, dossierId, fileId, includeUnprocessed).pipe( return this.#recategorize(body, dossierId, fileId, includeUnprocessed, bulkLocal).pipe(
this.#showToast('recategorize-annotation', false, successMessageParameters), this.#showToast('recategorize-annotation', false, successMessageParameters),
); );
} }
@ -118,7 +120,7 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
includeUnprocessed = false, includeUnprocessed = false,
bulkLocal = false, bulkLocal = false,
) { ) {
return this.remove(body, dossierId, fileId, includeUnprocessed, bulkLocal).pipe( return this.#remove(body, dossierId, fileId, includeUnprocessed, bulkLocal).pipe(
this.#showToast(!isHint ? 'remove' : 'remove-hint', removeFromDictionary), this.#showToast(!isHint ? 'remove' : 'remove-hint', removeFromDictionary),
); );
} }
@ -141,30 +143,11 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
return this._post(bulkLocal ? body[0] : body, `${bulkPath}/add/${dossierId}/${fileId}`).pipe(this.#log('Add', body)); return this._post(bulkLocal ? body[0] : body, `${bulkPath}/add/${dossierId}/${fileId}`).pipe(this.#log('Add', body));
} }
recategorize(body: List<IRecategorizationRequest>, dossierId: string, fileId: string, includeUnprocessed = false) {
return this._post(body, `${this.#bulkRedaction}/recategorize/${dossierId}/${fileId}?includeUnprocessed=${includeUnprocessed}`).pipe(
this.#log('Recategorize', body),
);
}
undo(annotationIds: List, dossierId: string, fileId: string) { undo(annotationIds: List, dossierId: string, fileId: string) {
const url = `${this._defaultModelPath}/bulk/undo/${dossierId}/${fileId}`; const url = `${this._defaultModelPath}/bulk/undo/${dossierId}/${fileId}`;
return super.delete(annotationIds, url).pipe(this.#log('Undo', annotationIds)); return super.delete(annotationIds, url).pipe(this.#log('Undo', annotationIds));
} }
remove(
body: List<IRemoveRedactionRequest> | 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),
);
}
forceRedaction(body: List<ILegalBasisChangeRequest>, dossierId: string, fileId: string) { forceRedaction(body: List<ILegalBasisChangeRequest>, dossierId: string, fileId: string) {
return this._post(body, `${this.#bulkRedaction}/force/${dossierId}/${fileId}`).pipe(this.#log('Force redaction', body)); return this._post(body, `${this.#bulkRedaction}/force/${dossierId}/${fileId}`).pipe(this.#log('Force redaction', body));
} }
@ -175,6 +158,32 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
); );
} }
#recategorize(
body: List<IRecategorizationRequest> | IBulkRecategorizationRequest,
dossierId: string,
fileId: string,
includeUnprocessed = false,
bulkLocal = false,
) {
const bulkPath = bulkLocal ? this.#bulkLocal : this.#bulkRedaction;
return this._post(body, `${bulkPath}/recategorize/${dossierId}/${fileId}?includeUnprocessed=${includeUnprocessed}`).pipe(
this.#log('Recategorize', body),
);
}
#remove(
body: List<IRemoveRedactionRequest> | 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),
);
}
#log(action: string, body: unknown) { #log(action: string, body: unknown) {
return tap(response => { return tap(response => {
this._logger.info(`[MANUAL-REDACTIONS] ${action} `, body, response); this._logger.info(`[MANUAL-REDACTIONS] ${action} `, body, response);

View File

@ -19,16 +19,6 @@ export const ActionsHelpModeKeys = {
'hint-image': 'hint', 'hint-image': 'hint',
} as const; } as const;
export const DialogHelpModeKeys = {
REDACTION_EDIT: 'redaction_edit',
REDACTION_REMOVE: 'redaction_remove',
SKIPPED_EDIT: 'skipped_edit',
SKIPPED_REMOVE: 'skipped_remove',
RECOMMENDATION_REMOVE: 'recommendation_remove',
HINT_EDIT: 'hint_edit',
HINT_REMOVE: 'hint_remove',
} as const;
export const ALL_HOTKEYS: List = ['Escape', 'F', 'f', 'ArrowUp', 'ArrowDown', 'H', 'h'] as const; export const ALL_HOTKEYS: List = ['Escape', 'F', 'f', 'ArrowUp', 'ArrowDown', 'H', 'h'] as const;
export const HeaderElements = { export const HeaderElements = {

View File

@ -7,6 +7,7 @@ import { removeAnnotationTranslations } from '@translations/remove-annotation-tr
import { removeRedactionTranslations } from '@translations/remove-redaction-translations'; import { removeRedactionTranslations } from '@translations/remove-redaction-translations';
import { resizeRedactionTranslations } from '@translations/resize-redaction-translations'; import { resizeRedactionTranslations } from '@translations/resize-redaction-translations';
import { import {
EditRedactionOption,
ForceAnnotationOption, ForceAnnotationOption,
RedactOrHintOption, RedactOrHintOption,
RedactOrHintOptions, RedactOrHintOptions,
@ -22,36 +23,21 @@ const DOCUMENT_ICON = 'iqser:document';
const FOLDER_ICON = 'red:folder'; const FOLDER_ICON = 'red:folder';
const REMOVE_FROM_DICT_ICON = 'red:remove-from-dict'; const REMOVE_FROM_DICT_ICON = 'red:remove-from-dict';
export const getEditRedactionOptions = ( export const getEditRedactionOptions = (): DetailsRadioOption<EditRedactionOption>[] => {
dossierName: string, return [
applyToAllDossiers: boolean,
dossierDictionaryOnly: boolean,
isModifyDictionary: boolean,
): DetailsRadioOption<RedactOrHintOption>[] => {
const options: DetailsRadioOption<RedactOrHintOption>[] = [
{ {
label: editRedactionTranslations.onlyHere.label, label: editRedactionTranslations.onlyHere.label,
description: editRedactionTranslations.onlyHere.description, description: editRedactionTranslations.onlyHere.description,
icon: PIN_ICON, icon: PIN_ICON,
value: ResizeOptions.ONLY_HERE, value: RedactOrHintOptions.ONLY_HERE,
},
{
label: editRedactionTranslations.inDocument.label,
description: editRedactionTranslations.inDocument.description,
icon: DOCUMENT_ICON,
value: RedactOrHintOptions.IN_DOCUMENT,
}, },
]; ];
if (isModifyDictionary) {
options.push({
label: editRedactionTranslations.inDossier.label,
description: editRedactionTranslations.inDossier.description,
descriptionParams: { dossierName: dossierName },
icon: FOLDER_ICON,
value: ResizeOptions.IN_DOSSIER,
extraOption: {
label: editRedactionTranslations.inDossier.extraOptionLabel,
checked: applyToAllDossiers,
hidden: dossierDictionaryOnly,
disabled: true,
},
});
}
return options;
}; };
export const getRedactOrHintOptions = ( export const getRedactOrHintOptions = (
@ -71,7 +57,7 @@ export const getRedactOrHintOptions = (
label: translations.onlyHere.label, label: translations.onlyHere.label,
description: translations.onlyHere.description, description: translations.onlyHere.description,
icon: PIN_ICON, icon: PIN_ICON,
value: ResizeOptions.ONLY_HERE, value: RedactOrHintOptions.ONLY_HERE,
}); });
} }
@ -84,7 +70,7 @@ export const getRedactOrHintOptions = (
label: redactTextTranslations.inDocument.label, label: redactTextTranslations.inDocument.label,
description: redactTextTranslations.inDocument.description, description: redactTextTranslations.inDocument.description,
icon: DOCUMENT_ICON, icon: DOCUMENT_ICON,
value: ResizeOptions.IN_DOCUMENT, value: RedactOrHintOptions.IN_DOCUMENT,
}); });
} }
@ -93,7 +79,7 @@ export const getRedactOrHintOptions = (
description: translations.inDossier.description, description: translations.inDossier.description,
descriptionParams: { dossierName: dossier.dossierName }, descriptionParams: { dossierName: dossier.dossierName },
icon: FOLDER_ICON, icon: FOLDER_ICON,
value: ResizeOptions.IN_DOSSIER, value: RedactOrHintOptions.IN_DOSSIER,
disabled: isPageExcluded, disabled: isPageExcluded,
extraOption: { extraOption: {
label: translations.inDossier.extraOptionLabel, label: translations.inDossier.extraOptionLabel,
@ -119,7 +105,7 @@ export const getResizeRedactionOptions = (
label: translations.onlyHere.label, label: translations.onlyHere.label,
description: translations.onlyHere.description, description: translations.onlyHere.description,
icon: PIN_ICON, icon: PIN_ICON,
value: RedactOrHintOptions.ONLY_HERE, value: ResizeOptions.ONLY_HERE,
}, },
]; ];
@ -135,7 +121,7 @@ export const getResizeRedactionOptions = (
disabled: !dictBasedType || redaction.hasBeenRecategorized, disabled: !dictBasedType || redaction.hasBeenRecategorized,
tooltip: !dictBasedType ? translations.inDossier.tooltip : null, tooltip: !dictBasedType ? translations.inDossier.tooltip : null,
icon: FOLDER_ICON, icon: FOLDER_ICON,
value: RedactOrHintOptions.IN_DOSSIER, value: ResizeOptions.IN_DOSSIER,
extraOption: { extraOption: {
label: translations.inDossier.extraOptionLabel, label: translations.inDossier.extraOptionLabel,
checked: applyToAllDossiers, checked: applyToAllDossiers,

View File

@ -3,6 +3,13 @@ import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { ManualRedactionEntryWrapper } from '@models/file/manual-redaction-entry.wrapper'; import { ManualRedactionEntryWrapper } from '@models/file/manual-redaction-entry.wrapper';
import { Dictionary, Dossier, File, IAddRedactionRequest, IManualRedactionEntry } from '@red/domain'; import { Dictionary, Dossier, File, IAddRedactionRequest, IManualRedactionEntry } from '@red/domain';
export const EditRedactionOptions = {
ONLY_HERE: 'ONLY_HERE',
IN_DOCUMENT: 'IN_DOCUMENT',
} as const;
export type EditRedactionOption = keyof typeof EditRedactionOptions;
export const RedactOrHintOptions = { export const RedactOrHintOptions = {
ONLY_HERE: 'ONLY_HERE', ONLY_HERE: 'ONLY_HERE',
IN_DOCUMENT: 'IN_DOCUMENT', IN_DOCUMENT: 'IN_DOCUMENT',
@ -45,7 +52,6 @@ export interface RedactTextData {
export interface EditRedactionData { export interface EditRedactionData {
annotations: AnnotationWrapper[]; annotations: AnnotationWrapper[];
dossierId: string; dossierId: string;
applyToAllDossiers: boolean;
isApprover?: boolean; isApprover?: boolean;
} }
@ -58,7 +64,9 @@ export interface RedactTextResult {
bulkLocal?: boolean; bulkLocal?: boolean;
} }
export type RedactRecommendationData = EditRedactionData; export type RedactRecommendationData = EditRedactionData & {
applyToAllDossiers: boolean;
};
export interface RedactRecommendationResult { export interface RedactRecommendationResult {
redaction: IAddRedactionRequest; redaction: IAddRedactionRequest;
@ -72,6 +80,7 @@ export interface EditRedactResult {
comment: string; comment: string;
type: string; type: string;
value: string; value: string;
option: EditRedactionOption;
} }
export type AddHintResult = RedactTextResult; export type AddHintResult = RedactTextResult;

View File

@ -25,20 +25,13 @@ export const redactTextTranslations: Record<'onlyHere' | 'inDocument' | 'inDossi
}, },
} as const; } as const;
export const editRedactionTranslations: Record<'onlyHere' | 'inDossier', DialogOption> = { export const editRedactionTranslations: Record<'onlyHere' | 'inDocument', DialogOption> = {
onlyHere: { onlyHere: {
label: _('edit-redaction.dialog.content.options.only-here.label'), label: _('edit-redaction.dialog.content.options.only-here.label'),
description: _('edit-redaction.dialog.content.options.only-here.description'), description: _('edit-redaction.dialog.content.options.only-here.description'),
}, },
inDossier: { inDocument: {
label: _('edit-redaction.dialog.content.options.in-dossier.label'), label: _('edit-redaction.dialog.content.options.in-document.label'),
description: _('edit-redaction.dialog.content.options.in-dossier.description'), description: _('edit-redaction.dialog.content.options.in-document.description'),
extraOptionLabel: _('edit-redaction.dialog.content.options.in-dossier.extraOptionLabel'),
}, },
} as const; } as const;
export const editRedactionLabelsTranslations = {
redactedText: _('edit-redaction.dialog.content.redacted-text'),
customRectangle: _('edit-redaction.dialog.content.custom-rectangle'),
imported: _('edit-redaction.dialog.content.imported'),
} as const;

View File

@ -27,8 +27,6 @@ export function mainGuard(): AsyncGuard {
const logger = inject(NGXLogger); const logger = inject(NGXLogger);
logger.info('[ROUTES] Main resolver started...'); logger.info('[ROUTES] Main resolver started...');
console.log('main guard');
const router = inject(Router); const router = inject(Router);
inject(FeaturesService).loadConfig(); inject(FeaturesService).loadConfig();
if (inject(IqserPermissionsService).has(Roles.dossiers.read)) { if (inject(IqserPermissionsService).has(Roles.dossiers.read)) {

View File

@ -1284,14 +1284,11 @@
"content": { "content": {
"comment": "Kommentar", "comment": "Kommentar",
"comment-placeholder": "Bemerkungen oder Notizen hinzufügen...", "comment-placeholder": "Bemerkungen oder Notizen hinzufügen...",
"custom-rectangle": "Bereichsschwärzung",
"imported": "Importierte Schwärzung",
"legal-basis": "Rechtsgrundlage", "legal-basis": "Rechtsgrundlage",
"options": { "options": {
"in-dossier": { "in-document": {
"description": "Schwärzung in jedem Dokument in {dossierName} bearbeiten.", "description": "",
"extraOptionLabel": "In alle aktiven und zukünftigen Dossiers übernehmen", "label": ""
"label": "Typ in Dossier ändern"
}, },
"only-here": { "only-here": {
"description": "Bearbeiten Sie die Schwärzung nur an dieser Stelle im Dokument.", "description": "Bearbeiten Sie die Schwärzung nur an dieser Stelle im Dokument.",

View File

@ -1284,18 +1284,15 @@
"content": { "content": {
"comment": "Comment", "comment": "Comment",
"comment-placeholder": "Add remarks or notes...", "comment-placeholder": "Add remarks or notes...",
"custom-rectangle": "Custom Rectangle",
"imported": "Imported Redaction",
"legal-basis": "Legal basis", "legal-basis": "Legal basis",
"options": { "options": {
"in-dossier": { "in-document": {
"description": "Edit redaction in every document in {dossierName}.", "description": "Edit redaction of all linked occurrences of the term in this document.",
"extraOptionLabel": "Apply to all active and future dossiers", "label": "Change in document"
"label": "Change type in dossier"
}, },
"only-here": { "only-here": {
"description": "Edit redaction only at this position in this document.", "description": "Edit redaction only at this position in this document.",
"label": "Change type only here" "label": "Change only here"
} }
}, },
"reason": "Reason", "reason": "Reason",

View File

@ -1284,13 +1284,10 @@
"content": { "content": {
"comment": "Comment", "comment": "Comment",
"comment-placeholder": "Add remarks or mentions...", "comment-placeholder": "Add remarks or mentions...",
"custom-rectangle": "",
"imported": "",
"legal-basis": "", "legal-basis": "",
"options": { "options": {
"in-dossier": { "in-document": {
"description": "", "description": "",
"extraOptionLabel": "",
"label": "" "label": ""
}, },
"only-here": { "only-here": {

View File

@ -1284,13 +1284,10 @@
"content": { "content": {
"comment": "Comment", "comment": "Comment",
"comment-placeholder": "Add remarks or mentions...", "comment-placeholder": "Add remarks or mentions...",
"custom-rectangle": "",
"imported": "",
"legal-basis": "", "legal-basis": "",
"options": { "options": {
"in-dossier": { "in-document": {
"description": "", "description": "",
"extraOptionLabel": "",
"label": "" "label": ""
}, },
"only-here": { "only-here": {

View File

@ -6,3 +6,18 @@ export interface IRecategorizationRequest {
readonly section?: string; readonly section?: string;
readonly value?: string; readonly value?: string;
} }
export interface IBulkRecategorizationRequest {
readonly value: string;
readonly type: string;
readonly legalBasis: string;
readonly section: string;
readonly originTypes: string[];
readonly originLegalBases: string[];
readonly rectangle: boolean;
readonly position?: {
readonly rectangle: number[];
readonly pageNumber: number;
};
readonly pageNumbers?: number[];
}