RED-3356: Add Error handling for missing type in redaction log

This commit is contained in:
Adina Țeudan 2022-02-08 17:49:14 +02:00
parent 73cdcd9ca4
commit 2a3b32305a
8 changed files with 73 additions and 54 deletions

View File

@ -33,9 +33,9 @@
<mat-menu #userMenu="matMenu" xPosition="before"> <mat-menu #userMenu="matMenu" xPosition="before">
<ng-container *ngFor="let item of userMenuItems; trackBy: trackByName"> <ng-container *ngFor="let item of userMenuItems; trackBy: trackByName">
<button (click)="(item.action)" *ngIf="item.show" [routerLink]="item.routerLink" mat-menu-item translate> <a (click)="(item.action)" *ngIf="item.show" [routerLink]="item.routerLink" mat-menu-item>
{{ item.name }} {{ item.name | translate }}
</button> </a>
</ng-container> </ng-container>
<button (click)="userService.logout()" mat-menu-item> <button (click)="userService.logout()" mat-menu-item>

View File

@ -13,6 +13,7 @@ import { AnnotationWrapper } from './annotation.wrapper';
import * as moment from 'moment'; import * as moment from 'moment';
import { BehaviorSubject } from 'rxjs'; import { BehaviorSubject } from 'rxjs';
import { RedactionLogEntry } from './redaction-log.entry'; import { RedactionLogEntry } from './redaction-log.entry';
import { MISSING_TYPES_ERROR } from '@utils/constants';
export class FileDataModel { export class FileDataModel {
static readonly DELTA_VIEW_TIME = 10 * 60 * 1000; // 10 minutes; static readonly DELTA_VIEW_TIME = 10 * 60 * 1000; // 10 minutes;
@ -76,18 +77,23 @@ export class FileDataModel {
private _convertData(): RedactionLogEntry[] { private _convertData(): RedactionLogEntry[] {
let result: RedactionLogEntry[] = []; let result: RedactionLogEntry[] = [];
const missingTypes = new Set<string>();
const reasonAnnotationIds: { [key: string]: RedactionLogEntry[] } = {}; const reasonAnnotationIds: { [key: string]: RedactionLogEntry[] } = {};
this.redactionLog.redactionLogEntry?.forEach(redactionLogEntry => { this.redactionLog.redactionLogEntry?.forEach(redactionLogEntry => {
// copy the redactionLog Entry // copy the redactionLog Entry
const changeLogValues = this.getChangeLogValues(redactionLogEntry); const changeLogValues = this.#getChangeLogValues(redactionLogEntry);
if (!this._dictionaryData[redactionLogEntry.type]) {
missingTypes.add(redactionLogEntry.type);
return;
}
const redactionLogEntryWrapper: RedactionLogEntry = new RedactionLogEntry( const redactionLogEntryWrapper: RedactionLogEntry = new RedactionLogEntry(
redactionLogEntry, redactionLogEntry,
changeLogValues.changeLogType, changeLogValues.changeLogType,
changeLogValues.isChangeLogEntry, changeLogValues.isChangeLogEntry,
changeLogValues.hidden, changeLogValues.hidden,
this._dictionaryData[redactionLogEntry.type].hint,
this.redactionLog.legalBasis, this.redactionLog.legalBasis,
); );
@ -123,10 +129,14 @@ export class FileDataModel {
result = result.filter(r => !r.hidden); result = result.filter(r => !r.hidden);
if (missingTypes.size > 0) {
throw new Error(MISSING_TYPES_ERROR);
}
return result; return result;
} }
private getChangeLogValues(redactionLogEntry: IRedactionLogEntry): { #getChangeLogValues(redactionLogEntry: IRedactionLogEntry): {
hidden: boolean; hidden: boolean;
changeLogType: ChangeType; changeLogType: ChangeType;
isChangeLogEntry: boolean; isChangeLogEntry: boolean;

View File

@ -36,7 +36,6 @@ export class RedactionLogEntry implements IRedactionLogEntry {
readonly changeLogType: 'ADDED' | 'REMOVED' | 'CHANGED', readonly changeLogType: 'ADDED' | 'REMOVED' | 'CHANGED',
readonly isChangeLogEntry: boolean, readonly isChangeLogEntry: boolean,
readonly hidden: boolean, readonly hidden: boolean,
readonly hintDictionary: boolean,
readonly legalBasisList: ILegalBasis[], readonly legalBasisList: ILegalBasis[],
) { ) {
this.changes = redactionLogEntry.changes; this.changes = redactionLogEntry.changes;

View File

@ -1,9 +1,8 @@
<div *ngIf="references$ | async as references" class="content-container"> <div *ngIf="references$ | async as references" class="content-container">
<div class="dialog references-dialog"> <div class="dialog references-dialog">
<div class="references-header flex"> <div class="references-header flex">
<div class="small-label"> <div class="small-label uppercase">
{{ references.length }} {{ 'references' | translate: { count: references.length } }}
{{ (references.length === 1 ? 'references.singular' : 'references.plural') | translate }}
</div> </div>
<iqser-circle-button (action)="annotationReferencesService.hide()" icon="iqser:close"></iqser-circle-button> <iqser-circle-button (action)="annotationReferencesService.hide()" icon="iqser:close"></iqser-circle-button>
</div> </div>

View File

@ -1,5 +1,9 @@
@use 'variables'; @use 'variables';
.uppercase {
text-transform: uppercase;
}
.references-dialog { .references-dialog {
position: fixed; position: fixed;
margin: 0; margin: 0;

View File

@ -6,9 +6,12 @@ import { PermissionsService } from '@services/permissions.service';
import { File, IRedactionLog, IViewedPage } from '@red/domain'; import { File, IRedactionLog, IViewedPage } from '@red/domain';
import { RedactionLogService } from './redaction-log.service'; import { RedactionLogService } from './redaction-log.service';
import { ViewedPagesService } from '@services/entity-services/viewed-pages.service'; import { ViewedPagesService } from '@services/entity-services/viewed-pages.service';
import { AppStateService } from '../../../state/app-state.service'; import { AppStateService } from '@state/app-state.service';
import { UserPreferenceService } from '../../../services/user-preference.service'; import { UserPreferenceService } from '@services/user-preference.service';
import { FilePreviewStateService } from '../screens/file-preview-screen/services/file-preview-state.service'; import { FilePreviewStateService } from '../screens/file-preview-screen/services/file-preview-state.service';
import { Toaster } from '@iqser/common-ui';
import { MISSING_TYPES_ERROR } from '@utils/constants';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
@Injectable() @Injectable()
export class PdfViewerDataService { export class PdfViewerDataService {
@ -19,6 +22,7 @@ export class PdfViewerDataService {
private readonly _appStateService: AppStateService, private readonly _appStateService: AppStateService,
private readonly _userPreferenceService: UserPreferenceService, private readonly _userPreferenceService: UserPreferenceService,
private readonly _stateService: FilePreviewStateService, private readonly _stateService: FilePreviewStateService,
private readonly _toaster: Toaster,
) {} ) {}
loadRedactionLogFor(dossierId: string, fileId: string) { loadRedactionLogFor(dossierId: string, fileId: string) {
@ -33,15 +37,22 @@ export class PdfViewerDataService {
const viewedPages$ = this.getViewedPagesFor(newFile); const viewedPages$ = this.getViewedPagesFor(newFile);
return forkJoin([redactionLog$, viewedPages$]).pipe( return forkJoin([redactionLog$, viewedPages$]).pipe(
map( map((data: [redactionLog: IRedactionLog, viewedPages: IViewedPage[]]) => {
(data: [redactionLog: IRedactionLog, viewedPages: IViewedPage[]]) => try {
new FileDataModel( return new FileDataModel(
newFile, newFile,
...data, ...data,
this._appStateService.dictionaryData[this._stateService.dossierTemplateId], this._appStateService.dictionaryData[this._stateService.dossierTemplateId],
this._userPreferenceService.areDevFeaturesEnabled, this._userPreferenceService.areDevFeaturesEnabled,
), );
), } catch (error) {
if (error.message === MISSING_TYPES_ERROR) {
this._toaster.error(_('error.missing-types'), { disableTimeOut: true });
} else {
throw error;
}
}
}),
); );
} }

View File

@ -1 +1,2 @@
export const CHANGED_CHECK_INTERVAL = 5000; export const CHANGED_CHECK_INTERVAL = 5000;
export const MISSING_TYPES_ERROR = 'MISSING_TYPES_ERROR';

View File

@ -1,4 +1,8 @@
{ {
"accept-recommendation-dialog": {
"header": "Accept recommendation",
"multiple-values": "Multiple recommendations selected"
},
"account-settings": "Account Settings", "account-settings": "Account Settings",
"actions": { "actions": {
"all": "All", "all": "All",
@ -141,10 +145,6 @@
"settings": "Settings" "settings": "Settings"
}, },
"annotation": "Annotation", "annotation": "Annotation",
"references": {
"singular": "REFERENCE",
"plural": "REFERENCES"
},
"annotation-actions": { "annotation-actions": {
"accept-recommendation": { "accept-recommendation": {
"label": "Accept Recommendation" "label": "Accept Recommendation"
@ -161,9 +161,6 @@
"force-redaction": { "force-redaction": {
"label": "Force Redaction" "label": "Force Redaction"
}, },
"see-references": {
"label": "See References"
},
"hide": "Hide", "hide": "Hide",
"message": { "message": {
"dictionary": { "dictionary": {
@ -268,12 +265,15 @@
"resize": { "resize": {
"label": "Resize" "label": "Resize"
}, },
"see-references": {
"label": "See References"
},
"show": "Show", "show": "Show",
"undo": "Undo" "undo": "Undo"
}, },
"annotation-changes": { "annotation-changes": {
"forced-redaction": "Redaction forced",
"forced-hint": "Hint forced", "forced-hint": "Hint forced",
"forced-redaction": "Redaction forced",
"header": "Manual changes:", "header": "Manual changes:",
"legal-basis": "Reason changed", "legal-basis": "Reason changed",
"recategorized": "Image category changed", "recategorized": "Image category changed",
@ -296,6 +296,7 @@
"suggestion-add": "Suggested redaction", "suggestion-add": "Suggested redaction",
"suggestion-add-dictionary": "Suggested dictionary add", "suggestion-add-dictionary": "Suggested dictionary add",
"suggestion-change-legal-basis": "Suggested change legal basis", "suggestion-change-legal-basis": "Suggested change legal basis",
"suggestion-force-hint": "",
"suggestion-force-redaction": "Suggestion force hint", "suggestion-force-redaction": "Suggestion force hint",
"suggestion-recategorize-image": "Suggested recategorize image", "suggestion-recategorize-image": "Suggested recategorize image",
"suggestion-remove": "Suggested local removal", "suggestion-remove": "Suggested local removal",
@ -303,7 +304,6 @@
"suggestion-resize": "Suggested Resize" "suggestion-resize": "Suggested Resize"
}, },
"annotations": "Annotations", "annotations": "Annotations",
"archived": "Archived",
"assign-dossier-owner": { "assign-dossier-owner": {
"dialog": { "dialog": {
"approvers": "Approvers", "approvers": "Approvers",
@ -311,7 +311,6 @@
"no-reviewers": "No members with \"review only\" permission.", "no-reviewers": "No members with \"review only\" permission.",
"reviewers": "Reviewers", "reviewers": "Reviewers",
"search": "Search...", "search": "Search...",
"select-below": "Select from the list below.",
"single-user": "Owner" "single-user": "Owner"
} }
}, },
@ -403,14 +402,14 @@
"confirm-delete-file-attribute": { "confirm-delete-file-attribute": {
"cancel": "Keep {type, select, single{Attribute} bulk{Attributes} other{}}", "cancel": "Keep {type, select, single{Attribute} bulk{Attributes} other{}}",
"delete": "Delete {type, select, single{Attribute} bulk{Attributes} other{}}", "delete": "Delete {type, select, single{Attribute} bulk{Attributes} other{}}",
"file-impacted-documents": "All documents {type, select, single{it is} bulk{they are} other{}} used on will be impacted",
"dossier-impacted-documents": "All dossiers based on this template will be affected", "dossier-impacted-documents": "All dossiers based on this template will be affected",
"file-lost-details": "All inputted details on the documents will be lost",
"dossier-lost-details": "All values for this attribute will be lost", "dossier-lost-details": "All values for this attribute will be lost",
"file-impacted-documents": "All documents {type, select, single{it is} bulk{they are} other{}} used on will be impacted",
"file-lost-details": "All inputted details on the documents will be lost",
"impacted-report": "{count} reports use the placeholder for this attribute and need to be adjusted",
"title": "Delete {type, select, single{{name}} bulk{File Attributes} other{}}", "title": "Delete {type, select, single{{name}} bulk{File Attributes} other{}}",
"toast-error": "Please confirm that you understand the ramifications of your action!", "toast-error": "Please confirm that you understand the ramifications of your action!",
"warning": "Warning: this cannot be undone!", "warning": "Warning: this cannot be undone!"
"impacted-report": "{count} reports use the placeholder for this attribute and need to be adjusted"
}, },
"confirm-delete-users": { "confirm-delete-users": {
"cancel": "Keep {usersCount, plural, one{User} other{Users}}", "cancel": "Keep {usersCount, plural, one{User} other{Users}}",
@ -459,6 +458,12 @@
"question": "Are you sure you want to delete {filesCount, plural, one{this document} other{these documents}}?", "question": "Are you sure you want to delete {filesCount, plural, one{this document} other{these documents}}?",
"title": "Delete {filesCount, plural, one{{fileName}} other{Selected Documents}}" "title": "Delete {filesCount, plural, one{{fileName}} other{Selected Documents}}"
}, },
"report-template-same-name": {
"confirmation-text": "Yes. Continue upload",
"deny-text": "No. Cancel Upload",
"question": "There is already a Report Template with the name: <b>{fileName}</b>. Do you wish to continue?",
"title": "Report Template Upload"
},
"unsaved-changes": { "unsaved-changes": {
"confirmation-text": "Save and Leave", "confirmation-text": "Save and Leave",
"details": "If you leave the tab without saving, all the unsaved changes will be lost.", "details": "If you leave the tab without saving, all the unsaved changes will be lost.",
@ -472,12 +477,6 @@
"deny-text": "Cancel Upload", "deny-text": "Cancel Upload",
"question": "Please choose if <b>{fileName}</b> is a single or multi-file report template", "question": "Please choose if <b>{fileName}</b> is a single or multi-file report template",
"title": "Report Template Upload" "title": "Report Template Upload"
},
"report-template-same-name": {
"confirmation-text": "Yes. Continue upload",
"deny-text": "No. Cancel Upload",
"question": "There is already a Report Template with the name: <b>{fileName}</b>. Do you wish to continue?",
"title": "Report Template Upload"
} }
}, },
"content": "Reason", "content": "Reason",
@ -790,8 +789,8 @@
}, },
"table-col-names": { "table-col-names": {
"added-on": "Added", "added-on": "Added",
"last-modified": "Last modified on",
"assigned-to": "Assigned to", "assigned-to": "Assigned to",
"last-modified": "Last modified on",
"name": "Name", "name": "Name",
"needs-work": "Workload", "needs-work": "Workload",
"pages": "Pages", "pages": "Pages",
@ -808,20 +807,12 @@
"dossier-template-info-screen": { "dossier-template-info-screen": {
"created-by": "Created by", "created-by": "Created by",
"created-on": "Created on: {date}", "created-on": "Created on: {date}",
"valid-from": "Valid from: {date}",
"valid-to": "Valid to: {date}",
"description": "Description", "description": "Description",
"dictionaries": "{count} {count, plural, one{dictionary} other{dictionaries}}", "dictionaries": "{count} {count, plural, one{dictionary} other{dictionaries}}",
"entries": "{count} {count, plural, one{entry} other{entries}}", "entries": "{count} {count, plural, one{entry} other{entries}}",
"modified-on": "Modified on: {date}" "modified-on": "Modified on: {date}",
}, "valid-from": "Valid from: {date}",
"dossier-templates": { "valid-to": "Valid to: {date}"
"label": "Dossier Templates",
"status": {
"label": "Status",
"active": "Active",
"incomplete": "Incomplete"
}
}, },
"dossier-templates-listing": { "dossier-templates-listing": {
"action": { "action": {
@ -855,6 +846,13 @@
"title": "{length} dossier {length, plural, one{template} other{templates}}" "title": "{length} dossier {length, plural, one{template} other{templates}}"
} }
}, },
"dossier-templates": {
"label": "Dossier Templates",
"status": {
"active": "Active",
"incomplete": "Incomplete"
}
},
"download-includes": "Choose what is included at download:", "download-includes": "Choose what is included at download:",
"download-status": { "download-status": {
"queued": "Your download has been queued, you can see all your requested downloads here: <a href='/ui/main/downloads'>My Downloads<a/>." "queued": "Your download has been queued, you can see all your requested downloads here: <a href='/ui/main/downloads'>My Downloads<a/>."
@ -1002,6 +1000,7 @@
"http": { "http": {
"generic": "Action failed with code {status}" "generic": "Action failed with code {status}"
}, },
"missing-types": "The dossier template has missing types. Data might not be displayed correctly.",
"offline": "Disconnected", "offline": "Disconnected",
"online": "Reconnected", "online": "Reconnected",
"reload": "Reload", "reload": "Reload",
@ -1379,10 +1378,6 @@
} }
} }
}, },
"accept-recommendation-dialog": {
"header": "Accept recommendation",
"multiple-values": "Multiple recommendations selected"
},
"months": { "months": {
"apr": "Apr.", "apr": "Apr.",
"aug": "Aug.", "aug": "Aug.",
@ -1474,7 +1469,6 @@
}, },
"toggle-tooltips": "{active, select, true{Disable} false{Enable} other{}} annotation tooltips" "toggle-tooltips": "{active, select, true{Disable} false{Enable} other{}} annotation tooltips"
}, },
"pending-changes-guard": "WARNING: You have unsaved changes. Press Cancel to go back and save these changes, or OK to lose these changes.",
"readonly": "Read only", "readonly": "Read only",
"recategorize-image-dialog": { "recategorize-image-dialog": {
"actions": { "actions": {
@ -1489,6 +1483,7 @@
"header": "Edit Image Type" "header": "Edit Image Type"
}, },
"redaction": "Redaction", "redaction": "Redaction",
"references": "{count} {count, plural, one{reference} other{references}}",
"remove-annotations-dialog": { "remove-annotations-dialog": {
"cancel": "Cancel", "cancel": "Cancel",
"confirm": "Yes, proceed and remove!", "confirm": "Yes, proceed and remove!",