Import Redactions work in progress / fix for missing dossier templates, annotation debug

This commit is contained in:
Timo Bejan 2022-02-17 20:36:10 +02:00
parent 6565c2da20
commit c1a342e6ee
17 changed files with 109 additions and 20 deletions

View File

@ -37,7 +37,7 @@ export class DossierDetailsStatsComponent implements OnInit {
switchMap(() => this._filesService.getDeletedFilesFor(this.dossier.id)),
map(files => files.length),
);
this.dossierTemplateName = this._dossierTemplatesService.find(this.dossier.dossierTemplateId).name;
this.dossierTemplateName = this._dossierTemplatesService.find(this.dossier.dossierTemplateId)?.name || '-';
}
openEditDossierDialog(section: string): void {

View File

@ -36,6 +36,6 @@ export class DossiersListingDossierNameComponent {
}
getDossierTemplateNameFor(dossierTemplateId: string): string {
return this._dossierTemplatesService.find(dossierTemplateId).name;
return this._dossierTemplatesService.find(dossierTemplateId)?.name || '-';
}
}

View File

@ -1,11 +1,11 @@
<ng-container *ngIf="dossier.dossierStatusId">
<ng-container *ngIf="dossier.dossierStatusId && currentState">
<div class="flex-align-items-center dossier-status-container">
<div class="dossier-status-text">{{ currentState.name }}</div>
<redaction-small-chip [color]="currentState.color"></redaction-small-chip>
</div>
</ng-container>
<ng-container *ngIf="!dossier.dossierStatusId">
<ng-container *ngIf="!dossier.dossierStatusId || !currentState">
<div class="flex-align-items-center dossier-status-container">
<div class="dossier-status-text">{{ 'edit-dossier-dialog.general-info.form.dossier-status.placeholder' | translate }}</div>
<redaction-small-chip [color]="'#E2E4E9'"></redaction-small-chip>

View File

@ -143,7 +143,7 @@ export class ConfigService {
id =>
new NestedFilter({
id: id,
label: this._dossierTemplatesService.find(id).name,
label: this._dossierTemplatesService.find(id)?.name || '-',
}),
);

View File

