add dossier stats
This commit is contained in:
parent
41bc7a0055
commit
1bbf76f1b7
@ -71,7 +71,7 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti
|
||||
dossierTemplateId: [
|
||||
{
|
||||
value: this.dossier.dossierTemplateId,
|
||||
disabled: this.dossier.hasFiles,
|
||||
disabled: this.dossier.stats.hasFiles,
|
||||
},
|
||||
Validators.required,
|
||||
],
|
||||
|
||||
@ -1,17 +1,19 @@
|
||||
<div>
|
||||
<mat-icon svgIcon="iqser:document"></mat-icon>
|
||||
<span>{{ 'dossier-overview.dossier-details.stats.documents' | translate: { count: dossier.files.length } }}</span>
|
||||
</div>
|
||||
<ng-container *ngIf="dossier.stats$ | async as stats">
|
||||
<div>
|
||||
<mat-icon svgIcon="iqser:document"></mat-icon>
|
||||
<span>{{ 'dossier-overview.dossier-details.stats.documents' | translate: { count: stats.numberOfFiles } }}</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<mat-icon svgIcon="red:user"></mat-icon>
|
||||
<span>{{ 'dossier-overview.dossier-details.stats.people' | translate: { count: dossier.memberIds.length } }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<mat-icon svgIcon="red:user"></mat-icon>
|
||||
<span>{{ 'dossier-overview.dossier-details.stats.people' | translate: { count: dossier.memberIds.length } }}</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<mat-icon svgIcon="iqser:pages"></mat-icon>
|
||||
<span>{{ 'dossier-overview.dossier-details.stats.analysed-pages' | translate: { count: dossier.totalNumberOfPages | number } }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<mat-icon svgIcon="iqser:pages"></mat-icon>
|
||||
<span>{{ 'dossier-overview.dossier-details.stats.analysed-pages' | translate: { count: stats.numberOfPages | number } }}</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<div *ngIf="dossier.date | date: 'd MMM. yyyy' as date">
|
||||
<mat-icon svgIcon="red:calendar"></mat-icon>
|
||||
|
||||
@ -38,33 +38,35 @@
|
||||
></redaction-team-members>
|
||||
</div>
|
||||
|
||||
<div *ngIf="dossier.hasFiles" class="mt-24">
|
||||
<redaction-simple-doughnut-chart
|
||||
[config]="calculateChartConfig(dossier)"
|
||||
[radius]="63"
|
||||
[strokeWidth]="15"
|
||||
[subtitle]="'dossier-overview.dossier-details.charts.documents-in-dossier' | translate"
|
||||
direction="row"
|
||||
></redaction-simple-doughnut-chart>
|
||||
</div>
|
||||
|
||||
<div *ngIf="dossier.hasFiles && needsWorkFilters$ | async as filters" class="mt-24 legend pb-32">
|
||||
<div
|
||||
(click)="filterService.toggleFilter('needsWorkFilters', filter.id)"
|
||||
*ngFor="let filter of filters"
|
||||
[class.active]="filter.checked"
|
||||
>
|
||||
<redaction-type-filter [filter]="filter"></redaction-type-filter>
|
||||
<ng-container *ngIf="dossier.stats$ | async as stats">
|
||||
<div *ngIf="stats.hasFiles" class="mt-24">
|
||||
<redaction-simple-doughnut-chart
|
||||
[config]="calculateChartConfig(dossier)"
|
||||
[radius]="63"
|
||||
[strokeWidth]="15"
|
||||
[subtitle]="'dossier-overview.dossier-details.charts.documents-in-dossier' | translate"
|
||||
direction="row"
|
||||
></redaction-simple-doughnut-chart>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div [class.mt-24]="!dossier.hasFiles" class="pb-32">
|
||||
<redaction-dossier-details-stats
|
||||
(openDossierDictionaryDialog)="openDossierDictionaryDialog.emit()"
|
||||
[dossierAttributes]="dossierAttributes"
|
||||
[dossier]="dossier"
|
||||
></redaction-dossier-details-stats>
|
||||
</div>
|
||||
<div *ngIf="stats.hasFiles && needsWorkFilters$ | async as filters" class="mt-24 legend pb-32">
|
||||
<div
|
||||
(click)="filterService.toggleFilter('needsWorkFilters', filter.id)"
|
||||
*ngFor="let filter of filters"
|
||||
[class.active]="filter.checked"
|
||||
>
|
||||
<redaction-type-filter [filter]="filter"></redaction-type-filter>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div [class.mt-24]="!stats.hasFiles" class="pb-32">
|
||||
<redaction-dossier-details-stats
|
||||
(openDossierDictionaryDialog)="openDossierDictionaryDialog.emit()"
|
||||
[dossierAttributes]="dossierAttributes"
|
||||
[dossier]="dossier"
|
||||
></redaction-dossier-details-stats>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<div *ngIf="dossier.description as description" class="pb-32">
|
||||
<div class="heading" translate="dossier-overview.dossier-details.description"></div>
|
||||
|
||||
@ -156,7 +156,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<File> imple
|
||||
this.calculateData();
|
||||
|
||||
this.addSubscription = timer(0, 20 * 1000).subscribe(async () => {
|
||||
await this._appStateService.reloadActiveDossierFilesIfNecessary();
|
||||
await this._appStateService.reloadActiveDossierFiles();
|
||||
this.calculateData();
|
||||
});
|
||||
|
||||
|
||||
@ -1,29 +1,35 @@
|
||||
<div [matTooltip]="dossier.dossierName" class="table-item-title heading mb-6" matTooltipPosition="above">
|
||||
{{ dossier.dossierName }}
|
||||
</div>
|
||||
|
||||
<div class="small-label stats-subtitle mb-6">
|
||||
<div>
|
||||
<mat-icon svgIcon="red:template"></mat-icon>
|
||||
{{ getDossierTemplateNameFor(dossier.dossierTemplateId) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="small-label stats-subtitle">
|
||||
|
||||
<div *ngIf="dossier.stats$ | async as stats" class="small-label stats-subtitle">
|
||||
<div>
|
||||
<mat-icon svgIcon="iqser:document"></mat-icon>
|
||||
{{ dossier.filesLength }}
|
||||
{{ stats.numberOfFiles }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<mat-icon svgIcon="iqser:pages"></mat-icon>
|
||||
{{ dossier.totalNumberOfPages }}
|
||||
{{ stats.numberOfPages }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<mat-icon svgIcon="red:user"></mat-icon>
|
||||
{{ dossier.memberIds.length }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<mat-icon svgIcon="red:calendar"></mat-icon>
|
||||
{{ dossier.date | date: 'mediumDate' }}
|
||||
</div>
|
||||
|
||||
<div *ngIf="dossier.dueDate">
|
||||
<mat-icon svgIcon="red:lightning"></mat-icon>
|
||||
{{ dossier.dueDate | date: 'mediumDate' }}
|
||||
|
||||
@ -84,10 +84,6 @@ export class DossiersListingScreenComponent
|
||||
await this._appStateService.loadAllDossiers();
|
||||
this.calculateData();
|
||||
});
|
||||
|
||||
this.addSubscription = this._appStateService.fileChanged$.subscribe(() => {
|
||||
this.calculateData();
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import { GenericService, mapEach, RequiredParam, Validate } from '@iqser/common-ui';
|
||||
import { Observable } from 'rxjs';
|
||||
import { DossierStats, IDossierStats } from '@red/domain';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class DossierStatsService extends GenericService<IDossierStats> {
|
||||
constructor(protected readonly _injector: Injector) {
|
||||
super(_injector, 'dossier-stats');
|
||||
}
|
||||
|
||||
@Validate()
|
||||
getFor(@RequiredParam() dossierIds: string[]): Observable<DossierStats[]> {
|
||||
return this._post<IDossierStats[]>(dossierIds).pipe(mapEach(entity => new DossierStats(entity)));
|
||||
}
|
||||
|
||||
// @Validate()
|
||||
// loadFor(@RequiredParam() dossierId: string): Observable<DossierStats> {
|
||||
// return this._getOne<IDossierStats>([dossierId]).pipe(
|
||||
// map((entity: IDossierStats) => new DossierStats(entity)),
|
||||
// tap((entity: DossierStats) => this.replace(entity)),
|
||||
// );
|
||||
// }
|
||||
}
|
||||
@ -1,12 +1,14 @@
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import { EntitiesService, List, QueryParam, RequiredParam, Toaster, Validate } from '@iqser/common-ui';
|
||||
import { EntitiesService, List, QueryParam, RequiredParam, shareLast, Toaster, Validate } from '@iqser/common-ui';
|
||||
import { Dossier, File, IDossier, IDossierRequest } from '@red/domain';
|
||||
import { catchError, map, tap } from 'rxjs/operators';
|
||||
import { BehaviorSubject, Observable, of } from 'rxjs';
|
||||
import { catchError, filter, map, switchMap, tap } from 'rxjs/operators';
|
||||
import { BehaviorSubject, combineLatest, Observable, of, throwError } from 'rxjs';
|
||||
import { ActivationEnd, Router } from '@angular/router';
|
||||
import { DictionaryService } from '@shared/services/dictionary.service';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { currentComponentRoute } from '@utils/functions';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { DossierStatsService } from '@services/entity-services/dossier-stats.service';
|
||||
|
||||
export interface IDossiersStats {
|
||||
totalPeople: number;
|
||||
@ -20,15 +22,16 @@ const GENERIC_MGS = _('add-dossier-dialog.errors.generic');
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class DossiersService extends EntitiesService<Dossier, IDossier> {
|
||||
readonly stats$ = this.all$.pipe(map(entities => this._computeStats(entities)));
|
||||
readonly stats$ = this.all$.pipe(switchMap(entities => this._generalStats$(entities)));
|
||||
readonly activeDossier$: Observable<Dossier | undefined>;
|
||||
private readonly _activeDossier$ = new BehaviorSubject<Dossier | undefined>(undefined);
|
||||
|
||||
constructor(
|
||||
protected readonly _injector: Injector,
|
||||
private readonly _router: Router,
|
||||
private readonly _dictionaryService: DictionaryService,
|
||||
private readonly _toaster: Toaster,
|
||||
protected readonly _injector: Injector,
|
||||
private readonly _dictionaryService: DictionaryService,
|
||||
private readonly _dossierStatsService: DossierStatsService,
|
||||
) {
|
||||
super(_injector, Dossier, 'dossier');
|
||||
this.activeDossier$ = this._activeDossier$.asObservable();
|
||||
@ -97,13 +100,18 @@ export class DossiersService extends EntitiesService<Dossier, IDossier> {
|
||||
|
||||
@Validate()
|
||||
createOrUpdate(@RequiredParam() dossier: IDossierRequest): Observable<Dossier | undefined> {
|
||||
return this._post(dossier).pipe(
|
||||
map(updatedDossier => new Dossier(updatedDossier, this.find(updatedDossier.dossierId)?.files ?? [])),
|
||||
const showToast = (error: HttpErrorResponse) => {
|
||||
this._toaster.error(error.status === 409 ? DOSSIER_EXISTS_MSG : GENERIC_MGS);
|
||||
return throwError(error);
|
||||
};
|
||||
|
||||
const dossier$ = this._post(dossier).pipe(shareLast());
|
||||
const stats$ = dossier$.pipe(switchMap(updatedDossier => this._dossierStatsService.getFor([updatedDossier.dossierId])));
|
||||
|
||||
return combineLatest([dossier$, stats$]).pipe(
|
||||
map(([updatedDossier, stats]) => new Dossier(updatedDossier, stats[0], this.find(updatedDossier.dossierId)?.files ?? [])),
|
||||
tap(newDossier => this.replace(newDossier)),
|
||||
catchError(error => {
|
||||
this._toaster.error(error.status === 409 ? DOSSIER_EXISTS_MSG : GENERIC_MGS);
|
||||
return of(undefined);
|
||||
}),
|
||||
catchError(showToast),
|
||||
);
|
||||
}
|
||||
|
||||
@ -139,7 +147,7 @@ export class DossiersService extends EntitiesService<Dossier, IDossier> {
|
||||
|
||||
entities.forEach(dossier => {
|
||||
dossier.memberIds?.forEach(m => totalPeople.add(m));
|
||||
totalAnalyzedPages += dossier.totalNumberOfPages;
|
||||
totalAnalyzedPages += dossier.stats.numberOfPages;
|
||||
});
|
||||
|
||||
return {
|
||||
@ -147,4 +155,13 @@ export class DossiersService extends EntitiesService<Dossier, IDossier> {
|
||||
totalAnalyzedPages,
|
||||
};
|
||||
}
|
||||
|
||||
private _generalStats$(entities: List<Dossier>): Observable<IDossiersStats> {
|
||||
const stats$ = entities.map(entity => entity.stats$);
|
||||
return combineLatest(stats$).pipe(
|
||||
filter(stats => stats.every(s => !!s)),
|
||||
map(() => this._computeStats(entities)),
|
||||
shareLast(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ 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 { ReanalysisService } from '@services/reanalysis.service';
|
||||
import { DossierStatsService } from '@services/entity-services/dossier-stats.service';
|
||||
|
||||
export interface AppState {
|
||||
activeFileId?: string;
|
||||
@ -35,6 +36,7 @@ export class AppStateService {
|
||||
private readonly _reanalysisService: ReanalysisService,
|
||||
private readonly _dictionaryService: DictionaryService,
|
||||
private readonly _dossierTemplatesService: DossierTemplatesService,
|
||||
private readonly _dossierStatsService: DossierStatsService,
|
||||
private readonly _fileAttributesService: FileAttributesService,
|
||||
private readonly _userPreferenceService: UserPreferenceService,
|
||||
) {
|
||||
@ -90,10 +92,6 @@ export class AppStateService {
|
||||
return this._appState.activeFileId;
|
||||
}
|
||||
|
||||
async reloadActiveDossierFilesIfNecessary() {
|
||||
await this.reloadActiveDossierFiles();
|
||||
}
|
||||
|
||||
getDictionaryColor(type?: string, dossierTemplateId = this._dossiersService.activeDossier?.dossierTemplateId) {
|
||||
if (!dossierTemplateId) {
|
||||
dossierTemplateId = this.dossierTemplates[0]?.dossierTemplateId;
|
||||
@ -128,10 +126,14 @@ export class AppStateService {
|
||||
return;
|
||||
}
|
||||
|
||||
const dossierIds = dossiers.map(dossier => dossier.dossierId);
|
||||
const dossierStats = await this._dossierStatsService.getFor(dossierIds).toPromise();
|
||||
|
||||
const mappedDossiers$ = dossiers.map(async p => {
|
||||
const oldDossier = this._dossiersService.find(p.dossierId);
|
||||
const type = oldDossier?.type ?? (await this._getDictionaryFor(p));
|
||||
return new Dossier(p, oldDossier?.files ?? [], type);
|
||||
const stats = dossierStats.find(s => s.dossierId === p.dossierId);
|
||||
return new Dossier(p, stats, oldDossier?.files ?? [], type);
|
||||
});
|
||||
const mappedDossiers = await Promise.all(mappedDossiers$);
|
||||
const fileData = await this._filesService.getFor(mappedDossiers.map(p => p.id)).toPromise();
|
||||
@ -160,7 +162,7 @@ export class AppStateService {
|
||||
);
|
||||
const files = activeDossier.files.filter(file => file.fileId !== activeFile.fileId);
|
||||
files.push(activeFile);
|
||||
const newDossier = new Dossier(activeDossier, files, activeDossier.type);
|
||||
const newDossier = new Dossier(activeDossier, activeDossier.stats, files, activeDossier.type);
|
||||
this._dossiersService.replace(newDossier);
|
||||
|
||||
if (activeFile.lastProcessed !== oldProcessedDate) {
|
||||
@ -512,7 +514,7 @@ export class AppStateService {
|
||||
}
|
||||
}
|
||||
|
||||
const newDossier = new Dossier(dossier, newFiles, dossier.type);
|
||||
const newDossier = new Dossier(dossier, dossier.stats, newFiles, dossier.type);
|
||||
this._dossiersService.replace(newDossier);
|
||||
|
||||
return newFiles;
|
||||
|
||||
@ -18,3 +18,4 @@ export * from './lib/reports';
|
||||
export * from './lib/configuration';
|
||||
export * from './lib/signature';
|
||||
export * from './lib/legal-basis';
|
||||
export * from './lib/dossier-stats';
|
||||
|
||||
34
libs/red-domain/src/lib/dossier-stats/dossier-stats.model.ts
Normal file
34
libs/red-domain/src/lib/dossier-stats/dossier-stats.model.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { IDossierStats } from './dossier-stats';
|
||||
import { FileCountPerProcessingStatus, FileCountPerWorkflowStatus } from './types';
|
||||
|
||||
export class DossierStats implements IDossierStats {
|
||||
readonly dossierId: string;
|
||||
readonly fileCountPerProcessingStatus: FileCountPerProcessingStatus;
|
||||
readonly fileCountPerWorkflowStatus: FileCountPerWorkflowStatus;
|
||||
readonly hasHintsNoRedactionsFilePresent: boolean;
|
||||
readonly hasNoFlagsFilePresent: boolean;
|
||||
readonly hasRedactionsFilePresent: boolean;
|
||||
readonly hasSuggestionsFilePresent: boolean;
|
||||
readonly hasUpdatesFilePresent: boolean;
|
||||
readonly numberOfPages: number;
|
||||
readonly numberOfFiles: number;
|
||||
|
||||
readonly hasNone: boolean;
|
||||
readonly hasFiles: boolean;
|
||||
|
||||
constructor(stats: IDossierStats) {
|
||||
this.dossierId = stats.dossierId;
|
||||
this.fileCountPerProcessingStatus = stats.fileCountPerProcessingStatus;
|
||||
this.fileCountPerWorkflowStatus = stats.fileCountPerWorkflowStatus;
|
||||
this.hasHintsNoRedactionsFilePresent = stats.hasHintsNoRedactionsFilePresent;
|
||||
this.hasNoFlagsFilePresent = stats.hasNoFlagsFilePresent;
|
||||
this.hasRedactionsFilePresent = stats.hasRedactionsFilePresent;
|
||||
this.hasSuggestionsFilePresent = stats.hasSuggestionsFilePresent;
|
||||
this.hasUpdatesFilePresent = stats.hasUpdatesFilePresent;
|
||||
this.numberOfPages = stats.numberOfPages;
|
||||
this.numberOfFiles = stats.numberOfFiles;
|
||||
|
||||
this.hasNone = !this.hasSuggestionsFilePresent && !this.hasRedactionsFilePresent && !this.hasHintsNoRedactionsFilePresent;
|
||||
this.hasFiles = this.numberOfFiles > 0;
|
||||
}
|
||||
}
|
||||
14
libs/red-domain/src/lib/dossier-stats/dossier-stats.ts
Normal file
14
libs/red-domain/src/lib/dossier-stats/dossier-stats.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { FileCountPerProcessingStatus, FileCountPerWorkflowStatus } from './types';
|
||||
|
||||
export interface IDossierStats {
|
||||
dossierId: string;
|
||||
fileCountPerProcessingStatus: FileCountPerProcessingStatus;
|
||||
fileCountPerWorkflowStatus: FileCountPerWorkflowStatus;
|
||||
hasHintsNoRedactionsFilePresent: boolean;
|
||||
hasNoFlagsFilePresent: boolean;
|
||||
hasRedactionsFilePresent: boolean;
|
||||
hasSuggestionsFilePresent: boolean;
|
||||
hasUpdatesFilePresent: boolean;
|
||||
numberOfPages: number;
|
||||
numberOfFiles: number;
|
||||
}
|
||||
3
libs/red-domain/src/lib/dossier-stats/index.ts
Normal file
3
libs/red-domain/src/lib/dossier-stats/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from './dossier-stats';
|
||||
export * from './dossier-stats.model';
|
||||
export * from './types';
|
||||
26
libs/red-domain/src/lib/dossier-stats/types.ts
Normal file
26
libs/red-domain/src/lib/dossier-stats/types.ts
Normal file
@ -0,0 +1,26 @@
|
||||
export const WorkflowFileStatuses = {
|
||||
APPROVED: 'APPROVED',
|
||||
UNASSIGNED: 'UNASSIGNED',
|
||||
UNDER_APPROVAL: 'UNDER_APPROVAL',
|
||||
UNDER_REVIEW: 'UNDER_REVIEW',
|
||||
} as const;
|
||||
|
||||
export type WorkflowFileStatus = keyof typeof WorkflowFileStatuses;
|
||||
|
||||
export type FileCountPerWorkflowStatus = { [key in WorkflowFileStatus]?: number };
|
||||
|
||||
export const ProcessingFileStatuses = {
|
||||
DELETED: 'DELETED',
|
||||
ERROR: 'ERROR',
|
||||
FULLREPROCESS: 'FULLREPROCESS',
|
||||
INDEXING: 'INDEXING',
|
||||
OCR_PROCESSING: 'OCR_PROCESSING',
|
||||
PROCESSED: 'PROCESSED',
|
||||
PROCESSING: 'PROCESSING',
|
||||
REPROCESS: 'REPROCESS',
|
||||
UNPROCESSED: 'UNPROCESSED',
|
||||
} as const;
|
||||
|
||||
export type ProcessingFileStatus = keyof typeof ProcessingFileStatuses;
|
||||
|
||||
export type FileCountPerProcessingStatus = { [key in ProcessingFileStatus]?: number };
|
||||
@ -4,6 +4,8 @@ import { IDossier } from './dossier';
|
||||
import { DossierStatus } from './types';
|
||||
import { DownloadFileType } from '../shared';
|
||||
import { IDictionary } from '../dictionaries';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { DossierStats } from '../dossier-stats';
|
||||
|
||||
export class Dossier implements IDossier, IListable {
|
||||
readonly dossierId: string;
|
||||
@ -25,17 +27,17 @@ export class Dossier implements IDossier, IListable {
|
||||
readonly hasReviewers: boolean;
|
||||
|
||||
readonly reanalysisRequired = this.files.some(file => file.analysisRequired);
|
||||
readonly hasFiles = this.files.length > 0;
|
||||
readonly filesLength = this.files.length;
|
||||
|
||||
readonly totalNumberOfPages: number;
|
||||
readonly hintsOnly: boolean;
|
||||
readonly hasRedactions: boolean;
|
||||
readonly hasSuggestions: boolean;
|
||||
readonly hasNone: boolean;
|
||||
readonly hasPendingOrProcessing: boolean;
|
||||
|
||||
constructor(dossier: IDossier, readonly files: List<File> = [], public type?: IDictionary) {
|
||||
readonly stats$: Observable<DossierStats>;
|
||||
private readonly _stats$: BehaviorSubject<DossierStats>;
|
||||
|
||||
constructor(dossier: IDossier, stats: DossierStats, readonly files: List<File> = [], public type?: IDictionary) {
|
||||
this.dossierId = dossier.dossierId;
|
||||
this.approverIds = dossier.approverIds;
|
||||
this.date = dossier.date;
|
||||
@ -54,6 +56,9 @@ export class Dossier implements IDossier, IListable {
|
||||
this.watermarkEnabled = dossier.watermarkEnabled;
|
||||
this.hasReviewers = !!this.memberIds && this.memberIds.length > 1;
|
||||
|
||||
this._stats$ = new BehaviorSubject<DossierStats>(stats);
|
||||
this.stats$ = this._stats$.asObservable();
|
||||
|
||||
let hintsOnly = false;
|
||||
let hasRedactions = false;
|
||||
let hasSuggestions = false;
|
||||
@ -72,7 +77,6 @@ export class Dossier implements IDossier, IListable {
|
||||
this.hasRedactions = hasRedactions;
|
||||
this.hasSuggestions = hasSuggestions;
|
||||
this.totalNumberOfPages = totalNumberOfPages;
|
||||
this.hasPendingOrProcessing = hasPendingOrProcessing;
|
||||
this.hasNone = !this.hasSuggestions && !this.hasRedactions && !this.hintsOnly;
|
||||
}
|
||||
|
||||
@ -88,6 +92,10 @@ export class Dossier implements IDossier, IListable {
|
||||
return this.dossierName;
|
||||
}
|
||||
|
||||
get stats(): DossierStats {
|
||||
return this._stats$.getValue();
|
||||
}
|
||||
|
||||
hasStatus(status: string): boolean {
|
||||
return !!this.files.find(f => f.status === status);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user