Merge branch 'RED-8137' into 'master'

RED-8137: enabled actions on unprocessed annotations.

See merge request redactmanager/red-ui!245
This commit is contained in:
Dan Percic 2024-01-09 12:42:46 +01:00
commit f8a78c8238
6 changed files with 97 additions and 40 deletions

View File

@ -15,29 +15,36 @@ export const canAcceptRecommendation = (annotation: AnnotationWrapper) => annota
export const canMarkAsFalsePositive = (annotation: AnnotationWrapper, annotationEntity: Dictionary) =>
annotation.canBeMarkedAsFalsePositive && annotationEntity?.hasDictionary;
export const canRemoveOnlyHere = (annotation: AnnotationWrapper, canAddRedaction: boolean) =>
canAddRedaction && !annotation.pending && (annotation.isRedacted || (annotation.isHint && !annotation.isImage));
export const canRemoveOnlyHere = (annotation: AnnotationWrapper, canAddRedaction: boolean, autoAnalysisDisabled: boolean) =>
canAddRedaction &&
(autoAnalysisDisabled || !annotation.pending) &&
(annotation.isRedacted || (annotation.isHint && !annotation.isImage));
export const canRemoveFromDictionary = (annotation: AnnotationWrapper) =>
export const canRemoveFromDictionary = (annotation: AnnotationWrapper, autoAnalysisDisabled: boolean) =>
annotation.isModifyDictionary &&
(annotation.isRedacted || annotation.isSkipped || annotation.isHint) &&
!annotation.pending &&
(autoAnalysisDisabled || !annotation.pending) &&
!annotation.hasBeenResized;
export const canRemoveRedaction = (annotation: AnnotationWrapper, permissions: AnnotationPermissions) =>
!annotation.isIgnoredHint &&
(permissions.canRemoveOnlyHere || permissions.canRemoveFromDictionary || permissions.canMarkAsFalsePositive);
export const canChangeLegalBasis = (annotation: AnnotationWrapper, canAddRedaction: boolean) =>
canAddRedaction && annotation.isRedacted && !annotation.pending;
export const canChangeLegalBasis = (annotation: AnnotationWrapper, canAddRedaction: boolean, autoAnalysisDisabled: boolean) =>
canAddRedaction && annotation.isRedacted && (autoAnalysisDisabled || !annotation.pending);
export const canRecategorizeAnnotation = (annotation: AnnotationWrapper, canRecategorize: boolean) =>
canRecategorize && (annotation.isImage || annotation.isDictBasedHint) && !annotation.pending;
export const canRecategorizeAnnotation = (annotation: AnnotationWrapper, canRecategorize: boolean, autoAnalysisDisabled: boolean) =>
canRecategorize && (annotation.isImage || annotation.isDictBasedHint) && (autoAnalysisDisabled || !annotation.pending);
export const canResizeAnnotation = (annotation: AnnotationWrapper, canAddRedaction: boolean, hasDictionary = false) =>
export const canResizeAnnotation = (
annotation: AnnotationWrapper,
canAddRedaction: boolean,
autoAnalysisDisabled: boolean,
hasDictionary = false,
) =>
canAddRedaction &&
!annotation.isSkipped &&
!annotation.pending &&
(autoAnalysisDisabled || !annotation.pending) &&
(annotation.isRedacted ||
annotation.isImage ||
annotation.isDictBasedHint ||

View File

@ -41,6 +41,7 @@ export class AnnotationPermissions {
annotations: AnnotationWrapper | AnnotationWrapper[],
entities: Dictionary[],
permissionsService: IqserPermissionsService,
autoAnalysisDisabled: boolean,
) {
if (!isArray(annotations)) {
annotations = [annotations];
@ -57,12 +58,17 @@ export class AnnotationPermissions {
permissions.canForceRedaction = canForceRedaction(annotation, canAddRedaction);
permissions.canAcceptRecommendation = canAcceptRecommendation(annotation);
permissions.canMarkAsFalsePositive = canMarkAsFalsePositive(annotation, annotationEntity);
permissions.canRemoveOnlyHere = canRemoveOnlyHere(annotation, canAddRedaction);
permissions.canRemoveFromDictionary = canRemoveFromDictionary(annotation);
permissions.canRemoveOnlyHere = canRemoveOnlyHere(annotation, canAddRedaction, autoAnalysisDisabled);
permissions.canRemoveFromDictionary = canRemoveFromDictionary(annotation, autoAnalysisDisabled);
permissions.canRemoveRedaction = canRemoveRedaction(annotation, permissions);
permissions.canChangeLegalBasis = canChangeLegalBasis(annotation, canAddRedaction);
permissions.canRecategorizeAnnotation = canRecategorizeAnnotation(annotation, canAddRedaction);
permissions.canResizeAnnotation = canResizeAnnotation(annotation, canAddRedaction, annotationEntity?.hasDictionary);
permissions.canChangeLegalBasis = canChangeLegalBasis(annotation, canAddRedaction, autoAnalysisDisabled);
permissions.canRecategorizeAnnotation = canRecategorizeAnnotation(annotation, canAddRedaction, autoAnalysisDisabled);
permissions.canResizeAnnotation = canResizeAnnotation(
annotation,
canAddRedaction,
autoAnalysisDisabled,
annotationEntity?.hasDictionary,
);
permissions.canEditAnnotations = canEditAnnotation(annotation);
permissions.canEditHints = canEditHint(annotation);
permissions.canEditImages = canEditImage(annotation);

View File

@ -165,6 +165,7 @@ export class AnnotationActionsComponent implements OnChanges {
this.#annotations,
this._state.dictionaries,
this._iqserPermissionsService,
this._state.file().excludedFromAutomaticAnalysis,
);
}

View File

@ -91,7 +91,8 @@ export class AnnotationActionsService {
}
async editRedaction(annotations: AnnotationWrapper[]) {
const { dossierId, dossierTemplateId, fileId } = this._state;
const { dossierId, dossierTemplateId, fileId, file } = this._state;
const isUnprocessed = annotations.every(annotation => annotation.pending);
const dossierTemplate = this._dossierTemplatesService.find(dossierTemplateId);
const data = {
annotations,
@ -118,14 +119,28 @@ export class AnnotationActionsService {
section: result.section ?? annotation.section,
value: result.value ?? annotation.value,
}));
requests.push(this._manualRedactionService.changeLegalBasis(changeLegalBasisBody, dossierId, fileId));
requests.push(
this._manualRedactionService.changeLegalBasis(
changeLegalBasisBody,
dossierId,
fileId,
file().excludedFromAutomaticAnalysis && isUnprocessed,
),
);
}
if (result.type && !annotations.every(annotation => annotation.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));
requests.push(
this._manualRedactionService.recategorizeRedactions(
recategorizeBody,
dossierId,
fileId,
file().excludedFromAutomaticAnalysis && isUnprocessed,
),
);
}
if (result.comment) {
@ -152,6 +167,7 @@ export class AnnotationActionsService {
};
const dossierTemplate = this._dossierTemplatesService.find(this._state.dossierTemplateId);
const isApprover = this._permissionsService.isApprover(this._state.dossier());
const isUnprocessed = redactions.every(annotation => annotation.pending);
const data = {
redactions,
@ -174,7 +190,7 @@ export class AnnotationActionsService {
) {
this.#setAsFalsePositive(redactions, result);
} else {
this.#removeRedaction(redactions, result);
this.#removeRedaction(redactions, result, this._state.file().excludedFromAutomaticAnalysis && isUnprocessed);
}
}
@ -241,6 +257,7 @@ export class AnnotationActionsService {
const text = annotation.AREA ? annotation.value : isImageText;
const isApprover = this._permissionsService.isApprover(dossier);
const dossierTemplate = this._dossierTemplatesService.find(this._state.dossierTemplateId);
const isUnprocessed = annotation.pending;
const data = {
redaction: annotation,
@ -267,8 +284,13 @@ export class AnnotationActionsService {
await this.cancelResize(annotation);
const { fileId, dossierId } = this._state;
const request = this._manualRedactionService.resize([resizeRequest], dossierId, fileId);
const { fileId, dossierId, file } = this._state;
const request = this._manualRedactionService.resize(
[resizeRequest],
dossierId,
fileId,
isUnprocessed && file().excludedFromAutomaticAnalysis,
);
return this.#processObsAndEmit(request);
}
@ -423,7 +445,7 @@ export class AnnotationActionsService {
this.#processObsAndEmit(this._manualRedactionService.addAnnotation(requests, dossierId, fileId)).then();
}
#removeRedaction(redactions: AnnotationWrapper[], dialogResult: RemoveRedactionResult) {
#removeRedaction(redactions: AnnotationWrapper[], dialogResult: RemoveRedactionResult, includeUnprocessed = false) {
const removeFromDictionary = dialogResult.option.value === RemoveRedactionOptions.IN_DOSSIER;
const body = redactions.map(redaction => ({
annotationId: redaction.id,
@ -434,7 +456,9 @@ export class AnnotationActionsService {
// 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)).then();
this.#processObsAndEmit(
this._manualRedactionService.removeRedaction(body, dossierId, fileId, removeFromDictionary, isHint, includeUnprocessed),
).then();
}
#getRemoveRedactionDialog(data: RemoveRedactionData) {

View File

@ -62,12 +62,12 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
return this.addAnnotation(recommendations, dossierId, fileId);
}
changeLegalBasis(body: List<ILegalBasisChangeRequest>, dossierId: string, fileId: string) {
return this.legalBasisChange(body, dossierId, fileId).pipe(this.#showToast('change-legal-basis'));
changeLegalBasis(body: List<ILegalBasisChangeRequest>, dossierId: string, fileId: string, includeUnprocessed = false) {
return this.legalBasisChange(body, dossierId, fileId, includeUnprocessed).pipe(this.#showToast('change-legal-basis'));
}
recategorizeRedactions(body: List<IRecategorizationRequest>, dossierId: string, fileId: string) {
return this.recategorize(body, dossierId, fileId).pipe(this.#showToast('change-type'));
recategorizeRedactions(body: List<IRecategorizationRequest>, dossierId: string, fileId: string, includeUnprocessed = false) {
return this.recategorize(body, dossierId, fileId, includeUnprocessed).pipe(this.#showToast('change-type'));
}
addAnnotation(
@ -95,8 +95,17 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
return this.undo(annotationIds, dossierId, fileId).pipe(this.#showToast('undo', modifyDictionary));
}
removeRedaction(body: List<IRemoveRedactionRequest>, dossierId: string, fileId: string, removeFromDictionary = false, isHint = false) {
return this.remove(body, dossierId, fileId).pipe(this.#showToast(!isHint ? 'remove' : 'remove-hint', removeFromDictionary));
removeRedaction(
body: List<IRemoveRedactionRequest>,
dossierId: string,
fileId: string,
removeFromDictionary = false,
isHint = false,
includeUnprocessed = false,
) {
return this.remove(body, dossierId, fileId, includeUnprocessed).pipe(
this.#showToast(!isHint ? 'remove' : 'remove-hint', removeFromDictionary),
);
}
getTitle(type: ManualRedactionEntryType) {
@ -116,14 +125,17 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
return this._post(body, `${this.#bulkRedaction}/add/${dossierId}/${fileId}`).pipe(this.#log('Add', body));
}
recategorize(body: List<IRecategorizationRequest>, dossierId: string, fileId: string) {
return this._post(body, `${this.#bulkRedaction}/recategorize/${dossierId}/${fileId}`).pipe(this.#log('Recategorize', 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),
);
}
legalBasisChange(body: List<ILegalBasisChangeRequest>, dossierId: string, fileId: string) {
return this._post(body, `${this.#bulkRedaction}/legalBasisChange/${dossierId}/${fileId}`).pipe(
this.#log('Legal basis change', body),
);
legalBasisChange(body: List<ILegalBasisChangeRequest>, dossierId: string, fileId: string, includeUnprocessed = false) {
return this._post(
body,
`${this.#bulkRedaction}/legalBasisChange/${dossierId}/${fileId}?includeUnprocessed=${includeUnprocessed}`,
).pipe(this.#log('Legal basis change', body));
}
undo(annotationIds: List, dossierId: string, fileId: string) {
@ -131,16 +143,20 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
return super.delete(annotationIds, url).pipe(this.#log('Undo', annotationIds));
}
remove(body: List<IRemoveRedactionRequest>, dossierId: string, fileId: string) {
return this._post(body, `${this.#bulkRedaction}/remove/${dossierId}/${fileId}`).pipe(this.#log('Remove', body));
remove(body: List<IRemoveRedactionRequest>, dossierId: string, fileId: string, includeUnprocessed = false) {
return this._post(body, `${this.#bulkRedaction}/remove/${dossierId}/${fileId}?includeUnprocessed=${includeUnprocessed}`).pipe(
this.#log('Remove', body),
);
}
forceRedaction(body: List<ILegalBasisChangeRequest>, dossierId: string, fileId: string) {
return this._post(body, `${this.#bulkRedaction}/force/${dossierId}/${fileId}`).pipe(this.#log('Force redaction', body));
}
resize(body: List<IResizeRequest>, dossierId: string, fileId: string) {
return this._post(body, `${this.#bulkRedaction}/resize/${dossierId}/${fileId}`).pipe(this.#log('Resize', body));
resize(body: List<IResizeRequest>, dossierId: string, fileId: string, includeUnprocessed = false) {
return this._post(body, `${this.#bulkRedaction}/resize/${dossierId}/${fileId}?includeUnprocessed=${includeUnprocessed}`).pipe(
this.#log('Resize', body),
);
}
#log(action: string, body: unknown) {

View File

@ -133,7 +133,10 @@ export class PdfAnnotationActionsService {
const dossier = this.#state.dossier();
const isApprover = this.#permissionsService.isApprover(dossier);
const dictionaries = this.#state.dictionaries;
const permissions = annotations.map(a => AnnotationPermissions.forUser(isApprover, a, dictionaries, this.#iqserPermissionsService));
const autoAnalysisDisabled = this.#state.file().excludedFromAutomaticAnalysis;
const permissions = annotations.map(a =>
AnnotationPermissions.forUser(isApprover, a, dictionaries, this.#iqserPermissionsService, autoAnalysisDisabled),
);
return AnnotationPermissions.reduce(permissions);
}
}