Handle deleted entities

This commit is contained in:
Adina Țeudan 2022-01-13 00:21:25 +02:00
parent 72504dfebc
commit c400e875f9
6 changed files with 79 additions and 24 deletions

View File

@ -1,3 +1,4 @@
<router-outlet></router-outlet>
<iqser-full-page-loading-indicator></iqser-full-page-loading-indicator>
<iqser-connection-status></iqser-connection-status>
<iqser-full-page-error></iqser-full-page-error>

View File

@ -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<File> implements OnInit, OnDestroy, OnDetach, OnAttach {
export class DossierOverviewScreenComponent extends ListingComponent<File> 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<File> imple
@ViewChild('fileInput', { static: true }) private readonly _fileInput: ElementRef;
@ViewChild(TableComponent) private readonly _tableComponent: TableComponent<Dossier>;
private _fileAttributeConfigs: IFileAttributeConfig[];
private readonly _removableSubscriptions = new Subscription();
constructor(
protected readonly _injector: Injector,
@ -92,6 +94,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<File> 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<File> 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<File> 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 || [];

View File

@ -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<Dossier> implements OnInit, OnDestroy, OnAttach, OnDetach {
export class DossiersListingScreenComponent extends ListingComponent<Dossier> 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<Dossier> 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]);

View File

@ -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<T>(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<void | boolean> {

View File

@ -7,6 +7,7 @@ import { filter, startWith } from 'rxjs/operators';
export class FilesMapService {
readonly fileReanalysed$ = new Subject<File>();
private readonly _entityChanged$ = new Subject<File>();
private readonly _entityDeleted$ = new Subject<File>();
private readonly _map = new Map<string, BehaviorSubject<File[]>>();
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<File> {
return this._entityDeleted$.pipe(filter(entity => entity.id === entityId));
}
}

View File

@ -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}"
},