@ -5,6 +5,7 @@ import { MultiSelectService } from '../../services/multi-select.service';
import { AnnotationReferencesService } from '../../services/annotation-references.service';
import { ViewModeService } from '../../services/view-mode.service';
import { FilePreviewStateService } from '../../services/file-preview-state.service';
import { UserPreferenceService } from '../../../../../../services/user-preference.service';
@Component({
selector: 'redaction-annotations-list',
@ -28,6 +29,7 @@ export class AnnotationsListComponent implements OnChanges {
readonly annotationReferencesService: AnnotationReferencesService,
private readonly _filterService: FilterService,
private readonly _state: FilePreviewStateService,
private readonly _userPreferenceService: UserPreferenceService,
) {}
ngOnChanges(changes: SimpleChanges): void {
@ -37,6 +39,10 @@ export class AnnotationsListComponent implements OnChanges {
}
annotationClicked(annotation: AnnotationWrapper, $event: MouseEvent): void {
if (this._userPreferenceService.areDevFeaturesEnabled) {
console.log('Selected Annotation:', annotation);
}
if (($event?.target as IqserEventTarget)?.localName === 'input') {
return;
}

View File

@ -2,7 +2,7 @@
<div #viewer [id]="(stateService.file$ | async).fileId" class="viewer"></div>
</div>
<input #compareFileInput (change)="uploadFile($event.target['files'])" class="file-upload-input" type="file" />
<input #compareFileInput (change)="uploadFile($event.target['files'])" class="file-upload-input" type="file" accept="application/pdf" />
<div *ngIf="utils?.totalPages && utils?.currentPage" class="pagination noselect">
<div (click)="utils.previousPage()">

View File

@ -4,6 +4,14 @@
<iqser-status-bar *ngIf="showStatusBar" [configs]="[{ color: file.workflowStatus, length: 1 }]"></iqser-status-bar>
</div>
<input
#importRedactionsInput
(change)="importRedactions($event.target['files'])"
class="file-upload-input"
type="file"
accept="application/pdf"
/>
<ng-container *ngIf="isFilePreview || isDossierOverviewWorkflow">
<ng-container *ngTemplateOutlet="actions"></ng-container>
</ng-container>

View File

@ -10,6 +10,10 @@
}
}
.file-upload-input {
display: none;
}
.reviewer {
display: flex;
align-items: center;

View File

@ -2,6 +2,7 @@ import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ElementRef,
HostBinding,
Input,
OnChanges,
@ -37,6 +38,9 @@ import { tap } from 'rxjs/operators';
import { DocumentInfoService } from '../../../screens/file-preview-screen/services/document-info.service';
import { ExpandableFileActionsComponent } from '@shared/components/expandable-file-actions/expandable-file-actions.component';
import { firstValueFrom } from 'rxjs';
import { environment } from '../../../../../../environments/environment';
import { loadCompareDocumentWrapper } from '../../../utils/compare-mode.utils';
import { RedactionImportService } from '../../services/redaction-import.service';
@Component({
selector: 'redaction-file-actions [file] [type]',
@ -52,12 +56,15 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnDestroy,
@Input() type: 'file-preview' | 'dossier-overview-list' | 'dossier-overview-workflow';
@Input() maxWidth: number;
@ViewChild('importRedactionsInput', { static: true }) importRedactionsInput: ElementRef;
toggleTooltip?: string;
assignTooltip?: string;
buttonType?: CircleButtonType;
showUndoApproval = false;
showAssignToSelf = false;
showImportRedactions = false;
showAssign = false;
showDelete = false;
showOCR = false;
@ -99,6 +106,7 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnDestroy,
private readonly _reanalysisService: ReanalysisService,
private readonly _router: Router,
private readonly _changeRef: ChangeDetectorRef,
private readonly _redactionImportService: RedactionImportService,
) {
super();
}
@ -139,6 +147,13 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnDestroy,
icon: 'red:assign-me',
show: this.showAssignToSelf,
},
{
type: ActionTypes.circleBtn,
action: $event => this._triggerImportRedactions($event),
tooltip: _('dossier-overview.import-redactions'),
icon: 'iqser:upload',
show: this.showImportRedactions,
},
{
type: ActionTypes.downloadBtn,
show: true,
@ -271,6 +286,25 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnDestroy,
);
}
private _triggerImportRedactions($event: MouseEvent) {
$event.stopPropagation();
this.importRedactionsInput.nativeElement.click();
}
async importRedactions(files: FileList) {
const fileToImport = files[0];
if (!fileToImport) {
console.error('No file to compare!');
return;
}
await firstValueFrom(this._redactionImportService.importRedactions(this.file.dossierId, this.file.fileId, fileToImport)).catch(
exception => {},
);
// reload file
}
forceReanalysisAction($event: LongPressEvent) {
this.analysisForced = !$event.touchEnd && this._userPreferenceService.areDevFeaturesEnabled;
this._setup();
@ -380,6 +414,8 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnDestroy,
(this._permissionsService.canAssignUser(this.file) || this._permissionsService.canUnassignUser(this.file)) &&
this.isDossierOverview;
this.showImportRedactions = this._permissionsService.canImportRedactions(this.file);
this.showReanalyseFilePreview = this.canReanalyse && this.isFilePreview && (this.analysisForced || this.canEnableAutoAnalysis);
this.showReanalyseDossierOverview =
this.canReanalyse && this.isDossierOverview && (this.analysisForced || this.canEnableAutoAnalysis);

View File

@ -0,0 +1,25 @@
import { Injectable, Injector } from '@angular/core';
import { GenericService, HeadersConfiguration, RequiredParam, Validate } from '@iqser/common-ui';
@Injectable()
export class RedactionImportService extends GenericService<void> {
constructor(protected readonly _injector: Injector) {
super(_injector, 'import-redactions');
}
@Validate()
importRedactions(@RequiredParam() dossierId: string, @RequiredParam() fileId: string, file?: Blob) {
const formParams = new FormData();
if (file !== undefined) {
formParams.append('file', file);
}
const headers = HeadersConfiguration.getHeaders({ contentType: false }).append('ngsw-bypass', 'true');
return this._http.post<void>(`/${this._defaultModelPath}/${dossierId}/${fileId}`, formParams, {
headers,
observe: 'response',
});
}
}

View File

@ -4,13 +4,14 @@ import { FileAssignService } from './services/file-assign.service';
import { FileActionsComponent } from './components/file-actions/file-actions.component';
import { IqserIconsModule } from '@iqser/common-ui';
import { SharedModule } from '@shared/shared.module';
import { RedactionImportService } from './services/redaction-import.service';
const components = [FileActionsComponent];
@NgModule({
declarations: [...components],
exports: [...components],
providers: [FileAssignService],
providers: [FileAssignService, RedactionImportService],
imports: [CommonModule, IqserIconsModule, SharedModule],
})
export class SharedDossiersModule {}

View File

@ -15,6 +15,6 @@ export class DictionariesMapService extends EntitiesMapService<Dictionary, IDict
}
getDictionaryColor(type: string, dossierTemplateId: string) {
return !this.get(dossierTemplateId) ? '#cccccc' : this.getDictionary(type, dossierTemplateId).hexColor;
return !this.get(dossierTemplateId) ? '#cccccc' : this.getDictionary(type, dossierTemplateId)?.hexColor || '#cccccc';
}
}

View File

@ -3,7 +3,7 @@ import { EntitiesService, mapEach, RequiredParam, Validate } from '@iqser/common
import { DossierState, IDossierState } from '@red/domain';
import { forkJoin, Observable, switchMap } from 'rxjs';
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
import { map, tap } from 'rxjs/operators';
import { defaultIfEmpty, map, tap } from 'rxjs/operators';
@Injectable({
providedIn: 'root',
@ -27,7 +27,7 @@ export class DossierStateService extends EntitiesService<DossierState, IDossierS
return this._dossierTemplatesService.all$.pipe(
mapEach(template => template.dossierTemplateId),
mapEach(id => this.loadAllForTemplate(id)),
switchMap(all => forkJoin(all)),
switchMap(all => forkJoin(all).pipe(defaultIfEmpty([]))),
map(value => value.flatMap(item => item)),
tap(value => this.setEntities(value)),
);

View File

@ -1,7 +1,7 @@
import { EntitiesService, List, mapEach, RequiredParam, Toaster, Validate } from '@iqser/common-ui';
import { DossierTemplate, IDossierTemplate } from '@red/domain';
import { Injectable, Injector } from '@angular/core';
import { forkJoin, Observable, throwError } from 'rxjs';
import { forkJoin, map, Observable, of, throwError } from 'rxjs';
import { FileAttributesService } from './file-attributes.service';
import { catchError, mapTo, switchMap, tap } from 'rxjs/operators';
import { DossierTemplateStatsService } from '@services/entity-services/dossier-template-stats.service';
@ -34,13 +34,17 @@ export class DossierTemplatesService extends EntitiesService<DossierTemplate, ID
return this.getAll().pipe(
mapEach(entity => new DossierTemplate(entity)),
/* Load stats before updating entities */
switchMap(templates =>
forkJoin([
this._dossierTemplateStatsService.getFor(dossierTemplateIds(templates)),
...getAttributes(templates),
this._dictionaryService.loadDictionaryData(dossierTemplateIds(templates)),
]).pipe(mapTo(templates)),
),
switchMap(templates => {
if (templates.length) {
return forkJoin([
this._dossierTemplateStatsService.getFor(dossierTemplateIds(templates)),
...getAttributes(templates),
this._dictionaryService.loadDictionaryData(dossierTemplateIds(templates)),
]).pipe(mapTo(templates));
} else {
return of(templates);
}
}),
tap(templates => this.setEntities(templates)),
);
}

View File

@ -154,6 +154,10 @@ export class PermissionsService {
return (comment.user === this._userService.currentUser.id || this.isApprover(dossier)) && !file.isApproved;
}
canImportRedactions(file: File) {
return (this.isFileAssignee(file) || this.isApprover(this._getDossier(file))) && !file.isApproved;
}
private _canToggleAnalysis(file: File): boolean {
return this.isFileAssignee(file) && (file.isNew || file.isUnderReview || file.isUnderApproval);
}

View File

@ -1,7 +1,7 @@
{
"ADMIN_CONTACT_NAME": null,
"ADMIN_CONTACT_URL": null,
"API_URL": "https://dev-04.iqser.cloud/redaction-gateway-v1",
"API_URL": "https://rosa1.iqser.cloud/redaction-gateway-v1",
"APP_NAME": "RedactManager",
"AUTO_READ_TIME": 3,
"BACKEND_APP_VERSION": "4.4.40",
@ -17,7 +17,7 @@
"MAX_RETRIES_ON_SERVER_ERROR": 3,
"OAUTH_CLIENT_ID": "redaction",
"OAUTH_IDP_HINT": null,
"OAUTH_URL": "https://dev-04.iqser.cloud/auth/realms/redaction",
"OAUTH_URL": "https://rosa1.iqser.cloud/auth/realms/redaction",
"RECENT_PERIOD_IN_HOURS": 24,
"SELECTION_MODE": "structural",
"MANUAL_BASE_URL": "https://docs.redactmanager.com/3.0"

View File

@ -733,6 +733,7 @@
"assign-approver": "Assign Approver",
"assign-me": "Assign To Me",
"assign-reviewer": "Assign User",
"import-redactions": "Import redactions from other file",
"bulk": {
"delete": "Delete Documents",
"reanalyse": "Analyze Documents"