RED-4361: Background refresh archive

This commit is contained in:
Adina Țeudan 2022-06-24 17:44:51 +03:00
parent 6b2a9e1eb4
commit e2d3c99f0c
6 changed files with 106 additions and 69 deletions

View File

@ -2,6 +2,7 @@ import { Component, ViewContainerRef } from '@angular/core';
import { RouterHistoryService } from '@services/router-history.service';
import { UserService } from '@services/user.service';
import { REDDocumentViewer } from './modules/pdf-viewer/services/document-viewer.service';
import { DossiersChangesService } from '@services/dossiers/dossier-changes.service';
@Component({
selector: 'redaction-root',
@ -16,5 +17,11 @@ export class AppComponent {
private readonly _routerHistoryService: RouterHistoryService,
private readonly _userService: UserService,
readonly documentViewer: REDDocumentViewer,
) {}
private readonly _dossierChangesService: DossiersChangesService,
) {
// TODO: Find a better place to initialize dossiers refresh
if (_userService.currentUser?.isUser) {
_dossierChangesService.initializeRefresh();
}
}
}

View File

@ -2,7 +2,6 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { UserService } from '@services/user.service';
import { DashboardStatsService } from '@services/dossier-templates/dashboard-stats.service';
import { UserPreferenceService } from '@services/user-preference.service';
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
@Component({
selector: 'redaction-dashboard-screen',
@ -18,10 +17,7 @@ export class DashboardScreenComponent implements OnInit {
private readonly _userService: UserService,
private readonly _dashboardStatsService: DashboardStatsService,
private readonly _userPreferenceService: UserPreferenceService,
private readonly _activeDossiersService: ActiveDossiersService,
) {
_activeDossiersService.initializeRefresh();
}
) {}
async ngOnInit(): Promise<void> {
await this._userPreferenceService.saveLastDossierTemplate(null);

View File

@ -1,35 +1,12 @@
import { Injectable, Injector } from '@angular/core';
import { CHANGED_CHECK_INTERVAL } from '@utils/constants';
import { DossiersService } from './dossiers.service';
import { Observable, timer } from 'rxjs';
import { switchMap, tap } from 'rxjs/operators';
import { Dossier, DOSSIERS_ROUTE } from '@red/domain';
import { DOSSIERS_ROUTE } from '@red/domain';
@Injectable({
providedIn: 'root',
})
export class ActiveDossiersService extends DossiersService {
private _initializedRefresh = false;
constructor(protected readonly _injector: Injector) {
super(_injector, 'dossier', DOSSIERS_ROUTE);
}
initializeRefresh() {
if (this._initializedRefresh) {
return;
}
this._initializedRefresh = true;
timer(CHANGED_CHECK_INTERVAL, CHANGED_CHECK_INTERVAL)
.pipe(
switchMap(() => this.loadOnlyChanged()),
tap(changes => this._emitFileChanges(changes)),
)
.subscribe();
}
loadAll(): Observable<Dossier[]> {
this.initializeRefresh();
return super.loadAll();
}
}

View File

@ -0,0 +1,88 @@
import { GenericService, List, QueryParam } from '@iqser/common-ui';
import { Dossier, DossierStats, IDossierChanges } from '@red/domain';
import { forkJoin, Observable, of, throwError, timer } from 'rxjs';
import { catchError, filter, map, switchMap, take, tap } from 'rxjs/operators';
import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http';
import { NGXLogger } from 'ngx-logger';
import { ActiveDossiersService } from './active-dossiers.service';
import { ArchivedDossiersService } from './archived-dossiers.service';
import { Injectable, Injector } from '@angular/core';
import { DossierStatsService } from './dossier-stats.service';
import { DashboardStatsService } from '../dossier-templates/dashboard-stats.service';
import { CHANGED_CHECK_INTERVAL } from '@utils/constants';
@Injectable({ providedIn: 'root' })
export class DossiersChangesService extends GenericService<Dossier> {
private _initializedRefresh = false;
private readonly _activeDossiersService: ActiveDossiersService = this._injector.get(ActiveDossiersService);
private readonly _archivedDossiersService: ArchivedDossiersService = this._injector.get(ArchivedDossiersService);
protected constructor(
protected readonly _injector: Injector,
private readonly _dossierStatsService: DossierStatsService,
private readonly _dashboardStatsService: DashboardStatsService,
private readonly _logger: NGXLogger,
) {
super(_injector, 'dossier');
}
loadOnlyChanged(): Observable<IDossierChanges> {
const removeIfNotFound = (id: string) =>
catchError((error: HttpErrorResponse) => {
if (error.status === HttpStatusCode.NotFound) {
this._activeDossiersService.remove(id);
this._archivedDossiersService.remove(id);
return of([]);
}
return throwError(() => error);
});
const load = (changes: IDossierChanges) =>
changes.map(change => this._load(change.dossierId).pipe(removeIfNotFound(change.dossierId)));
return this.hasChangesDetails$().pipe(
tap(changes => this._logger.info('[CHANGES] ', changes)),
switchMap(dossierChanges =>
forkJoin([...load(dossierChanges), this._dashboardStatsService.loadAll().pipe(take(1))]).pipe(map(() => dossierChanges)),
),
tap(() => this._updateLastChanged()),
);
}
hasChangesDetails$(): Observable<IDossierChanges> {
const body = { value: this._lastCheckedForChanges.get('root') ?? '0' };
return this._post<IDossierChanges>(body, `${this._defaultModelPath}/changes/details`).pipe(filter(changes => changes.length > 0));
}
initializeRefresh() {
if (this._initializedRefresh) {
return;
}
this._initializedRefresh = true;
timer(CHANGED_CHECK_INTERVAL, CHANGED_CHECK_INTERVAL)
.pipe(
switchMap(() => this.loadOnlyChanged()),
tap(changes => {
this._activeDossiersService.emitFileChanges(changes);
this._archivedDossiersService.emitFileChanges(changes);
}),
)
.subscribe();
}
private _load(id: string): Observable<DossierStats[]> {
const queryParams: List<QueryParam> = [{ key: 'includeArchived', value: true }];
return super._getOne([id], this._defaultModelPath, queryParams).pipe(
map(entity => new Dossier(entity)),
switchMap((dossier: Dossier) => {
if (dossier.isArchived) {
this._activeDossiersService.remove(dossier.id);
return this._archivedDossiersService.updateDossier(dossier);
}
this._archivedDossiersService.remove(dossier.id);
return this._activeDossiersService.updateDossier(dossier);
}),
);
}
}

View File

@ -1,7 +1,7 @@
import { EntitiesService, List, mapEach, QueryParam, RequiredParam, Toaster, Validate } from '@iqser/common-ui';
import { EntitiesService, mapEach, RequiredParam, Toaster, Validate } from '@iqser/common-ui';
import { Dossier, DossierStats, IDossier, IDossierChanges, IDossierRequest } from '@red/domain';
import { forkJoin, Observable, of, Subject, throwError } from 'rxjs';
import { catchError, filter, map, switchMap, take, tap } from 'rxjs/operators';
import { Observable, of, Subject } from 'rxjs';
import { catchError, map, switchMap, tap } from 'rxjs/operators';
import { Injector } from '@angular/core';
import { DossierStatsService } from './dossier-stats.service';
import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http';
@ -36,28 +36,6 @@ export abstract class DossiersService extends EntitiesService<Dossier, IDossier>
);
}
loadOnlyChanged(): Observable<IDossierChanges> {
const removeIfNotFound = (id: string) =>
catchError((error: HttpErrorResponse) => {
if (error.status === HttpStatusCode.NotFound) {
this.remove(id);
return of([]);
}
return throwError(() => error);
});
const load = (changes: IDossierChanges) =>
changes.map(change => this._load(change.dossierId).pipe(removeIfNotFound(change.dossierId)));
return this.hasChangesDetails$().pipe(
tap(changes => this._logger.info('[CHANGES] ', changes)),
switchMap(dossierChanges =>
forkJoin([...load(dossierChanges), this._dashboardStatsService.loadAll().pipe(take(1))]).pipe(map(() => dossierChanges)),
),
tap(() => this._updateLastChanged()),
);
}
loadAll(): Observable<Dossier[]> {
const dossierIds = (dossiers: Dossier[]) => dossiers.map(d => d.id);
return this.getAll().pipe(
@ -69,21 +47,12 @@ export abstract class DossiersService extends EntitiesService<Dossier, IDossier>
);
}
hasChangesDetails$(): Observable<IDossierChanges> {
const body = { value: this._lastCheckedForChanges.get('root') ?? '0' };
return this._post<IDossierChanges>(body, `${this._defaultModelPath}/changes/details`).pipe(filter(changes => changes.length > 0));
updateDossier(dossier: Dossier): Observable<DossierStats[]> {
this.replace(dossier);
return this._dossierStatsService.getFor([dossier.id]);
}
protected _emitFileChanges(dossierChanges: IDossierChanges): void {
emitFileChanges(dossierChanges: IDossierChanges): void {
dossierChanges.filter(change => change.fileChanges).forEach(change => this.dossierFileChanges$.next(change.dossierId));
}
private _load(id: string): Observable<DossierStats[]> {
const queryParams: List<QueryParam> = [{ key: 'includeArchived', value: this._path === 'archived-dossiers' }];
return super._getOne([id], this._defaultModelPath, queryParams).pipe(
map(entity => new Dossier(entity)),
tap(dossier => this.replace(dossier)),
switchMap(dossier => this._dossierStatsService.getFor([dossier.dossierId])),
);
}
}

View File

@ -53,7 +53,7 @@ export function configurationInitializer(
}),
switchMap(() => languageService.chooseAndSetInitialLanguage()),
tap(() => userService.initialize()),
tap(() => firstValueFrom(licenseService.loadLicense())),
switchMap(() => licenseService.loadLicense()),
take(1),
);
return () => firstValueFrom(setup);