diff --git a/apps/red-ui/src/app/app.component.html b/apps/red-ui/src/app/app.component.html
index ff64625af..20a8fecb2 100644
--- a/apps/red-ui/src/app/app.component.html
+++ b/apps/red-ui/src/app/app.component.html
@@ -1,3 +1,4 @@
+
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.ts b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.ts
index 9aed7b89f..19e8e7e71 100644
--- a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.ts
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.ts
@@ -15,18 +15,19 @@ import { FileDropOverlayService } from '@upload-download/services/file-drop-over
import { FileUploadModel } from '@upload-download/model/file-upload.model';
import { FileUploadService } from '@upload-download/services/file-upload.service';
import { StatusOverlayService } from '@upload-download/services/status-overlay.service';
-import { Observable } from 'rxjs';
+import { Observable, Subscription } from 'rxjs';
import { filter, skip, switchMap, tap } from 'rxjs/operators';
import { convertFiles, Files, handleFileDrop } from '@utils/index';
import {
CircleButtonTypes,
+ CustomError,
DefaultListingServices,
+ ErrorService,
ListingComponent,
ListingModes,
LoadingService,
NestedFilter,
OnAttach,
- OnDetach,
TableColumnConfig,
TableComponent,
WorkflowConfig,
@@ -52,7 +53,7 @@ import { DossierStatsService } from '@services/entity-services/dossier-stats.ser
providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => DossierOverviewScreenComponent) }],
changeDetection: ChangeDetectionStrategy.OnPush,
})
-export class DossierOverviewScreenComponent extends ListingComponent implements OnInit, OnDestroy, OnDetach, OnAttach {
+export class DossierOverviewScreenComponent extends ListingComponent implements OnInit, OnDestroy, OnAttach {
readonly listingModes = ListingModes;
readonly circleButtonTypes = CircleButtonTypes;
readonly tableHeaderLabel = _('dossier-overview.table-header.title');
@@ -73,6 +74,7 @@ export class DossierOverviewScreenComponent extends ListingComponent imple
@ViewChild('fileInput', { static: true }) private readonly _fileInput: ElementRef;
@ViewChild(TableComponent) private readonly _tableComponent: TableComponent;
private _fileAttributeConfigs: IFileAttributeConfig[];
+ private readonly _removableSubscriptions = new Subscription();
constructor(
protected readonly _injector: Injector,
@@ -92,6 +94,7 @@ export class DossierOverviewScreenComponent extends ListingComponent imple
readonly configService: ConfigService,
private readonly _userPreferenceService: UserPreferenceService,
private readonly _fileMapService: FilesMapService,
+ private readonly _errorService: ErrorService,
activatedRoute: ActivatedRoute,
) {
super(_injector);
@@ -165,11 +168,10 @@ export class DossierOverviewScreenComponent extends ListingComponent imple
ngOnAttach() {
this._fileDropOverlayService.initFileDropHandling(this.dossierId);
+ this._setRemovableSubscriptions();
this._tableComponent?.scrollToLastIndex();
}
- ngOnDetach() {}
-
forceReanalysisAction($event: LongPressEvent) {
this.analysisForced = !$event.touchEnd && this._userPreferenceService.areDevFeaturesEnabled;
}
@@ -191,6 +193,21 @@ export class DossierOverviewScreenComponent extends ListingComponent imple
(this._fileInput as any).nativeElement.value = null;
}
+ private _setRemovableSubscriptions(): void {
+ this._removableSubscriptions.add(
+ this._dossiersService
+ .getEntityDeleted$(this.dossierId)
+ .pipe(tap(() => this._handleDeletedDossier()))
+ .subscribe(),
+ );
+ }
+
+ private _handleDeletedDossier(): void {
+ this._errorService.set(
+ new CustomError(_('error.deleted-entity.dossier.label'), _('error.deleted-entity.dossier.action'), 'iqser:expand'),
+ );
+ }
+
private _updateFileAttributes(): void {
this._fileAttributeConfigs =
this._fileAttributesService.getFileAttributeConfig(this.currentDossier.dossierTemplateId)?.fileAttributeConfigs || [];
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 79b8fd977..d70a2ae00 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,11 +1,11 @@
-import { ChangeDetectionStrategy, Component, forwardRef, Injector, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';
+import { ChangeDetectionStrategy, Component, forwardRef, Injector, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { Dossier } from '@red/domain';
import { UserService } from '@services/user.service';
import { PermissionsService } from '@services/permissions.service';
import { TranslateChartService } from '@services/translate-chart.service';
import { Router } from '@angular/router';
import { DossiersDialogService } from '../../../services/dossiers-dialog.service';
-import { DefaultListingServicesTmp, EntitiesService, ListingComponent, OnAttach, OnDetach, TableComponent } from '@iqser/common-ui';
+import { DefaultListingServicesTmp, EntitiesService, ListingComponent, OnAttach, TableComponent } from '@iqser/common-ui';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { ConfigService } from '../config.service';
import { DossiersService } from '@services/entity-services/dossiers.service';
@@ -23,7 +23,7 @@ import { tap } from 'rxjs/operators';
],
changeDetection: ChangeDetectionStrategy.OnPush,
})
-export class DossiersListingScreenComponent extends ListingComponent implements OnInit, OnDestroy, OnAttach, OnDetach {
+export class DossiersListingScreenComponent extends ListingComponent implements OnInit, OnAttach {
readonly currentUser = this._userService.currentUser;
readonly tableColumnConfigs = this._configService.tableConfig;
readonly tableHeaderLabel = _('dossier-listing.table-header.title');
@@ -59,14 +59,9 @@ export class DossiersListingScreenComponent extends ListingComponent im
}
ngOnAttach(): void {
- this.ngOnInit();
this._tableComponent?.scrollToLastIndex();
}
- ngOnDetach(): void {
- this.ngOnDestroy();
- }
-
openAddDossierDialog(): void {
this._dialogService.openDialog('addDossier', null, null, async (addResponse: { dossier: Dossier; addMembers: boolean }) => {
await this._router.navigate([addResponse.dossier.routerLink]);
diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts
index 445d22bbd..4ff4c076a 100644
--- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts
+++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts
@@ -5,7 +5,9 @@ import { PdfViewerComponent } from './components/pdf-viewer/pdf-viewer.component
import {
AutoUnsubscribe,
CircleButtonTypes,
+ CustomError,
Debounce,
+ ErrorService,
FilterService,
LoadingService,
OnAttach,
@@ -43,19 +45,12 @@ import { ViewModeService } from './services/view-mode.service';
import { MultiSelectService } from './services/multi-select.service';
import { DocumentInfoService } from './services/document-info.service';
import { ReanalysisService } from '../../../../services/reanalysis.service';
+import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import Annotation = Core.Annotations.Annotation;
import PDFNet = Core.PDFNet;
const ALL_HOTKEY_ARRAY = ['Escape', 'F', 'f', 'ArrowUp', 'ArrowDown'];
-function diff(first: readonly T[], second: readonly T[]): T[] {
- // symmetrical difference between two arrays
- const a = new Set(first);
- const b = new Set(second);
-
- return [...first.filter(x => !b.has(x)), ...second.filter(x => !a.has(x))];
-}
-
@Component({
templateUrl: './file-preview-screen.component.html',
styleUrls: ['./file-preview-screen.component.scss'],
@@ -108,6 +103,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
private readonly _filesMapService: FilesMapService,
private readonly _dossiersService: DossiersService,
private readonly _reanalysisService: ReanalysisService,
+ private readonly _errorService: ErrorService,
readonly excludedPagesService: ExcludedPagesService,
readonly viewModeService: ViewModeService,
readonly multiSelectService: MultiSelectService,
@@ -190,7 +186,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
ngOnDetach(): void {
this.displayPdfViewer = false;
- super.ngOnDestroy();
+ super.ngOnDetach();
this._changeDetectorRef.markForCheck();
}
@@ -529,10 +525,10 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
}
private _subscribeToFileUpdates(): void {
- this.addSubscription = timer(0, 5000)
+ this.addActiveScreenSubscription = timer(0, 5000)
.pipe(switchMap(() => this._filesService.reload(this.dossierId, this.fileId)))
.subscribe();
- this.addSubscription = this._filesMapService.fileReanalysed$
+ this.addActiveScreenSubscription = this._filesMapService.fileReanalysed$
.pipe(filter(file => file.fileId === this.fileId))
.subscribe(async file => {
if (file.lastProcessed !== this.fileData?.file.lastProcessed) {
@@ -541,6 +537,28 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
}
this._loadingService.stop();
});
+
+ this.addActiveScreenSubscription = this._dossiersService
+ .getEntityDeleted$(this.dossierId)
+ .pipe(tap(() => this._handleDeletedDossier()))
+ .subscribe();
+
+ this.addActiveScreenSubscription = this._filesMapService
+ .watchDeleted$(this.fileId)
+ .pipe(tap(() => this._handleDeletedFile()))
+ .subscribe();
+ }
+
+ private _handleDeletedDossier(): void {
+ this._errorService.set(
+ new CustomError(_('error.deleted-entity.file-dossier.label'), _('error.deleted-entity.file-dossier.action'), 'iqser:expand'),
+ );
+ }
+
+ private _handleDeletedFile(): void {
+ this._errorService.set(
+ new CustomError(_('error.deleted-entity.file.label'), _('error.deleted-entity.file.action'), 'iqser:expand'),
+ );
}
private async _loadFileData(file: File): Promise {
diff --git a/apps/red-ui/src/app/services/entity-services/files-map.service.ts b/apps/red-ui/src/app/services/entity-services/files-map.service.ts
index b861090da..9d04a9d99 100644
--- a/apps/red-ui/src/app/services/entity-services/files-map.service.ts
+++ b/apps/red-ui/src/app/services/entity-services/files-map.service.ts
@@ -7,6 +7,7 @@ import { filter, startWith } from 'rxjs/operators';
export class FilesMapService {
readonly fileReanalysed$ = new Subject();
private readonly _entityChanged$ = new Subject();
+ private readonly _entityDeleted$ = new Subject();
private readonly _map = new Map>();
get$(dossierId: string) {
@@ -39,6 +40,7 @@ export class FilesMapService {
const reanalysedEntities = [];
const changedEntities = [];
+ const deletedEntities = this.get(key).filter(oldEntity => !entities.find(newEntity => newEntity.id === oldEntity.id));
// Keep old object references for unchanged entities
const newEntities = entities.map(newEntity => {
@@ -67,6 +69,10 @@ export class FilesMapService {
for (const file of changedEntities) {
this._entityChanged$.next(file);
}
+
+ for (const file of deletedEntities) {
+ this._entityDeleted$.next(file);
+ }
}
replace(entity: File) {
@@ -83,4 +89,8 @@ export class FilesMapService {
startWith(this.get(key, entityId)),
);
}
+
+ watchDeleted$(entityId: string): Observable {
+ return this._entityDeleted$.pipe(filter(entity => entity.id === entityId));
+ }
}
diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json
index 510458983..fa8141da2 100644
--- a/apps/red-ui/src/assets/i18n/en.json
+++ b/apps/red-ui/src/assets/i18n/en.json
@@ -938,6 +938,20 @@
"unsaved-changes": "You have unsaved changes. Save or revert before changing the tab."
},
"error": {
+ "deleted-entity": {
+ "dossier": {
+ "action": "Back to overview",
+ "label": "This dossier has been deleted!"
+ },
+ "file-dossier": {
+ "action": "Back to overview",
+ "label": "The dossier of this file has been deleted!"
+ },
+ "file": {
+ "action": "Back to dossier",
+ "label": "This file has been deleted!"
+ }
+ },
"http": {
"generic": "Action failed with code {status}"
},