diff --git a/apps/red-ui/src/app/components/notifications/notifications.component.ts b/apps/red-ui/src/app/components/notifications/notifications.component.ts index 79b71d79c..5d807fcbd 100644 --- a/apps/red-ui/src/app/components/notifications/notifications.component.ts +++ b/apps/red-ui/src/app/components/notifications/notifications.component.ts @@ -1,7 +1,6 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { DatePipe } from '@shared/pipes/date.pipe'; -import { AppStateService } from '@state/app-state.service'; import { UserService } from '@services/user.service'; import { DossiersService } from '@services/entity-services/dossiers.service'; import { NotificationsService } from '@services/notifications.service'; @@ -33,7 +32,6 @@ export class NotificationsComponent extends AutoUnsubscribe implements OnInit { private readonly _translateService: TranslateService, private readonly _userService: UserService, private readonly _notificationsService: NotificationsService, - private readonly _appStateService: AppStateService, private readonly _dossiersService: DossiersService, private readonly _datePipe: DatePipe, ) { @@ -43,6 +41,14 @@ export class NotificationsComponent extends AutoUnsubscribe implements OnInit { this.hasUnreadNotifications$ = this._hasUnreadNotifications$; } + private get _hasUnreadNotifications$(): Observable { + return this.notifications$.pipe( + map(notifications => notifications.filter(n => !n.readDate).length > 0), + distinctUntilChanged(), + shareLast(), + ); + } + async ngOnInit(): Promise { await this._loadData(); @@ -54,14 +60,6 @@ export class NotificationsComponent extends AutoUnsubscribe implements OnInit { .subscribe(); } - private get _hasUnreadNotifications$(): Observable { - return this.notifications$.pipe( - map(notifications => notifications.filter(n => !n.readDate).length > 0), - distinctUntilChanged(), - shareLast(), - ); - } - async markRead($event, notifications: List = this._notifications$.getValue().map(n => n.id), isRead = true): Promise { $event.stopPropagation(); await this._notificationsService.toggleNotificationRead(notifications, isRead).toPromise(); diff --git a/apps/red-ui/src/app/guards/dossier-files-guard.ts b/apps/red-ui/src/app/guards/dossier-files-guard.ts index 61861a0a6..67d764cd8 100644 --- a/apps/red-ui/src/app/guards/dossier-files-guard.ts +++ b/apps/red-ui/src/app/guards/dossier-files-guard.ts @@ -3,7 +3,6 @@ import { ActivatedRouteSnapshot, CanActivate, CanDeactivate, Router, RouterState import { DossiersService } from '@services/entity-services/dossiers.service'; 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'; @@ -11,7 +10,6 @@ import { FilesService } from '@services/entity-services/files.service'; export class DossierFilesGuard implements CanActivate, CanDeactivate { constructor( private readonly _dossiersService: DossiersService, - private readonly _appStateService: AppStateService, private readonly _breadcrumbsService: BreadcrumbsService, private readonly _filesMapService: FilesMapService, private readonly _filesService: FilesService, diff --git a/apps/red-ui/src/app/guards/dossiers.guard.ts b/apps/red-ui/src/app/guards/dossiers.guard.ts index d9c5c9938..db39ed378 100644 --- a/apps/red-ui/src/app/guards/dossiers.guard.ts +++ b/apps/red-ui/src/app/guards/dossiers.guard.ts @@ -2,13 +2,11 @@ import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, CanActivate, CanDeactivate, Router, RouterStateSnapshot } from '@angular/router'; import { DossiersService } from '@services/entity-services/dossiers.service'; import { BreadcrumbsService } from '@services/breadcrumbs.service'; -import { AppStateService } from '@state/app-state.service'; @Injectable({ providedIn: 'root' }) export class DossiersGuard implements CanActivate, CanDeactivate { constructor( private readonly _dossiersService: DossiersService, - private readonly _appStateService: AppStateService, private readonly _breadcrumbsService: BreadcrumbsService, private readonly _router: Router, ) {} diff --git a/apps/red-ui/src/app/guards/file-preview.guard.ts b/apps/red-ui/src/app/guards/file-preview.guard.ts index 8672f0d5f..6d8fe5440 100644 --- a/apps/red-ui/src/app/guards/file-preview.guard.ts +++ b/apps/red-ui/src/app/guards/file-preview.guard.ts @@ -1,7 +1,6 @@ import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, CanActivate, CanDeactivate, Router, RouterStateSnapshot } from '@angular/router'; import { FilesMapService } from '@services/entity-services/files-map.service'; -import { AppStateService } from '@state/app-state.service'; import { DossiersService } from '@services/entity-services/dossiers.service'; import { BreadcrumbsService } from '@services/breadcrumbs.service'; import { pluck } from 'rxjs/operators'; @@ -11,7 +10,6 @@ export class FilePreviewGuard implements CanActivate, CanDeactivate { constructor( private readonly _filesMapService: FilesMapService, private readonly _dossiersService: DossiersService, - private readonly _appStateService: AppStateService, private readonly _breadcrumbsService: BreadcrumbsService, private readonly _router: Router, ) {} diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component.ts index bffaa60fe..c963908a1 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component.ts @@ -1,6 +1,5 @@ import { Component, Inject } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; -import { AppStateService } from '@state/app-state.service'; import { FileAttributeConfigTypes, IFileAttributeConfig } from '@red/domain'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { fileAttributeTypesTranslations } from '../../translations/file-attribute-types-translations'; @@ -19,7 +18,6 @@ export class AddEditFileAttributeDialogComponent extends BaseDialogComponent { translations = fileAttributeTypesTranslations; constructor( - private readonly _appStateService: AppStateService, private readonly _formBuilder: FormBuilder, public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) @@ -28,18 +26,6 @@ export class AddEditFileAttributeDialogComponent extends BaseDialogComponent { super(); } - private _getForm(fileAttribute: IFileAttributeConfig): FormGroup { - return this._formBuilder.group({ - label: [fileAttribute?.label, Validators.required], - csvColumnHeader: [fileAttribute?.csvColumnHeader], - type: [fileAttribute?.type || FileAttributeConfigTypes.TEXT, Validators.required], - readonly: [fileAttribute ? !fileAttribute.editable : false], - primaryAttribute: [fileAttribute?.primaryAttribute], - filterable: [fileAttribute?.filterable], - displayedInFileList: [fileAttribute?.displayedInFileList], - }); - } - get changed(): boolean { if (!this.fileAttribute) { return true; @@ -66,4 +52,16 @@ export class AddEditFileAttributeDialogComponent extends BaseDialogComponent { }; this.dialogRef.close(fileAttribute); } + + private _getForm(fileAttribute: IFileAttributeConfig): FormGroup { + return this._formBuilder.group({ + label: [fileAttribute?.label, Validators.required], + csvColumnHeader: [fileAttribute?.csvColumnHeader], + type: [fileAttribute?.type || FileAttributeConfigTypes.TEXT, Validators.required], + readonly: [fileAttribute ? !fileAttribute.editable : false], + primaryAttribute: [fileAttribute?.primaryAttribute], + filterable: [fileAttribute?.filterable], + displayedInFileList: [fileAttribute?.displayedInFileList], + }); + } } diff --git a/apps/red-ui/src/app/modules/admin/screens/dossier-attributes-listing/dossier-attributes-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/dossier-attributes-listing/dossier-attributes-listing-screen.component.ts index 5ad935999..66bb09192 100644 --- a/apps/red-ui/src/app/modules/admin/screens/dossier-attributes-listing/dossier-attributes-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/dossier-attributes-listing/dossier-attributes-listing-screen.component.ts @@ -8,7 +8,6 @@ import { LoadingService, TableColumnConfig, } from '@iqser/common-ui'; -import { AppStateService } from '@state/app-state.service'; import { AdminDialogService } from '../../services/admin-dialog.service'; import { DossierAttributesService } from '@shared/services/controller-wrappers/dossier-attributes.service'; import { dossierAttributeTypesTranslations } from '../../translations/dossier-attribute-types-translations'; @@ -40,7 +39,6 @@ export class DossierAttributesListingScreenComponent extends ListingComponent, diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/screen/dossiers-listing-screen.component.ts b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/screen/dossiers-listing-screen.component.ts index 873d0e2ea..8f2d96158 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/screen/dossiers-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/screen/dossiers-listing-screen.component.ts @@ -1,5 +1,4 @@ import { ChangeDetectionStrategy, Component, forwardRef, Injector, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core'; -import { AppStateService } from '@state/app-state.service'; import { Dossier } from '@red/domain'; import { UserService } from '@services/user.service'; import { PermissionsService } from '@services/permissions.service'; @@ -50,7 +49,6 @@ export class DossiersListingScreenComponent extends ListingComponent im protected readonly _injector: Injector, private readonly _userService: UserService, readonly permissionsService: PermissionsService, - private readonly _appStateService: AppStateService, private readonly _dossiersService: DossiersService, private readonly _dialogService: DossiersDialogService, private readonly _translateChartService: TranslateChartService, diff --git a/apps/red-ui/src/app/modules/dossier/services/annotation-actions.service.ts b/apps/red-ui/src/app/modules/dossier/services/annotation-actions.service.ts index acc4b9e9a..ba57ebe6f 100644 --- a/apps/red-ui/src/app/modules/dossier/services/annotation-actions.service.ts +++ b/apps/red-ui/src/app/modules/dossier/services/annotation-actions.service.ts @@ -11,7 +11,6 @@ import { BASE_HREF } from '../../../tokens'; import { UserService } from '@services/user.service'; import { Core, WebViewerInstance } from '@pdftron/webviewer'; import { Dossier, IAddRedactionRequest, ILegalBasisChangeRequest, IRectangle, IResizeRequest } from '@red/domain'; -import { AppStateService } from '../../../state/app-state.service'; import { toPosition } from '../utils/pdf-calculation.utils'; import { AnnotationDrawService } from './annotation-draw.service'; import { translateQuads } from '../../../utils'; @@ -22,7 +21,6 @@ export class AnnotationActionsService { constructor( @Inject(BASE_HREF) private readonly _baseHref: string, private readonly _ngZone: NgZone, - private readonly _appStateService: AppStateService, private readonly _userService: UserService, private readonly _permissionsService: PermissionsService, private readonly _manualAnnotationService: ManualAnnotationService, diff --git a/apps/red-ui/src/app/services/entity-services/file-management.service.ts b/apps/red-ui/src/app/services/entity-services/file-management.service.ts index fd254a2e1..cc5dfa525 100644 --- a/apps/red-ui/src/app/services/entity-services/file-management.service.ts +++ b/apps/red-ui/src/app/services/entity-services/file-management.service.ts @@ -2,29 +2,38 @@ import { GenericService, HeadersConfiguration, List, QueryParam, RequiredParam, import { Injectable, Injector } from '@angular/core'; import { HttpHeaders, HttpResponse } from '@angular/common/http'; import { Observable } from 'rxjs'; +import { switchMap } from 'rxjs/operators'; +import { FilesService } from '@services/entity-services/files.service'; +import { DossierStatsService } from '@services/entity-services/dossier-stats.service'; @Injectable({ providedIn: 'root', }) export class FileManagementService extends GenericService { - constructor(protected readonly _injector: Injector) { + constructor( + protected readonly _injector: Injector, + private readonly _filesService: FilesService, + private readonly _dossierStatsService: DossierStatsService, + ) { super(_injector, ''); } @Validate() - delete(@RequiredParam() body: List, @RequiredParam() dossierId: string) { - return super._post(body, `delete/${dossierId}`); + delete(@RequiredParam() fileIds: List, @RequiredParam() dossierId: string) { + return super._post(fileIds, `delete/${dossierId}`).pipe(switchMap(() => this._filesService.loadAll(dossierId))); } @Validate() hardDelete(@RequiredParam() dossierId: string, @RequiredParam() fileIds: List) { const queryParams = fileIds.map(id => ({ key: 'fileIds', value: id })); - return super.delete({}, `delete/hard-delete/${dossierId}`, queryParams); + return super + .delete({}, `delete/hard-delete/${dossierId}`, queryParams) + .pipe(switchMap(() => this._dossierStatsService.getFor([dossierId]))); } @Validate() restore(@RequiredParam() body: List, @RequiredParam() dossierId: string) { - return this._post(body, `delete/restore/${dossierId}`); + return this._post(body, `delete/restore/${dossierId}`).pipe(switchMap(() => this._filesService.loadAll(dossierId))); } downloadOriginalFile(dossierId: string, fileId: string, observe?: 'body', inline?: boolean, indicator?: string): Observable; diff --git a/apps/red-ui/src/app/services/entity-services/files.service.ts b/apps/red-ui/src/app/services/entity-services/files.service.ts index 55e31a480..24ae31d60 100644 --- a/apps/red-ui/src/app/services/entity-services/files.service.ts +++ b/apps/red-ui/src/app/services/entity-services/files.service.ts @@ -3,9 +3,10 @@ import { EntitiesService, List, mapEach, RequiredParam, Validate } from '@iqser/ import { File, IFile } from '@red/domain'; import { Observable } from 'rxjs'; 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'; +import { map, mapTo, switchMap, tap } from 'rxjs/operators'; +import { DossierStatsService } from '@services/entity-services/dossier-stats.service'; + @Injectable({ providedIn: 'root', @@ -14,38 +15,31 @@ export class FilesService extends EntitiesService { constructor( protected readonly _injector: Injector, private readonly _userService: UserService, - private readonly _fileAttributesService: FileAttributesService, private readonly _filesMapService: FilesMapService, + private readonly _dossierStatsService: DossierStatsService, ) { super(_injector, File, 'status'); } + /** Reload dossier files + stats. */ 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))); + const loadStats$ = files$.pipe(switchMap(files => this._dossierStatsService.getFor([dossierId]).pipe(mapTo(files)))); + return loadStats$.pipe(tap(files => this._filesMapService.set(dossierId, files))); } - getOne(dossierId: string, fileId: string): Observable { - return super._getOne([dossierId, fileId]); - } - - async reload(dossierId: string, fileId: string): Promise { - 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; + reload(dossierId: string, fileId: string): Observable { + return super._getOne([dossierId, fileId]).pipe( + map(file => new File(file, this._userService.getNameForId(file.currentReviewer))), + switchMap(file => this._dossierStatsService.getFor([dossierId]).pipe(mapTo(file))), + tap(file => this._filesMapService.replace(file)), + ); } @Validate() setUnderApprovalFor(@RequiredParam() fileIds: List, @RequiredParam() dossierId: string, approverId: string) { const url = `${this._defaultModelPath}/under-approval/${dossierId}/bulk`; - return this._post(fileIds, url, [{ key: 'approverId', value: approverId }]); + return this._post(fileIds, url, [{ key: 'approverId', value: approverId }]).pipe(switchMap(() => this.loadAll(dossierId))); } /** @@ -54,7 +48,9 @@ export class FilesService extends EntitiesService { @Validate() setReviewerFor(@RequiredParam() filesIds: List, @RequiredParam() dossierId: string, reviewerId: string) { const url = `${this._defaultModelPath}/set-reviewer/${dossierId}/bulk`; - return this._post(filesIds, url, [{ key: 'reviewerId', value: reviewerId }]); + return this._post(filesIds, url, [{ key: 'reviewerId', value: reviewerId }]).pipe( + switchMap(() => this.loadAll(dossierId)), + ); } /** @@ -62,7 +58,9 @@ export class FilesService extends EntitiesService { */ @Validate() setApprovedFor(@RequiredParam() filesIds: List, @RequiredParam() dossierId: string) { - return this._post(filesIds, `${this._defaultModelPath}/approved/${dossierId}/bulk`); + return this._post(filesIds, `${this._defaultModelPath}/approved/${dossierId}/bulk`).pipe( + switchMap(() => this.loadAll(dossierId)), + ); } /** @@ -70,7 +68,9 @@ export class FilesService extends EntitiesService { */ @Validate() setUnderReviewFor(@RequiredParam() filesIds: List, @RequiredParam() dossierId: string) { - return this._post(filesIds, `${this._defaultModelPath}/under-review/${dossierId}/bulk`); + return this._post(filesIds, `${this._defaultModelPath}/under-review/${dossierId}/bulk`).pipe( + switchMap(() => this.loadAll(dossierId)), + ); } /** diff --git a/apps/red-ui/src/app/services/reanalysis.service.ts b/apps/red-ui/src/app/services/reanalysis.service.ts index d08bfdfd6..1defc5008 100644 --- a/apps/red-ui/src/app/services/reanalysis.service.ts +++ b/apps/red-ui/src/app/services/reanalysis.service.ts @@ -1,12 +1,14 @@ import { Injectable, Injector } from '@angular/core'; import { GenericService, List, QueryParam, RequiredParam, Validate } from '@iqser/common-ui'; import { IPageExclusionRequest } from '@red/domain'; +import { switchMap, switchMapTo } from 'rxjs/operators'; +import { FilesService } from './entity-services/files.service'; @Injectable({ providedIn: 'root', }) export class ReanalysisService extends GenericService { - constructor(protected readonly _injector: Injector) { + constructor(protected readonly _injector: Injector, private readonly _filesService: FilesService) { super(_injector, ''); } @@ -37,12 +39,14 @@ export class ReanalysisService extends GenericService { queryParams.push({ key: 'excluded', value: excluded }); } - return this._post({}, `toggle-analysis/${dossierId}/${fileId}`, queryParams); + return this._post({}, `toggle-analysis/${dossierId}/${fileId}`, queryParams).pipe( + switchMap(() => this._filesService.loadAll(dossierId)), + ); } @Validate() ocrFiles(@RequiredParam() body: List, @RequiredParam() dossierId: string) { - return this._post(body, `ocr/reanalyze/${dossierId}/bulk`); + return this._post(body, `ocr/reanalyze/${dossierId}/bulk`).pipe(switchMap(() => this._filesService.loadAll(dossierId))); } @Validate() @@ -52,6 +56,6 @@ export class ReanalysisService extends GenericService { queryParams.push({ key: 'force', value: force }); } - return this._post({}, `reanalyze/${dossierId}`, queryParams); + return this._post({}, `reanalyze/${dossierId}`, queryParams).pipe(switchMapTo(this._filesService.loadAll(dossierId))); } }