DM-413: enabled bulk edit only for skipped and annotations.

This commit is contained in:
Nicoleta Panaghiu 2023-09-06 17:29:11 +03:00
parent 8b5558b743
commit 841cf2e50c
7 changed files with 65 additions and 22 deletions

View File

@ -29,6 +29,7 @@ export class AnnotationPermissions {
canResizeAnnotation = true;
canRecategorizeAnnotation = true;
canForceHint = true;
canEditAnnotations = true;
static forUser(
isApprover: boolean,
@ -58,6 +59,7 @@ export class AnnotationPermissions {
permissions.canChangeLegalBasis = canChangeLegalBasis(annotation, canAddRedaction);
permissions.canRecategorizeAnnotation = canRecategorizeAnnotation(annotation, canAddRedaction);
permissions.canResizeAnnotation = canResizeAnnotation(annotation, canAddRedaction);
permissions.canEditAnnotations = annotation.isSkipped || annotation.isRedacted;
summedPermissions._merge(permissions);
}
@ -77,6 +79,7 @@ export class AnnotationPermissions {
result.canRemoveOnlyHere = permissions.reduce((acc, next) => acc && next.canRemoveOnlyHere, true);
result.canRemoveRedaction = permissions.reduce((acc, next) => acc && next.canRemoveRedaction, true);
result.canUndo = permissions.reduce((acc, next) => acc && next.canUndo, true);
result.canEditAnnotations = permissions.reduce((acc, next) => acc && next.canEditAnnotations, true);
return result;
}

View File

@ -3,16 +3,26 @@
<div [translate]="'edit-redaction.dialog.title'" class="dialog-header heading-l"></div>
<div class="dialog-content redaction">
<div *ngIf="redactedText" class="iqser-input-group w-450">
<label [translate]="'edit-redaction.dialog.content.redacted-text'" class="selected-text"></label>
{{ redactedText }}
<div *ngIf="showList">
<label
[translate]="'edit-redaction.dialog.content.redacted-text'"
[translateParams]="{ length: redactedTexts.length }"
class="selected-text"
></label>
<cdk-virtual-scroll-viewport
[itemSize]="16"
[ngStyle]="{ height: redactedTexts.length <= 5 ? 16 * redactedTexts.length + 'px' : 80 + 'px' }"
>
<ul *cdkVirtualFor="let text of redactedTexts">
<li>{{ text }}</li>
</ul>
</cdk-virtual-scroll-viewport>
</div>
<div class="iqser-input-group required w-450">
<label [translate]="'edit-redaction.dialog.content.type'"></label>
<mat-form-field>
<mat-select formControlName="type">
<mat-select formControlName="type" [placeholder]="'edit-redaction.dialog.content.unchanged' | translate">
<mat-select-trigger>{{ displayedDictionaryLabel }}</mat-select-trigger>
<mat-option
*ngFor="let dictionary of dictionaries"
@ -29,7 +39,11 @@
<div class="iqser-input-group w-450">
<label [translate]="'edit-redaction.dialog.content.comment'"></label>
<textarea
[placeholder]="'edit-redaction.dialog.content.comment-placeholder' | translate"
[placeholder]="
redactedTexts.length === 1
? ('edit-redaction.dialog.content.comment-placeholder' | translate)
: ('edit-redaction.dialog.content.unchanged' | translate)
"
formControlName="comment"
iqserHasScrollbar
name="comment"
@ -40,7 +54,12 @@
</div>
<div class="dialog-actions">
<iqser-icon-button [label]="'edit-redaction.dialog.actions.save' | translate" [submit]="true" [type]="iconButtonTypes.primary">
<iqser-icon-button
[label]="'edit-redaction.dialog.actions.save' | translate"
[submit]="true"
[type]="iconButtonTypes.primary"
[disabled]="!changed"
>
</iqser-icon-button>
<div [translate]="'edit-redaction.dialog.actions.cancel'" class="all-caps-label cancel" mat-dialog-close></div>

View File

@ -0,0 +1,14 @@
cdk-virtual-scroll-viewport {
margin-top: 8px;
}
:host ::ng-deep .cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper {
max-width: 100% !important;
}
li {
white-space: nowrap;
text-overflow: ellipsis;
list-style-position: inside;
overflow: hidden;
}

View File

@ -10,6 +10,7 @@ import { EditRedactionData, EditRedactResult } from '../../../utils/dialog-types
@Component({
templateUrl: 'edit-annotation-dialog.component.html',
styleUrls: ['edit-annotation-dialog.component.scss'],
})
export class EditAnnotationDialogComponent
extends IqserDialogComponent<EditAnnotationDialogComponent, EditRedactionData, EditRedactResult>
@ -17,7 +18,7 @@ export class EditAnnotationDialogComponent
{
readonly roles = Roles;
readonly iconButtonTypes = IconButtonTypes;
readonly redactedText: string;
readonly redactedTexts: string[];
dictionaries: Dictionary[] = [];
form: UntypedFormGroup;
readonly #dossier: Dossier;
@ -32,9 +33,9 @@ export class EditAnnotationDialogComponent
super();
this.#dossier = _activeDossiersService.find(this.data.dossierId);
const annotations = this.data.annotations;
const firstEntry = annotations[0];
this.redactedText = annotations.length === 1 ? firstEntry.value : null;
this.redactedTexts = annotations.map(annotation => annotation.value);
this.form = this.#getForm();
this.initialFormValue = JSON.parse(JSON.stringify(this.form.getRawValue()));
}
get displayedDictionaryLabel() {
@ -45,6 +46,10 @@ export class EditAnnotationDialogComponent
return null;
}
get showList() {
return this.data.annotations.every(annotation => annotation.isSkipped || annotation.isRedacted);
}
async ngOnInit(): Promise<void> {
this.#setTypes();
}
@ -66,9 +71,10 @@ export class EditAnnotationDialogComponent
}
#getForm(): UntypedFormGroup {
const sameType = new Set(this.data.annotations.map(annotation => annotation.type)).size === 1;
return this._formBuilder.group({
comment: [null],
type: [this.data.annotations[0].type],
type: [sameType ? this.data.annotations[0].type : null],
});
}

