manual redaction flow changes
This commit is contained in:
parent
55c8706a9d
commit
b128588778
@ -8,12 +8,18 @@
|
||||
</div>
|
||||
{{ manualRedactionEntryWrapper.manualRedactionEntry.value }}
|
||||
|
||||
<div
|
||||
class="red-input-group"
|
||||
[class.hidden]="manualRedactionEntryWrapper.type === 'DICTIONARY'"
|
||||
>
|
||||
<div class="red-input-group" *ngIf="!isDictionaryRequest">
|
||||
<label translate="manual-redaction.dialog.content.reason"></label>
|
||||
<input formControlName="reason" name="reason" type="text" rows="2" />
|
||||
<mat-select formControlName="reason" class="full-width">
|
||||
<mat-option *ngFor="let option of legalOptions" [value]="option.legalBasis">
|
||||
{{ option.label }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</div>
|
||||
|
||||
<div class="red-input-group" *ngIf="!isDictionaryRequest">
|
||||
<label translate="manual-redaction.dialog.content.legalBasis"></label>
|
||||
<input type="text" [value]="redactionForm.get('reason').value" disabled />
|
||||
</div>
|
||||
|
||||
<div class="red-input-group">
|
||||
@ -21,32 +27,18 @@
|
||||
<textarea formControlName="comment" name="comment" type="text" rows="4"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="red-input-group">
|
||||
<div class="red-input-group" *ngIf="isDictionaryRequest">
|
||||
<label translate="manual-redaction.dialog.content.dictionary"></label>
|
||||
<mat-select formControlName="dictionary" *ngIf="!isDictionaryRequest">
|
||||
<mat-option
|
||||
*ngFor="let dictionary of redactionDictionaries"
|
||||
[value]="dictionary.type"
|
||||
>
|
||||
{{ dictionary.label }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
|
||||
<mat-select formControlName="dictionary" *ngIf="isDictionaryRequest">
|
||||
<mat-select formControlName="dictionary">
|
||||
<mat-optgroup [label]="'group.redactions' | translate">
|
||||
<mat-option
|
||||
*ngFor="let dictionary of redactionDictionaries"
|
||||
[value]="dictionary.type"
|
||||
>
|
||||
<mat-option *ngFor="let dictionary of redactionDictionaries" [value]="dictionary.type">
|
||||
{{ dictionary.label }}
|
||||
</mat-option>
|
||||
</mat-optgroup>
|
||||
|
||||
<mat-optgroup [label]="'group.hints' | translate">
|
||||
<mat-option
|
||||
*ngFor="let dictionary of hintDictionaries"
|
||||
[value]="dictionary.type"
|
||||
>
|
||||
<mat-option *ngFor="let dictionary of hintDictionaries" [value]="dictionary.type">
|
||||
{{ dictionary.label }}
|
||||
</mat-option>
|
||||
</mat-optgroup>
|
||||
@ -55,13 +47,7 @@
|
||||
</div>
|
||||
|
||||
<div class="dialog-actions">
|
||||
<button
|
||||
color="primary"
|
||||
mat-flat-button
|
||||
[disabled]="!redactionForm.valid"
|
||||
translate="manual-redaction.dialog.actions.save"
|
||||
type="submit"
|
||||
></button>
|
||||
<button color="primary" mat-flat-button [disabled]="!redactionForm.valid" translate="manual-redaction.dialog.actions.save" type="submit"></button>
|
||||
</div>
|
||||
</form>
|
||||
<button (click)="dialogRef.close()" class="dialog-close" mat-icon-button>
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
@ -11,6 +11,39 @@ import { ManualAnnotationService } from '../../screens/file/service/manual-annot
|
||||
import { ManualAnnotationResponse } from '../../screens/file/model/manual-annotation-response';
|
||||
import { PermissionsService } from '../../common/service/permissions.service';
|
||||
|
||||
const LEGAL_OPTIONS = [
|
||||
{
|
||||
label: 'the method of manufacture',
|
||||
legalBasis: 'Reg (EC) No 1107/2009 Art. 63 (2a)'
|
||||
},
|
||||
{
|
||||
label:
|
||||
'the specification of impurity of the active substance except for the impurities that are considered to be toxicologically, ecotoxicologically or environmentally relevant',
|
||||
legalBasis: 'Reg (EC) No 1107/2009 Art. 63 (2b)'
|
||||
},
|
||||
{
|
||||
label: 'results of production batches of the active substance including impurities',
|
||||
legalBasis: 'Reg (EC) No 1107/2009 Art. 63 (2c)'
|
||||
},
|
||||
{
|
||||
label:
|
||||
'methods of analysis for impurities in the active substance as manufactured except for methods for impurities that are considered to be toxicologically, ecotoxicologically or environmentally relevant',
|
||||
legalBasis: 'Reg (EC) No 1107/2009 Art. 63 (2d)'
|
||||
},
|
||||
{
|
||||
label: 'links between a producer or importer and the applicant or the authorisation holder',
|
||||
legalBasis: 'Reg (EC) No 1107/2009 Art. 63 (2e)'
|
||||
},
|
||||
{
|
||||
label: 'information on the complete composition of a plant protection product',
|
||||
legalBasis: 'Reg (EC) No 1107/2009 Art. 63 (2f)'
|
||||
},
|
||||
{
|
||||
label: 'names and addresses of persons involved in testing on vertebrate animals',
|
||||
legalBasis: 'Reg (EC) No 1107/2009 Art. 63 (2g)'
|
||||
}
|
||||
];
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-manual-annotation-dialog',
|
||||
templateUrl: './manual-annotation-dialog.component.html',
|
||||
@ -24,6 +57,8 @@ export class ManualAnnotationDialogComponent implements OnInit {
|
||||
redactionDictionaries: TypeValue[] = [];
|
||||
hintDictionaries: TypeValue[] = [];
|
||||
|
||||
legalOptions = LEGAL_OPTIONS;
|
||||
|
||||
constructor(
|
||||
private readonly _appStateService: AppStateService,
|
||||
private readonly _userService: UserService,
|
||||
@ -38,13 +73,12 @@ export class ManualAnnotationDialogComponent implements OnInit {
|
||||
|
||||
async ngOnInit() {
|
||||
this.isDocumentAdmin = this._permissionsService.isManagerAndOwner();
|
||||
const commentField = this.isDocumentAdmin ? [null] : [null, Validators.required];
|
||||
|
||||
this.isDictionaryRequest = this.manualRedactionEntryWrapper.type === 'DICTIONARY';
|
||||
this.redactionForm = this._formBuilder.group({
|
||||
reason: this.isDictionaryRequest ? null : [null, Validators.required],
|
||||
dictionary: [null, Validators.required],
|
||||
comment: commentField
|
||||
reason: this.isDictionaryRequest ? [null] : [null, Validators.required],
|
||||
dictionary: this.isDictionaryRequest ? [null] : ['manual', Validators.required],
|
||||
comment: this.isDocumentAdmin ? [null] : [null, Validators.required]
|
||||
});
|
||||
|
||||
for (const key of Object.keys(this._appStateService.dictionaryData)) {
|
||||
@ -78,8 +112,8 @@ export class ManualAnnotationDialogComponent implements OnInit {
|
||||
|
||||
private _enhanceManualRedaction(addRedactionRequest: AddRedactionRequest) {
|
||||
addRedactionRequest.type = this.redactionForm.get('dictionary').value;
|
||||
addRedactionRequest.addToDictionary = this.manualRedactionEntryWrapper.type === 'DICTIONARY';
|
||||
addRedactionRequest.reason = this.redactionForm.get('reason').value;
|
||||
addRedactionRequest.addToDictionary = this.isDictionaryRequest;
|
||||
// todo fix this in backend
|
||||
if (!addRedactionRequest.reason) {
|
||||
addRedactionRequest.reason = '-';
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
<div [class.visible]="menuOpen" *ngIf="canPerformAnnotationActions" class="annotation-actions">
|
||||
<!-- Only owner can accept or reject suggestions-->
|
||||
<ng-container *ngIf="permissionsService.isManagerAndOwner()">
|
||||
<button (click)="acceptSuggestion($event, annotation, annotation.modifyDictionary)" *ngIf="annotation.isSuggestion" mat-icon-button>
|
||||
<ng-container *ngIf="permissionsService.isManagerAndOwner() && annotation.isSuggestion">
|
||||
<button (click)="acceptSuggestion($event, annotation, annotation.modifyDictionary)" mat-icon-button>
|
||||
<mat-icon svgIcon="red:check-alt"></mat-icon>
|
||||
</button>
|
||||
<button (click)="rejectSuggestion($event, annotation)" *ngIf="annotation.isSuggestion && !canUndoAnnotation()" mat-icon-button>
|
||||
<button (click)="rejectSuggestion($event, annotation)" *ngIf="!canUndoAnnotation()" mat-icon-button>
|
||||
<mat-icon svgIcon="red:close"></mat-icon>
|
||||
</button>
|
||||
</ng-container>
|
||||
@ -17,29 +17,24 @@
|
||||
<!-- Everyone can suggest to remove annotations, manager will remove directly while user will make a suggestion-->
|
||||
|
||||
<!-- For Suggesting Removal, in case of hints, the user can suggest removal from dictionary -->
|
||||
<button (click)="suggestRemoveAnnotation($event, annotation, true)" *ngIf="annotation.superType === 'hint' && !canUndoAnnotation()" mat-icon-button>
|
||||
<mat-icon svgIcon="red:trash"></mat-icon>
|
||||
</button>
|
||||
<ng-container *ngIf="!annotation.isSuggestion">
|
||||
<button (click)="suggestRemoveAnnotation($event, annotation, true)" *ngIf="showSimpleSuggestRemove()" mat-icon-button>
|
||||
<mat-icon svgIcon="red:close"></mat-icon>
|
||||
</button>
|
||||
|
||||
<!-- For Suggesting Removal, in case of redactions, the user can suggest only-here or everywhere-->
|
||||
<button
|
||||
(click)="openMenu($event)"
|
||||
*ngIf="annotation.superType === 'redaction' && !canUndoAnnotation()"
|
||||
[class.active]="menuOpen"
|
||||
[matMenuTriggerFor]="menu"
|
||||
class="confirm"
|
||||
mat-icon-button
|
||||
>
|
||||
<mat-icon svgIcon="red:trash"></mat-icon>
|
||||
</button>
|
||||
<mat-menu #menu="matMenu" (closed)="onMenuClosed()" xPosition="before">
|
||||
<div (click)="suggestRemoveAnnotation($event, annotation, true)" mat-menu-item>
|
||||
<redaction-annotation-icon [type]="'rhombus'" [label]="'S'" [color]="dictionaryColor"></redaction-annotation-icon>
|
||||
<div [translate]="'file-preview.tabs.annotations.remove-annotation.remove-from-dict'"></div>
|
||||
</div>
|
||||
<div (click)="suggestRemoveAnnotation($event, annotation, false)" mat-menu-item>
|
||||
<redaction-annotation-icon [type]="'rhombus'" [label]="'S'" [color]="suggestionColor"></redaction-annotation-icon>
|
||||
<div translate="file-preview.tabs.annotations.remove-annotation.only-here"></div>
|
||||
</div>
|
||||
</mat-menu>
|
||||
<!-- For Suggesting Removal, in case of redactions, the user can suggest only-here or everywhere-->
|
||||
<button (click)="openMenu($event)" *ngIf="showMenuSuggestRemove()" [class.active]="menuOpen" [matMenuTriggerFor]="menu" class="confirm" mat-icon-button>
|
||||
<mat-icon svgIcon="red:close"></mat-icon>
|
||||
</button>
|
||||
<mat-menu #menu="matMenu" (closed)="onMenuClosed()" xPosition="before">
|
||||
<div (click)="suggestRemoveAnnotation($event, annotation, true)" mat-menu-item>
|
||||
<redaction-annotation-icon [type]="'rhombus'" [label]="'S'" [color]="dictionaryColor"></redaction-annotation-icon>
|
||||
<div [translate]="'file-preview.tabs.annotations.remove-annotation.remove-from-dict'"></div>
|
||||
</div>
|
||||
<div (click)="suggestRemoveAnnotation($event, annotation, false)" mat-menu-item>
|
||||
<redaction-annotation-icon [type]="'rhombus'" [label]="'S'" [color]="suggestionColor"></redaction-annotation-icon>
|
||||
<div translate="file-preview.tabs.annotations.remove-annotation.only-here"></div>
|
||||
</div>
|
||||
</mat-menu>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
@ -74,13 +74,6 @@ export class AnnotationActionsComponent implements OnInit {
|
||||
this.menuOpen = false;
|
||||
}
|
||||
|
||||
canUndoAnnotation() {
|
||||
const isSuggestionOfCurrentUser = this.annotation.isSuggestion && this.annotation.userId === this.permissionsService.currentUserId;
|
||||
const isManualAnnotationOfCurrentUser =
|
||||
this.annotation.manual && this.annotation.userId === this.permissionsService.currentUserId && this.permissionsService.isManagerAndOwner();
|
||||
return isSuggestionOfCurrentUser || isManualAnnotationOfCurrentUser;
|
||||
}
|
||||
|
||||
get suggestionColor() {
|
||||
return this.appStateService.getDictionaryColor('suggestion');
|
||||
}
|
||||
@ -88,4 +81,31 @@ export class AnnotationActionsComponent implements OnInit {
|
||||
get dictionaryColor() {
|
||||
return this.appStateService.getDictionaryColor('suggestion-dictionary');
|
||||
}
|
||||
|
||||
showSimpleSuggestRemove() {
|
||||
return this._canRemove() && !this._showComplexMenu();
|
||||
}
|
||||
|
||||
showMenuSuggestRemove() {
|
||||
return this._canRemove() && this._showComplexMenu();
|
||||
}
|
||||
|
||||
private _showComplexMenu() {
|
||||
// we can show the complex dialog only for redactions that are not manual, but this is already checked via canUndo
|
||||
return this.annotation.superType === 'redaction' && this.annotation.dictionary !== 'manual';
|
||||
}
|
||||
|
||||
canUndoAnnotation() {
|
||||
// suggestions of current user can be undone
|
||||
const isSuggestionOfCurrentUser = this.annotation.isSuggestion && this.annotation.userId === this.permissionsService.currentUserId;
|
||||
// or any performed manual actions and you are the manager, provided that it is not a suggestion
|
||||
const isActionOfManger = this.permissionsService.isManagerAndOwner() && this.annotation.userId === this.permissionsService.currentUserId;
|
||||
return isSuggestionOfCurrentUser || isActionOfManger;
|
||||
}
|
||||
|
||||
private _canRemove() {
|
||||
const canUndo = this.canUndoAnnotation();
|
||||
// you can do a simple remove for anything you cannot undo, that is not ignored
|
||||
return !canUndo && !this.annotation.isIgnored;
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,16 +56,6 @@ export class AnnotationWrapper {
|
||||
annotationWrapper.userId = manualRedactionEntry?.user || idRemoval?.user;
|
||||
|
||||
if (redactionLogEntry) {
|
||||
if (redactionLogEntry.manual) {
|
||||
if (!manualRedactionEntry && redactionLogEntry.manualRedactionType === 'ADD') {
|
||||
// do not draw if it is no longer in the manual redactions
|
||||
annotationWrapper.shouldDraw = false;
|
||||
}
|
||||
if (manualRedactionEntry) {
|
||||
annotationWrapper.shouldDraw = manualRedactionEntry.status === 'REQUESTED' || manualRedactionEntry.status === 'APPROVED';
|
||||
}
|
||||
}
|
||||
|
||||
annotationWrapper.id = redactionLogEntry.id;
|
||||
annotationWrapper.redaction = redactionLogEntry.redacted;
|
||||
annotationWrapper.hint = redactionLogEntry.hint;
|
||||
@ -77,7 +67,26 @@ export class AnnotationWrapper {
|
||||
// either marked as manual or idRemove or manualRedactionEntry exists
|
||||
annotationWrapper.manual = redactionLogEntry.manual;
|
||||
annotationWrapper.modifyDictionary = !!manualRedactionEntry?.addToDictionary || !!idRemoval?.removeFromDictionary;
|
||||
|
||||
if (redactionLogEntry.manual) {
|
||||
// marked as add but the entryToAdd has been undone
|
||||
if (!manualRedactionEntry && redactionLogEntry.manualRedactionType === 'ADD') {
|
||||
// do not draw if it is no longer in the manual redactions
|
||||
annotationWrapper.shouldDraw = false;
|
||||
}
|
||||
if (manualRedactionEntry) {
|
||||
annotationWrapper.shouldDraw = manualRedactionEntry.status === 'REQUESTED' || manualRedactionEntry.status === 'APPROVED';
|
||||
}
|
||||
|
||||
// marked as remove but the idRemoval has been undone
|
||||
if (redactionLogEntry.manualRedactionType === 'REMOVE' && !idRemoval) {
|
||||
const dictionary = dictionaryData[redactionLogEntry.type];
|
||||
annotationWrapper.redaction = !dictionary.hint;
|
||||
annotationWrapper.hint = dictionary.hint;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no redaction log entry - not yet processed
|
||||
const dictionary = dictionaryData[manualRedactionEntry.type];
|
||||
annotationWrapper.id = manualRedactionEntry.id;
|
||||
annotationWrapper.redaction = !dictionary.hint;
|
||||
|
||||
@ -13,7 +13,6 @@ export class AnnotationDrawService {
|
||||
|
||||
public drawAnnotations(activeViewer: WebViewerInstance, annotationWrappers: AnnotationWrapper[]) {
|
||||
annotationWrappers.forEach((annotation) => {
|
||||
console.log('draw', annotation);
|
||||
this.drawAnnotation(activeViewer, annotation);
|
||||
});
|
||||
}
|
||||
|
||||
@ -124,24 +124,38 @@ export class ManualAnnotationService {
|
||||
// /manualRedaction/request/remove/
|
||||
removeOrSuggestRemoveAnnotation(annotationWrapper: AnnotationWrapper, removeFromDictionary: boolean = false) {
|
||||
if (this._permissionsService.isManagerAndOwner()) {
|
||||
return this._manualRedactionControllerService
|
||||
.removeRedaction(
|
||||
{
|
||||
annotationId: annotationWrapper.id,
|
||||
removeFromDictionary: removeFromDictionary,
|
||||
comment: 'Auto'
|
||||
},
|
||||
this._appStateService.activeProjectId,
|
||||
this._appStateService.activeFileId
|
||||
)
|
||||
.pipe(
|
||||
tap(
|
||||
() => this._notify('manual-annotation.remove-redaction-request.success'),
|
||||
() => {
|
||||
this._notify('manual-annotation.remove-redaction-request.error', NotificationType.ERROR);
|
||||
}
|
||||
// if it was something manual simply decline the existing request
|
||||
if (annotationWrapper.dictionary === 'manual') {
|
||||
return this._manualRedactionControllerService
|
||||
.declineRequest(this._appStateService.activeProjectId, this._appStateService.activeFileId, annotationWrapper.id)
|
||||
.pipe(
|
||||
tap(
|
||||
() => this._notify('manual-annotation.undo-request.success'),
|
||||
() => {
|
||||
this._notify('manual-annotation.undo-request.error', NotificationType.ERROR);
|
||||
}
|
||||
)
|
||||
);
|
||||
} else {
|
||||
return this._manualRedactionControllerService
|
||||
.removeRedaction(
|
||||
{
|
||||
annotationId: annotationWrapper.id,
|
||||
removeFromDictionary: removeFromDictionary,
|
||||
comment: 'Auto'
|
||||
},
|
||||
this._appStateService.activeProjectId,
|
||||
this._appStateService.activeFileId
|
||||
)
|
||||
);
|
||||
.pipe(
|
||||
tap(
|
||||
() => this._notify('manual-annotation.remove-redaction-request.success'),
|
||||
() => {
|
||||
this._notify('manual-annotation.remove-redaction-request.error', NotificationType.ERROR);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return this._manualRedactionControllerService
|
||||
.requestRemoveRedaction(
|
||||
|
||||
@ -370,7 +370,11 @@ export class AppStateService {
|
||||
type: 'suggestion',
|
||||
virtual: true
|
||||
};
|
||||
|
||||
this._dictionaryData['manual'] = {
|
||||
hexColor: colors.defaultColor,
|
||||
type: 'manual',
|
||||
virtual: true
|
||||
};
|
||||
this._dictionaryData['suggestion-dictionary'] = {
|
||||
hexColor: '#5B97DB',
|
||||
type: 'suggestion-dictionary',
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
"text": "Selected text:",
|
||||
"dictionary": "Type",
|
||||
"reason": "Reason",
|
||||
"legalBasis": "Legal Basis",
|
||||
"comment": "Comment"
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user