diff --git a/README.md b/README.md index 28ce2da2a..49fa5d365 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ To re-generate http rune swagger YOu need swagger-codegen installed `brew install swagger-codegen` ``` -BASE=https://red-staging.iqser.cloud/ +BASE=https://dev-06.iqser.cloud/ URL="$BASE"redaction-gateway-v1/v2/api-docs?group=redaction-gateway-v1 rm -Rf /tmp/swagger mkdir -p /tmp/swagger diff --git a/apps/red-ui/src/app/models/file/annotation.wrapper.ts b/apps/red-ui/src/app/models/file/annotation.wrapper.ts index 268c5efa5..d27d555d9 100644 --- a/apps/red-ui/src/app/models/file/annotation.wrapper.ts +++ b/apps/red-ui/src/app/models/file/annotation.wrapper.ts @@ -8,6 +8,7 @@ export class AnnotationWrapper { | 'remove-only-here' | 'change-legal-basis' | 'suggestion-change-legal-basis' + | 'suggestion-recategorize-image' | 'suggestion-add-dictionary' | 'suggestion-force-redaction' | 'suggestion-remove-dictionary' @@ -137,7 +138,11 @@ export class AnnotationWrapper { } get isSuggestion() { - return this.isSuggestionAdd || this.isSuggestionRemove || this.isSuggestionChangeLegalBasis; + return this.isSuggestionAdd || this.isSuggestionRemove || this.isSuggestionChangeLegalBasis || this.isSuggestionRecategorizeImage; + } + + get isSuggestionRecategorizeImage() { + return this.superType === 'suggestion-recategorize-image'; } get isSuggestionChangeLegalBasis() { @@ -229,6 +234,11 @@ export class AnnotationWrapper { return; } + if (redactionLogEntryWrapper.status === 'DECLINED') { + annotationWrapper.superType = 'declined-suggestion'; + return; + } + if (redactionLogEntryWrapper.manualRedactionType === 'FORCE_REDACT') { annotationWrapper.force = true; @@ -251,9 +261,10 @@ export class AnnotationWrapper { return; } - if (redactionLogEntryWrapper.status === 'DECLINED') { - annotationWrapper.superType = 'declined-suggestion'; - return; + if (redactionLogEntryWrapper.manualRedactionType === 'RECATEGORIZE') { + if (redactionLogEntryWrapper.status === 'REQUESTED') { + annotationWrapper.superType = 'suggestion-recategorize-image'; + } } if (annotationWrapper.dictionary?.toLowerCase() === 'false_positive') { diff --git a/apps/red-ui/src/app/models/file/redaction-log-entry.wrapper.ts b/apps/red-ui/src/app/models/file/redaction-log-entry.wrapper.ts index a9592e82e..2ddc9d003 100644 --- a/apps/red-ui/src/app/models/file/redaction-log-entry.wrapper.ts +++ b/apps/red-ui/src/app/models/file/redaction-log-entry.wrapper.ts @@ -8,7 +8,7 @@ export interface RedactionLogEntryWrapper { legalBasis?: string; legalBasisMapping?: Array; manual?: boolean; - manualRedactionType?: 'ADD' | 'REMOVE' | 'UNDO' | 'LEGAL_BASIS_CHANGE' | 'FORCE_REDACT'; + manualRedactionType?: 'ADD' | 'REMOVE' | 'UNDO' | 'LEGAL_BASIS_CHANGE' | 'FORCE_REDACT' | 'RECATEGORIZE'; matchedRule?: number; positions?: Array; reason?: string; diff --git a/apps/red-ui/src/app/state/app-state.service.ts b/apps/red-ui/src/app/state/app-state.service.ts index 03e251741..f8117c4ea 100644 --- a/apps/red-ui/src/app/state/app-state.service.ts +++ b/apps/red-ui/src/app/state/app-state.service.ts @@ -160,27 +160,15 @@ export class AppStateService { } private static _isFileOverviewRoute(event: Event) { - return ( - event instanceof ResolveStart && - event.url.includes('/main/dossiers/') && - event.url.includes('/file/') - ); + return event instanceof ResolveStart && event.url.includes('/main/dossiers/') && event.url.includes('/file/'); } private static _isDossierOverviewRoute(event: Event) { - return ( - event instanceof ResolveStart && - event.url.includes('/main/dossiers/') && - !event.url.includes('/file/') - ); + return event instanceof ResolveStart && event.url.includes('/main/dossiers/') && !event.url.includes('/file/'); } private static _isRandomRoute(event: Event) { - return ( - event instanceof NavigationEnd && - !event.url.includes('/main/dossiers/') && - !event.url.includes('/file/') - ); + return event instanceof NavigationEnd && !event.url.includes('/main/dossiers/') && !event.url.includes('/file/'); } async reloadActiveDossierFilesIfNecessary() { @@ -194,10 +182,7 @@ export class AppStateService { dossierTemplateId = this.activeDossier.dossierTemplateId; } if (!dossierTemplateId) { - dossierTemplateId = - this.dossierTemplates.length > 0 - ? this.dossierTemplates[0].dossierTemplateId - : undefined; + dossierTemplateId = this.dossierTemplates.length > 0 ? this.dossierTemplates[0].dossierTemplateId : undefined; } if (!dossierTemplateId) { return undefined; @@ -216,10 +201,7 @@ export class AppStateService { } if (!dossierTemplateId) { - dossierTemplateId = - this.dossierTemplates.length > 0 - ? this.dossierTemplates[0].dossierTemplateId - : undefined; + dossierTemplateId = this.dossierTemplates.length > 0 ? this.dossierTemplates[0].dossierTemplateId : undefined; } if (!dossierTemplateId) { return undefined; @@ -240,13 +222,9 @@ export class AppStateService { async loadAllDossiers(emitEvents: boolean = true) { const dossiers = await this._dossierControllerService.getDossiers().toPromise(); if (dossiers) { - const mappedDossiers = dossiers.map( - p => new DossierWrapper(p, this._getExistingFiles(p.dossierId)) - ); + const mappedDossiers = dossiers.map(p => new DossierWrapper(p, this._getExistingFiles(p.dossierId))); - const fileData = await this._statusControllerService - .getFileStatusForDossiers(mappedDossiers.map(p => p.dossierId)) - .toPromise(); + const fileData = await this._statusControllerService.getFileStatusForDossiers(mappedDossiers.map(p => p.dossierId)).toPromise(); for (const dossierId of Object.keys(fileData)) { const dossier = mappedDossiers.find(p => p.dossierId === dossierId); @@ -263,9 +241,7 @@ export class AppStateService { return null; } const oldProcessedDate = this.activeFile.lastProcessed; - const activeFile = await this._statusControllerService - .getFileStatus(this.activeDossierId, this.activeFileId) - .toPromise(); + const activeFile = await this._statusControllerService.getFileStatus(this.activeDossierId, this.activeFileId).toPromise(); const activeFileWrapper = new FileStatusWrapper( activeFile, @@ -289,9 +265,7 @@ export class AppStateService { if (!dossier) { dossier = this.activeDossier; } - const files = await this._statusControllerService - .getDossierStatus(dossier.dossierId) - .toPromise(); + const files = await this._statusControllerService.getDossierStatus(dossier.dossierId).toPromise(); return this._processFiles(dossier, files, emitEvents); } @@ -317,21 +291,18 @@ export class AppStateService { updateDossierDictionary(dossierTemplateId: string, dossierId: string) { // dossier exists, load it's dictionary - this._dictionaryControllerService - .getDictionaryForType(dossierTemplateId, 'dossier_redaction', dossierId) - .subscribe( - typeData => { - this.activeDossier.type = typeData; - }, - () => { - this.activeDossier.type = null; - } - ); + this._dictionaryControllerService.getDictionaryForType(dossierTemplateId, 'dossier_redaction', dossierId).subscribe( + typeData => { + this.activeDossier.type = typeData; + }, + () => { + this.activeDossier.type = null; + } + ); } activateFile(dossierId: string, fileId: string) { - if (this._appState.activeDossierId === dossierId && this._appState.activeFileId === fileId) - return; + if (this._appState.activeDossierId === dossierId && this._appState.activeFileId === fileId) return; this.activateDossier(dossierId); if (this.activeDossier) { this._appState.activeFileId = fileId; @@ -357,9 +328,7 @@ export class AppStateService { this._appState.activeDictionaryType = dictionaryType; if (!this.activeDictionary) { this._appState.activeDictionaryType = null; - this._router.navigate([ - '/main/admin/dossier-templates/' + this.activeDossierTemplateId - ]); + this._router.navigate(['/main/admin/dossier-templates/' + this.activeDossierTemplateId]); } } } @@ -377,9 +346,7 @@ export class AppStateService { .toPromise() .then( () => { - const index = this._appState.dossiers.findIndex( - p => p.dossier.dossierId === dossier.dossierId - ); + const index = this._appState.dossiers.findIndex(p => p.dossier.dossierId === dossier.dossierId); this._appState.dossiers.splice(index, 1); this._appState.dossiers = [...this._appState.dossiers]; }, @@ -395,12 +362,8 @@ export class AppStateService { async addOrUpdateDossier(dossier: Dossier) { try { - const updatedDossier = await this._dossierControllerService - .createOrUpdateDossier(dossier) - .toPromise(); - let foundDossier = this._appState.dossiers.find( - p => p.dossier.dossierId === updatedDossier.dossierId - ); + const updatedDossier = await this._dossierControllerService.createOrUpdateDossier(dossier).toPromise(); + let foundDossier = this._appState.dossiers.find(p => p.dossier.dossierId === updatedDossier.dossierId); if (foundDossier) { Object.assign((foundDossier.dossier = updatedDossier)); } else { @@ -412,9 +375,7 @@ export class AppStateService { } catch (error) { this._notificationService.showToastNotification( this._translateService.instant( - error.status === 409 - ? 'add-dossier-dialog.errors.dossier-already-exists' - : 'add-dossier-dialog.errors.generic' + error.status === 409 ? 'add-dossier-dialog.errors.dossier-already-exists' : 'add-dossier-dialog.errors.generic' ), null, NotificationType.ERROR @@ -429,19 +390,14 @@ export class AppStateService { } async loadAllDossierTemplates() { - const dossierTemplates = await this._dossierTemplateControllerService - .getAllDossierTemplates() - .toPromise(); - this._appState.dossierTemplates = dossierTemplates.map( - dossierTemplate => new DossierTemplateModelWrapper(dossierTemplate) - ); + const dossierTemplates = await this._dossierTemplateControllerService.getAllDossierTemplates().toPromise(); + this._appState.dossierTemplates = dossierTemplates.map(dossierTemplate => new DossierTemplateModelWrapper(dossierTemplate)); this._appState.fileAttributesConfig = {}; for (const dossierTemplate of this._appState.dossierTemplates) { - this._appState.fileAttributesConfig[dossierTemplate.dossierTemplateId] = - await this._fileAttributesService - .getFileAttributesConfiguration(dossierTemplate.dossierTemplateId) - .pipe(catchError(() => of({}))) - .toPromise(); + this._appState.fileAttributesConfig[dossierTemplate.dossierTemplateId] = await this._fileAttributesService + .getFileAttributesConfiguration(dossierTemplate.dossierTemplateId) + .pipe(catchError(() => of({}))) + .toPromise(); } } @@ -465,10 +421,7 @@ export class AppStateService { } } - getDictionaryDataForDossierTemplateObservables( - dossierTemplateId: string, - dictionaryData: { [key: string]: any } - ): Observable[] { + getDictionaryDataForDossierTemplateObservables(dossierTemplateId: string, dictionaryData: { [key: string]: any }): Observable[] { const typeObs = this._dictionaryControllerService.getAllTypes(dossierTemplateId).pipe( tap(typesResponse => { for (const type of typesResponse.types) { @@ -568,6 +521,14 @@ export class AppStateService { null, true ); + dictionaryData['suggestion-recategorize-image'] = new TypeValueWrapper( + { + hexColor: colors.requestAdd, + type: 'suggestion-recategorize-image' + }, + null, + true + ); dictionaryData['suggestion-add-dictionary'] = new TypeValueWrapper( { hexColor: colors.dictionaryRequestColor, @@ -704,11 +665,7 @@ export class AppStateService { return found ? found.files : []; } - private _processFiles( - dossier: DossierWrapper, - files: FileStatus[], - emitEvents: boolean = true - ) { + private _processFiles(dossier: DossierWrapper, files: FileStatus[], emitEvents: boolean = true) { const oldFiles = [...dossier.files]; const fileStatusChangedEvent = []; diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index cb33e9c3d..0a6b42e2f 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -242,6 +242,7 @@ "suggestion-add": "Suggested redaction", "suggestion-add-dictionary": "Suggested dictionary add", "suggestion-change-legal-basis": "Suggested change legal basis", + "suggestion-recategorize-image": "Suggested recategorize image", "suggestion-force-redaction": "Suggestion force redaction", "suggestion-remove": "Suggested redaction removal", "suggestion-remove-dictionary": "Suggested dictionary removal" diff --git a/libs/red-ui-http/src/lib/model/imageRecategorizationRequest.ts b/libs/red-ui-http/src/lib/model/imageRecategorizationRequest.ts index 64c71ca5d..11931772e 100644 --- a/libs/red-ui-http/src/lib/model/imageRecategorizationRequest.ts +++ b/libs/red-ui-http/src/lib/model/imageRecategorizationRequest.ts @@ -13,7 +13,5 @@ export interface ImageRecategorizationRequest { annotationId?: string; comment?: string; - legalBasis?: string; - redacted?: boolean; type?: string; } diff --git a/libs/red-ui-http/src/lib/model/typeValue.ts b/libs/red-ui-http/src/lib/model/typeValue.ts index d92d7db52..c46a17a52 100644 --- a/libs/red-ui-http/src/lib/model/typeValue.ts +++ b/libs/red-ui-http/src/lib/model/typeValue.ts @@ -50,4 +50,8 @@ export interface TypeValue { * The nonnull entry type. */ type?: string; + /** + * The label of this type + */ + label?: string; } diff --git a/libs/red-ui-http/src/lib/model/updateTypeValue.ts b/libs/red-ui-http/src/lib/model/updateTypeValue.ts index 4543aad5d..358251343 100644 --- a/libs/red-ui-http/src/lib/model/updateTypeValue.ts +++ b/libs/red-ui-http/src/lib/model/updateTypeValue.ts @@ -42,4 +42,8 @@ export interface UpdateTypeValue { * True if the type just for recommendations, not for redaction, default is false. */ recommendation?: boolean; + /** + * The label of this type + */ + label?: string; }