View File

@ -114,9 +114,9 @@ export class AnnotationActionsService {
requests.push(this._manualRedactionService.changeLegalBasis(changeLegalBasisBody, dossierId, fileId));
}
if (result.type !== annotations[0].type || this.#isDocumine) {
const recategorizeBody: List<IRecategorizationRequest> = annotations.map(({ id }) => ({
annotationId: id,
type: result.type,
const recategorizeBody: List<IRecategorizationRequest> = annotations.map(annotation => ({
annotationId: annotation.id,
type: result.type ?? annotation.type,
}));
requests.push(this._manualRedactionService.recategorizeRedactions(recategorizeBody, dossierId, fileId));
}

View File

@ -1,6 +1,6 @@
import { inject, Injectable, NgZone } from '@angular/core';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { IqserPermissionsService } from '@iqser/common-ui';
import { getConfig, IqserPermissionsService } from '@iqser/common-ui';
import { BASE_HREF_FN } from '@iqser/common-ui/lib/utils';
import { AnnotationPermissions } from '@models/file/annotation.permissions';
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
@ -21,7 +21,7 @@ export class PdfAnnotationActionsService {
readonly #annotationActionsService = inject(AnnotationActionsService);
readonly #iqserPermissionsService = inject(IqserPermissionsService);
readonly #annotationManager = inject(REDAnnotationManager);
readonly #isDocumine = getConfig().IS_DOCUMINE;
get(annotations: AnnotationWrapper[]): IHeaderElement[] {
const availableActions: IHeaderElement[] = [];
const permissions = this.#getAnnotationsPermissions(annotations);
@ -47,13 +47,13 @@ export class PdfAnnotationActionsService {
availableActions.push(resizeButton);
}
if (
const canEditRedactions =
permissions.canChangeLegalBasis ||
permissions.canRecategorizeAnnotation ||
permissions.canForceHint ||
permissions.canForceRedaction
) {
permissions.canForceRedaction;
const canEdit = this.#isDocumine && annotations.length > 1 ? permissions.canEditAnnotations : canEditRedactions;
if (canEdit) {
const editButton = this.#getButton('edit', _('annotation-actions.edit-redaction.label'), () =>
this.#annotationActionsService.editRedaction(annotations),
);

View File

@ -1235,9 +1235,10 @@
}
},
"reason": "",
"redacted-text": "Annotated text",
"redacted-text": "Selected {length, plural, one{annotation} other {annotations}}",
"section": "",
"type": "Type"
"type": "Type",
"unchanged": "Unchanged"
},
"title": "Edit annotation"
}