remove files related methods from app state

This commit is contained in:
Dan Percic 2021-11-22 11:17:23 +02:00
parent fd00fddc42
commit 59b9e69458
24 changed files with 129 additions and 161 deletions

View File

@ -5,6 +5,7 @@ import { BreadcrumbsService } from '../services/breadcrumbs.service';
import { pluck } from 'rxjs/operators';
import { AppStateService } from '../state/app-state.service';
import { FilesMapService } from '../services/entity-services/files-map.service';
import { FilesService } from '@services/entity-services/files.service';
@Injectable({ providedIn: 'root' })
export class DossierFilesGuard implements CanActivate, CanDeactivate<unknown> {
@ -13,20 +14,20 @@ export class DossierFilesGuard implements CanActivate, CanDeactivate<unknown> {
private readonly _appStateService: AppStateService,
private readonly _breadcrumbsService: BreadcrumbsService,
private readonly _filesMapService: FilesMapService,
private readonly _filesService: FilesService,
private readonly _router: Router,
) {}
async canActivate(route: ActivatedRouteSnapshot): Promise<boolean> {
const dossierId = route.paramMap.get('dossierId');
const dossier = this._dossiersService.find(dossierId);
if (!dossier) {
if (!this._dossiersService.has(dossierId)) {
await this._router.navigate(['/main', 'dossiers']);
return false;
}
if (!this._filesMapService.has(dossierId)) {
await this._appStateService.getFiles(dossier);
await this._filesService.loadAll(dossierId).toPromise();
}
this._breadcrumbsService.append({

View File

@ -14,6 +14,7 @@
(remove)="toggleSelected($event)"
[canAdd]="false"
[canRemove]="true"
[dossierId]="dossier.dossierId"
[largeSpacing]="true"
[memberIds]="selectedApproversList"
[perLine]="13"
@ -27,6 +28,7 @@
(remove)="toggleSelected($event)"
[canAdd]="false"
[canRemove]="true"
[dossierId]="dossier.dossierId"
[largeSpacing]="true"
[memberIds]="selectedReviewers$ | async"
[perLine]="13"

View File

@ -19,7 +19,6 @@ import { getLeftDateTime } from '@utils/functions';
import { Observable } from 'rxjs';
import { distinctUntilChanged, map } from 'rxjs/operators';
import { DossiersDialogService } from '../../../services/dossiers-dialog.service';
import { AppStateService } from '@state/app-state.service';
import { FilesService } from '@services/entity-services/files.service';
import { FileManagementService } from '../../../shared/services/file-management.service';
@ -56,7 +55,6 @@ export class EditDossierDeletedDocumentsComponent extends ListingComponent<FileL
constructor(
protected readonly _injector: Injector,
private readonly _fileManagementService: FileManagementService,
private readonly _appStateService: AppStateService,
private readonly _filesService: FilesService,
private readonly _loadingService: LoadingService,
private readonly _configService: ConfigService,
@ -115,7 +113,7 @@ export class EditDossierDeletedDocumentsComponent extends ListingComponent<FileL
const fileIds = files.map(f => f.fileId);
await this._fileManagementService.restore(fileIds, this.dossier.id).toPromise();
this._removeFromList(fileIds);
await this._appStateService.reloadDossierFiles(files[0].dossierId);
await this._filesService.loadAll(files[0].dossierId).toPromise();
this.updateDossier.emit();
}

View File

@ -34,15 +34,15 @@
<div>
<mat-icon svgIcon="red:template"></mat-icon>
<span>{{ dossierTemplate(dossier).name }} </span>
<span>{{ dossierTemplateName }} </span>
</div>
<div (click)="openDossierDictionaryDialog.emit()" class="link-property">
<div (click)="openEditDossierDialog('dossierDictionary')" class="link-property">
<mat-icon svgIcon="red:dictionary"></mat-icon>
<span>{{ 'dossier-overview.dossier-details.dictionary' | translate }} </span>
</div>
<div (click)="openEditDossierAttributesDialog(dossier.dossierId, 'deletedDocuments')" class="link-property">
<div (click)="openEditDossierDialog('deletedDocuments')" class="link-property">
<mat-icon svgIcon="iqser:trash"></mat-icon>
<span>{{ 'dossier-overview.dossier-details.stats.deleted' | translate: { count: deletedFilesCount$ | async } }}</span>
</div>
@ -53,11 +53,7 @@
</div>
<ng-container *ngIf="attributesExpanded">
<div
(click)="openEditDossierAttributesDialog(dossier.dossierId, 'dossierAttributes')"
*ngFor="let attr of dossierAttributes"
class="link-property"
>
<div (click)="openEditDossierDialog('dossierAttributes')" *ngFor="let attr of dossierAttributes" class="link-property">
<mat-icon svgIcon="red:attribute"></mat-icon>
<span *ngIf="!attr.value"> {{ attr.label + ': -' }}</span>
<span *ngIf="attr.value && attr.type === 'DATE'"> {{ attr.label + ': ' + (attr.value | date: 'd MMM. yyyy') }}</span>

View File

@ -1,7 +1,6 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { Dossier, DossierAttributeWithValue, DossierStats, DossierTemplate } from '@red/domain';
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
import { Dossier, DossierAttributeWithValue, DossierStats } from '@red/domain';
import { DossiersDialogService } from '../../../../services/dossiers-dialog.service';
import { DossiersService } from '@services/entity-services/dossiers.service';
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
import { FilesService } from '@services/entity-services/files.service';
import { Observable } from 'rxjs';
@ -13,17 +12,16 @@ import { FilesMapService } from '@services/entity-services/files-map.service';
selector: 'redaction-dossier-details-stats',
templateUrl: './dossier-details-stats.component.html',
styleUrls: ['./dossier-details-stats.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DossierDetailsStatsComponent implements OnInit {
@Input() dossierAttributes: DossierAttributeWithValue[];
@Input() dossier: Dossier;
attributesExpanded = false;
dossierTemplateName: string;
deletedFilesCount$: Observable<number>;
dossierStats$: Observable<DossierStats>;
@Input()
dossierAttributes: DossierAttributeWithValue[];
@Input()
dossier: Dossier;
@Output()
readonly openDossierDictionaryDialog = new EventEmitter();
constructor(
private readonly _dossierTemplatesService: DossierTemplatesService,
@ -31,7 +29,6 @@ export class DossierDetailsStatsComponent implements OnInit {
private readonly _filesService: FilesService,
private readonly _dossierStatsService: DossierStatsService,
private readonly _filesMapService: FilesMapService,
readonly dossiersService: DossiersService,
) {}
ngOnInit() {
@ -40,16 +37,13 @@ export class DossierDetailsStatsComponent implements OnInit {
switchMapTo(this._filesService.getDeletedFilesFor(this.dossier.id)),
map(files => files.length),
);
this.dossierTemplateName = this._dossierTemplatesService.find(this.dossier.dossierTemplateId).name;
}
dossierTemplate(dossier: Dossier): DossierTemplate {
return this._dossierTemplatesService.find(dossier.dossierTemplateId);
}
openEditDossierAttributesDialog(dossierId: string, section: string) {
this._dialogService.openDialog('editDossier', null, {
dossierId,
section: section,
openEditDossierDialog(section: string): void {
const data = { dossierId: this.dossier.dossierId, section };
this._dialogService.openDialog('editDossier', null, data, async () => {
await this._filesService.loadAll(this.dossier.dossierId).toPromise();
});
}
}

View File

@ -32,11 +32,7 @@
<div class="mt-16">
<div class="all-caps-label" translate="dossier-details.members"></div>
<redaction-team-members
(openAssignDossierMembersDialog)="openEditDossierDialog(dossier, 'members')"
[memberIds]="dossier.memberIds"
[perLine]="9"
></redaction-team-members>
<redaction-team-members [dossierId]="dossierId" [memberIds]="dossier.memberIds" [perLine]="9"></redaction-team-members>
</div>
<ng-container *ngIf="dossierStats$ | async as stats">
@ -65,11 +61,7 @@
</div>
<div [class.mt-24]="!stats.hasFiles" class="pb-32">
<redaction-dossier-details-stats
(openDossierDictionaryDialog)="openEditDossierDialog(dossier, 'dossierDictionary')"
[dossierAttributes]="dossierAttributes"
[dossier]="dossier"
></redaction-dossier-details-stats>
<redaction-dossier-details-stats [dossierAttributes]="dossierAttributes" [dossier]="dossier"></redaction-dossier-details-stats>
</div>
</ng-container>

View File

@ -13,6 +13,7 @@ import { Observable } from 'rxjs';
import { DossierStatsService } from '@services/entity-services/dossier-stats.service';
import { pluck, switchMap } from 'rxjs/operators';
import { DossiersDialogService } from '../../../../services/dossiers-dialog.service';
import { FilesService } from '@services/entity-services/files.service';
@Component({
selector: 'redaction-dossier-details',
@ -40,6 +41,7 @@ export class DossierDetailsComponent {
readonly filterService: FilterService,
private readonly _changeDetectorRef: ChangeDetectorRef,
private readonly _userService: UserService,
private readonly _filesService: FilesService,
private readonly _dossierStatsService: DossierStatsService,
private readonly _toaster: Toaster,
private readonly _dialogService: DossiersDialogService,
@ -77,11 +79,4 @@ export class DossierDetailsComponent {
const dossierName = dossier.dossierName;
this._toaster.info(_('assignment.owner'), { params: { ownerName, dossierName } });
}
openEditDossierDialog(dossier: Dossier, section: string): void {
const data = { dossierId: this.dossierId, section };
this._dialogService.openDialog('editDossier', null, data, async () => {
await this.appStateService.getFiles(dossier);
});
}
}

View File

@ -4,10 +4,10 @@
</div>
</div>
<div *ngIf="file.primaryAttribute" class="small-label">
<div *ngIf="primaryAttribute" class="small-label">
<div class="primary-attribute">
<span [matTooltip]="file.primaryAttribute" matTooltipPosition="above">
{{ file.primaryAttribute }}
<span [matTooltip]="primaryAttribute" matTooltipPosition="above">
{{ primaryAttribute }}
</span>
</div>
</div>

View File

@ -1,5 +1,6 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core';
import { File } from '@red/domain';
import { FileAttributesService } from '@services/entity-services/file-attributes.service';
@Component({
selector: 'redaction-file-name-column',
@ -7,6 +8,24 @@ import { File } from '@red/domain';
styleUrls: ['./file-name-column.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class FileNameColumnComponent {
export class FileNameColumnComponent implements OnChanges {
@Input() file: File;
@Input() dossierTemplateId: string;
primaryAttribute: string;
constructor(private readonly _fileAttributesService: FileAttributesService) {}
ngOnChanges() {
const fileAttributesConfig = this._fileAttributesService.getFileAttributeConfig(this.dossierTemplateId);
if (fileAttributesConfig) {
const primary = fileAttributesConfig.fileAttributeConfigs?.find(c => c.primaryAttribute);
if (primary && this.file.fileAttributes?.attributeIdToValue) {
this.primaryAttribute = this.file.fileAttributes?.attributeIdToValue[primary.id];
}
if (!this.primaryAttribute) {
this.primaryAttribute = '-';
}
}
}
}

View File

@ -1,5 +1,5 @@
<div class="cell">
<redaction-file-name-column [file]="file"></redaction-file-name-column>
<redaction-file-name-column [dossierTemplateId]="dossierTemplateId" [file]="file"></redaction-file-name-column>
</div>
<div class="cell">

View File

@ -11,5 +11,6 @@ import { Required } from '@iqser/common-ui';
export class TableItemComponent {
@Input() @Required() file!: File;
@Input() @Required() displayedAttributes!: IFileAttributeConfig[];
@Input() dossierTemplateId: string;
@Output() readonly calculateData = new EventEmitter<string>();
}

View File

@ -56,6 +56,15 @@
<ng-template #bulkActions>
<redaction-dossier-overview-bulk-actions (reload)="reloadFiles()" [dossier]="dossier"></redaction-dossier-overview-bulk-actions>
</ng-template>
<ng-template #tableItemTemplate let-file="entity">
<redaction-table-item
(calculateData)="actionPerformed($event)"
[displayedAttributes]="displayedAttributes"
[dossierTemplateId]="dossier.dossierTemplateId"
[file]="file"
></redaction-table-item>
</ng-template>
</ng-container>
<ng-template #needsWorkFilterTemplate let-filter="filter">
@ -64,14 +73,6 @@
<input #fileInput (change)="uploadFiles($event.target['files'])" class="file-upload-input" multiple="true" type="file" />
<ng-template #tableItemTemplate let-file="entity">
<redaction-table-item
(calculateData)="actionPerformed($event)"
[displayedAttributes]="displayedAttributes"
[file]="file"
></redaction-table-item>
</ng-template>
<ng-template #workflowItemTemplate let-entity="entity">
<redaction-workflow-item (actionPerformed)="actionPerformed($event, entity)" [file]="entity"></redaction-workflow-item>
</ng-template>

View File

@ -46,7 +46,6 @@ import { DossierTemplatesService } from '@services/entity-services/dossier-templ
import { LongPressEvent } from '@shared/directives/long-press.directive';
import { UserPreferenceService } from '@services/user-preference.service';
import { FilesMapService } from '@services/entity-services/files-map.service';
import { DossierStatsService } from '@services/entity-services/dossier-stats.service';
import { FilesService } from '@services/entity-services/files.service';
@Component({
@ -94,7 +93,6 @@ export class DossierOverviewScreenComponent extends ListingComponent<File> imple
readonly configService: ConfigService,
private readonly _userPreferenceService: UserPreferenceService,
private readonly _fileMapService: FilesMapService,
private readonly _dossierStatsService: DossierStatsService,
activatedRoute: ActivatedRoute,
) {
super(_injector);
@ -205,8 +203,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<File> imple
}
async reloadFiles() {
await this._appStateService.getFiles(this.currentDossier);
await this._dossierStatsService.getFor([this.dossierId]).toPromise();
await this._filesService.loadAll(this.dossierId).toPromise();
this._computeAllFilters();
}

View File

@ -367,7 +367,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
response.manualRedactionEntryWrapper.rectId,
);
this._instance.Core.annotationManager.deleteAnnotation(annotation);
await this.appStateService.reloadFile(this.dossierId, this.fileId);
await this._filesService.reload(this.dossierId, this.fileId);
const distinctPages = manualRedactionEntryWrapper.manualRedactionEntry.positions
.map(p => p.page)
.filter((item, pos, self) => self.indexOf(item) === pos);
@ -475,11 +475,11 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
case 'reanalyse':
await this._loadFileData(true);
this._updateCanPerformActions();
await this.appStateService.reloadDossierFiles(this.dossierId);
await this._filesService.loadAll(this.dossierId).toPromise();
return;
case 'exclude-pages':
await this.appStateService.reloadDossierFiles(this.dossierId);
await this._filesService.loadAll(this.dossierId).toPromise();
await this._loadFileData(true);
this._cleanupAndRedrawManualAnnotations$();
await this._stampPDF();
@ -508,7 +508,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
async assignToMe(file: File) {
await this._fileActionService.assignToMe([file], async () => {
await this.appStateService.reloadFile(this.dossierId, this.fileId);
await this._filesService.reload(this.dossierId, this.fileId);
this._updateCanPerformActions();
});
}
@ -521,7 +521,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
await this._filesService.setReviewerFor([fileId], dossierId, reviewerId).toPromise();
this._toaster.info(_('assignment.reviewer'), { params: { reviewerName, filename } });
await this.appStateService.reloadFile(this.dossierId, this.fileId);
await this._filesService.reload(this.dossierId, this.fileId);
this._updateCanPerformActions();
this.editingReviewer = false;
}
@ -617,7 +617,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
private _subscribeToFileUpdates(): void {
this.addSubscription = timer(0, 5000)
.pipe(switchMap(() => this.appStateService.reloadFile(this.dossierId, this.fileId)))
.pipe(switchMap(() => this._filesService.reload(this.dossierId, this.fileId)))
.subscribe();
this.addSubscription = this._filesMapService.fileReanalysed$
.pipe(filter(file => file.fileId === this.fileId))
@ -679,7 +679,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
const currentPageAnnotations = this.annotations.filter(a => a.pageNumber === page);
const currentPageAnnotationIds = currentPageAnnotations.map(a => a.id);
await this.appStateService.reloadFile(this.dossierId, this.fileId);
await this._filesService.reload(this.dossierId, this.fileId);
this.fileData.redactionLog = await this._fileDownloadService.loadRedactionLogFor(this.dossierId, this.fileId).toPromise();
this.rebuildFilters();

View File

@ -20,6 +20,7 @@ import { LongPressEvent } from '@shared/directives/long-press.directive';
import { FileActionService } from '../../services/file-action.service';
import { DossiersService } from '@services/entity-services/dossiers.service';
import { FileManagementService } from '../../services/file-management.service';
import { FilesService } from '@services/entity-services/files.service';
@Component({
selector: 'redaction-file-actions',
@ -70,6 +71,7 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnDestroy,
private readonly _fileActionService: FileActionService,
private readonly _loadingService: LoadingService,
private readonly _fileManagementService: FileManagementService,
private readonly _filesService: FilesService,
private readonly _userService: UserService,
private readonly _toaster: Toaster,
private readonly _userPreferenceService: UserPreferenceService,
@ -117,7 +119,7 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnDestroy,
.catch(error => {
this._toaster.error(_('error.http.generic'), { params: error });
});
await this.appStateService.reloadDossierFiles(this.file.dossierId);
await this._filesService.loadAll(this.file.dossierId).toPromise();
this.actionPerformed.emit('delete');
this._loadingService.stop();
},
@ -191,14 +193,17 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnDestroy,
}
reloadFiles(action: string) {
this.appStateService.getFiles(this.dossiersService.find(this.file.dossierId)).then(() => {
this.actionPerformed.emit(action);
});
this._filesService
.loadAll(this.file.dossierId)
.toPromise()
.then(() => {
this.actionPerformed.emit(action);
});
}
async toggleAnalysis() {
await this._fileActionService.toggleAnalysis(this.file).toPromise();
await this.appStateService.getFiles(this.dossiersService.find(this.file.dossierId));
await this._filesService.loadAll(this.file.dossierId).toPromise();
this.actionPerformed.emit(this.file?.excluded ? 'enable-analysis' : 'disable-analysis');
}

View File

@ -3,15 +3,15 @@ import { GenericService } from '@iqser/common-ui';
import { IMatchedDocument, ISearchInput, ISearchRequest, ISearchResponse } from '@red/domain';
import { Observable, of, zip } from 'rxjs';
import { mapTo, switchMap } from 'rxjs/operators';
import { AppStateService } from '@state/app-state.service';
import { DossiersService } from '@services/entity-services/dossiers.service';
import { FilesMapService } from '@services/entity-services/files-map.service';
import { FilesService } from '@services/entity-services/files.service';
@Injectable()
export class PlatformSearchService extends GenericService<ISearchResponse> {
constructor(
protected readonly _injector: Injector,
private readonly _appStateService: AppStateService,
private readonly _filesService: FilesService,
private readonly _dossiersService: DossiersService,
private readonly _filesMapService: FilesMapService,
) {
@ -47,7 +47,6 @@ export class PlatformSearchService extends GenericService<ISearchResponse> {
}
private _loadFilesFor$(dossierIds: string[]) {
const dossiers = dossierIds.map(dossierId => this._dossiersService.find(dossierId));
return zip(...dossiers.map(dossier => this._appStateService.getFiles(dossier)));
return zip(...dossierIds.map(dossierId => this._filesService.loadAll(dossierId)));
}
}

View File

@ -7,15 +7,18 @@
class="member"
>
<redaction-initials-avatar [user]="userId" color="gray" size="large"></redaction-initials-avatar>
<div *ngIf="canRemoveMember(userId)" class="remove">
<mat-icon svgIcon="iqser:close"></mat-icon>
</div>
</div>
<div *ngIf="overflowCount && !expandedTeam" [class.large-spacing]="largeSpacing" class="member pointer">
<div (click)="toggleExpandedTeam()" class="oval large white-dark">+{{ overflowCount }}</div>
</div>
<iqser-circle-button
(action)="openAssignDossierMembersDialog.emit()"
(action)="openEditDossierDialog()"
*ngIf="currentUser.isManager && canAdd"
[class.large-spacing]="largeSpacing"
[size]="32"
@ -26,4 +29,5 @@
iqserHelpMode="edit-dossier-member"
></iqser-circle-button>
</div>
<div (click)="toggleExpandedTeam()" *ngIf="expandedTeam" class="all-caps-label see-less pointer" translate="dossier-details.see-less"></div>

View File

@ -1,6 +1,7 @@
import { Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core';
import { CircleButtonTypes, List } from '@iqser/common-ui';
import { UserService } from '@services/user.service';
import { DossiersDialogService } from '../../../dossier/services/dossiers-dialog.service';
@Component({
selector: 'redaction-team-members',
@ -13,18 +14,18 @@ export class TeamMembersComponent {
@Input() memberIds: List;
@Input() perLine: number;
@Input() dossierId: string;
@Input() canAdd = true;
@Input() largeSpacing = false;
@Input() canRemove = false;
@Input() unremovableMembers: string[] = [];
@Output() openAssignDossierMembersDialog = new EventEmitter();
@Output() remove = new EventEmitter<string>();
@ViewChild('container', { static: true }) container: ElementRef;
@ViewChild('container', { static: true }) readonly container: ElementRef;
expandedTeam = false;
constructor(private readonly _userService: UserService) {}
constructor(private readonly _userService: UserService, private readonly _dialogService: DossiersDialogService) {}
get maxTeamMembersBeforeExpand(): number {
return this.perLine - (this.canAdd ? 1 : 0);
@ -45,4 +46,9 @@ export class TeamMembersComponent {
canRemoveMember(userId: string) {
return this.canRemove && this.unremovableMembers.indexOf(userId) === -1;
}
openEditDossierDialog(): void {
const data = { dossierId: this.dossierId, section: 'members' };
this._dialogService.openDialog('editDossier', null, data);
}
}

View File

@ -1,6 +1,5 @@
import { ApplicationRef, Injectable, Injector, OnDestroy } from '@angular/core';
import { FileUploadModel } from '../model/file-upload.model';
import { AppStateService } from '@state/app-state.service';
import { HttpErrorResponse, HttpEventType } from '@angular/common/http';
import { interval, Subject, Subscription } from 'rxjs';
import { ConfigService } from '@services/config.service';
@ -11,6 +10,7 @@ import { isCsv } from '@utils/file-drop-utils';
import { ErrorMessageService, GenericService, HeadersConfiguration, RequiredParam, Validate } from '@iqser/common-ui';
import { FilesMapService } from '@services/entity-services/files-map.service';
import { switchMap, tap, throttleTime } from 'rxjs/operators';
import { FilesService } from '@services/entity-services/files.service';
export interface ActiveUpload {
subscription: Subscription;
@ -30,7 +30,7 @@ export class FileUploadService extends GenericService<IFileUploadResult> impleme
private readonly _subscriptions = new Subscription();
constructor(
private readonly _appStateService: AppStateService,
private readonly _filesService: FilesService,
private readonly _filesMapService: FilesMapService,
private readonly _applicationRef: ApplicationRef,
private readonly _translateService: TranslateService,
@ -42,7 +42,7 @@ export class FileUploadService extends GenericService<IFileUploadResult> impleme
super(_injector, 'upload');
const fileFetch$ = this._fetchFiles$.pipe(
throttleTime(1500),
switchMap(dossierId => this._appStateService.reloadDossierFiles(dossierId)),
switchMap(dossierId => this._filesService.loadAll(dossierId)),
);
this._subscriptions.add(fileFetch$.subscribe());
const interval$ = interval(2500).pipe(tap(() => this._handleUploads()));

View File

@ -1,5 +1,4 @@
import { Injectable } from '@angular/core';
import { FilesService } from '@services/entity-services/files.service';
import { BehaviorSubject, Observable, Subject } from 'rxjs';
import { File } from '@red/domain';
import { filter, startWith } from 'rxjs/operators';
@ -10,8 +9,6 @@ export class FilesMapService {
private readonly _entityChanged$ = new Subject<File>();
private readonly _map = new Map<string, BehaviorSubject<File[]>>();
constructor(private readonly _filesService: FilesService) {}
get$(dossierId: string) {
if (!this._map.has(dossierId)) {
this._map.set(dossierId, new BehaviorSubject<File[]>([]));

View File

@ -1,26 +1,47 @@
import { Injectable, Injector } from '@angular/core';
import { EntitiesService, List, RequiredParam, Validate } from '@iqser/common-ui';
import { EntitiesService, List, mapEach, RequiredParam, Validate } from '@iqser/common-ui';
import { File, IFile } from '@red/domain';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { UserService } from '../user.service';
import { FileAttributesService } from '@services/entity-services/file-attributes.service';
import { FilesMapService } from '@services/entity-services/files-map.service';
import { tap } from 'rxjs/operators';
@Injectable({
providedIn: 'root',
})
export class FilesService extends EntitiesService<File, IFile> {
constructor(protected readonly _injector: Injector, private readonly _userService: UserService) {
constructor(
protected readonly _injector: Injector,
private readonly _userService: UserService,
private readonly _fileAttributesService: FileAttributesService,
private readonly _filesMapService: FilesMapService,
) {
super(_injector, File, 'status');
}
fetch() {
this.get().pipe(map(files => files.map(file => new File(file, this._userService.getNameForId(file.currentReviewer)))));
loadAll(dossierId: string) {
const files$ = this.getFor(dossierId).pipe(mapEach(file => new File(file, this._userService.getNameForId(file.currentReviewer))));
return files$.pipe(tap(files => this._filesMapService.set(dossierId, files)));
}
getOne(dossierId: string, fileId: string): Observable<IFile> {
return super._getOne([dossierId, fileId]);
}
async reload(dossierId: string, fileId: string): Promise<File> {
const oldFile = this._filesMapService.get(dossierId, fileId);
if (!oldFile) {
return null;
}
const rawFile = await this.getOne(dossierId, fileId).toPromise();
const newFile = new File(rawFile, this._userService.getNameForId(rawFile.currentReviewer));
this._filesMapService.replace(newFile);
return newFile;
}
@Validate()
setUnderApprovalFor(@RequiredParam() body: List, @RequiredParam() dossierId: string, approverId: string) {
const url = `${this._defaultModelPath}/under-approval/${dossierId}/bulk`;

View File

@ -2,9 +2,7 @@ import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router';
import { AppStateService } from './app-state.service';
import { UserService } from '@services/user.service';
import { DossiersService } from '@services/entity-services/dossiers.service';
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
import { FilesMapService } from '@services/entity-services/files-map.service';
@Injectable({
providedIn: 'root',
@ -12,8 +10,6 @@ import { FilesMapService } from '@services/entity-services/files-map.service';
export class AppStateGuard implements CanActivate {
constructor(
private readonly _appStateService: AppStateService,
private readonly _dossiersService: DossiersService,
private readonly _filesMapService: FilesMapService,
private readonly _dossierTemplatesService: DossierTemplatesService,
private readonly _userService: UserService,
private readonly _router: Router,

View File

@ -1,17 +1,13 @@
import { Injectable } from '@angular/core';
import { Dictionary, Dossier, DossierTemplate, File, IColors } from '@red/domain';
import { Dictionary, DossierTemplate, IColors } from '@red/domain';
import { ActivationEnd, Router } from '@angular/router';
import { UserService } from '@services/user.service';
import { forkJoin, Observable, of } from 'rxjs';
import { catchError, map, tap } from 'rxjs/operators';
import { currentComponentRoute, FALLBACK_COLOR, hexToRgb } from '@utils/functions';
import { DossiersService } from '@services/entity-services/dossiers.service';
import { FilesService } from '@services/entity-services/files.service';
import { DictionaryService } from '@shared/services/dictionary.service';
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
import { FileAttributesService } from '@services/entity-services/file-attributes.service';
import { DossierStatsService } from '@services/entity-services/dossier-stats.service';
import { FilesMapService } from '@services/entity-services/files-map.service';
export interface AppState {
activeFileId?: string;
@ -27,14 +23,10 @@ export class AppStateService {
constructor(
private readonly _router: Router,
private readonly _userService: UserService,
private readonly _dossiersService: DossiersService,
private readonly _filesService: FilesService,
private readonly _dictionaryService: DictionaryService,
private readonly _dossierTemplatesService: DossierTemplatesService,
private readonly _dossierStatsService: DossierStatsService,
private readonly _fileAttributesService: FileAttributesService,
private readonly _filesMapService: FilesMapService,
) {
_router.events.pipe(currentComponentRoute).subscribe((event: ActivationEnd) => {
const fileId = event.snapshot.paramMap.get('fileId');
@ -96,37 +88,6 @@ export class AppStateService {
return data ? data : this._dictionaryData[dossierTemplateId]['default'];
}
async reloadFile(dossierId: string, fileId: string): Promise<File> {
const dossier = this._dossiersService.find(dossierId);
const oldFile = this._filesMapService.get(dossierId, fileId);
if (!oldFile || !dossier) {
return null;
}
const iFile = await this._filesService.getOne(dossierId, fileId).toPromise();
const newFile = new File(
iFile,
this._userService.getNameForId(iFile.currentReviewer),
this._fileAttributesService.getFileAttributeConfig(dossier.dossierTemplateId),
);
this._filesMapService.replace(newFile);
return newFile;
}
async getFiles(dossier: Dossier) {
const files = await this._filesService.getFor(dossier.id).toPromise();
await this._dossierStatsService.getFor([dossier.id]).toPromise();
const fileAttributes = this._fileAttributesService.getFileAttributeConfig(dossier.dossierTemplateId);
const newFiles = files.map(iFile => new File(iFile, this._userService.getNameForId(iFile.currentReviewer), fileAttributes));
this._filesMapService.set(dossier.dossierId, newFiles);
return newFiles;
}
activateDictionary(dictionaryType: string) {
if (this._dossierTemplatesService.activeDossierTemplate) {
this._appState.activeDictionaryType = dictionaryType;
@ -142,12 +103,6 @@ export class AppStateService {
this._appState.activeDictionaryType = null;
}
async reloadDossierFiles(dossierId: string) {
if (dossierId) {
return this.getFiles(this._dossiersService.find(dossierId));
}
}
async refreshDossierTemplate(dossierTemplateId: string) {
const dossierTemplate = await this._dossierTemplatesService.get(dossierTemplateId).toPromise();

View File

@ -2,7 +2,7 @@ import { Entity } from '@iqser/common-ui';
import { StatusSorter } from '../shared';
import { isProcessingStatuses, ProcessingFileStatus, ProcessingFileStatuses, WorkflowFileStatus, WorkflowFileStatuses } from './types';
import { IFile } from './file';
import { FileAttributes, IFileAttributesConfig } from '../file-attributes';
import { FileAttributes } from '../file-attributes';
export class File extends Entity<IFile> implements IFile {
readonly added?: string;
@ -54,7 +54,7 @@ export class File extends Entity<IFile> implements IFile {
readonly canBeOpened: boolean;
readonly canBeOCRed: boolean;
constructor(file: IFile, readonly reviewerName: string, fileAttributesConfig?: IFileAttributesConfig) {
constructor(file: IFile, readonly reviewerName: string) {
super(file);
this.added = file.added;
this.allManualRedactionsApplied = !!file.allManualRedactionsApplied;
@ -106,17 +106,6 @@ export class File extends Entity<IFile> implements IFile {
this.canBeOpened = !this.isError && !this.isPending && this.numberOfAnalyses > 0;
this.canBeOCRed = !this.excluded && !this.lastOCRTime && (this.isUnassigned || this.isUnderReview || this.isUnderApproval);
if (fileAttributesConfig) {
const primary = fileAttributesConfig.fileAttributeConfigs?.find(c => c.primaryAttribute);
if (primary && file.fileAttributes?.attributeIdToValue) {
this.primaryAttribute = file.fileAttributes?.attributeIdToValue[primary.id];
}
if (!this.primaryAttribute) {
// Fallback here
this.primaryAttribute = '-';
}
}
if (!this.fileAttributes || !this.fileAttributes.attributeIdToValue) {
this.fileAttributes = { attributeIdToValue: {} };
}