From 065fe432f64ce086637de145aca1a1484a98e8a6 Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Wed, 29 Sep 2021 18:47:09 +0300 Subject: [PATCH 01/14] update types / undefineds --- .../app/models/audit-model-wrapper.model.ts | 0 apps/red-ui/src/app/models/audit.model.ts | 4 +- apps/red-ui/src/app/models/dictionary.ts | 2 +- apps/red-ui/src/app/models/file/file.ts | 60 ++++++++--------- apps/red-ui/src/app/models/user.ts | 4 +- .../dossier/services/dossiers.service.ts | 8 +-- .../red-ui/src/app/state/app-state.service.ts | 65 +++++++++++-------- .../state/model/dossier-attribute-config.ts | 4 +- apps/red-ui/src/app/state/model/dossier.ts | 34 +++++----- .../src/app/state/model/dossier.wrapper.ts | 0 libs/common-ui | 2 +- libs/red-ui-http/src/lib/model/audit.ts | 2 +- libs/red-ui-http/src/lib/model/dictionary.ts | 2 +- libs/red-ui-http/src/lib/model/dossier.ts | 8 +-- .../src/lib/model/dossierAttributeConfig.ts | 4 +- libs/red-ui-http/src/lib/model/file.ts | 10 +-- libs/red-ui-http/src/lib/model/user.ts | 2 +- 17 files changed, 112 insertions(+), 99 deletions(-) delete mode 100644 apps/red-ui/src/app/models/audit-model-wrapper.model.ts delete mode 100644 apps/red-ui/src/app/state/model/dossier.wrapper.ts diff --git a/apps/red-ui/src/app/models/audit-model-wrapper.model.ts b/apps/red-ui/src/app/models/audit-model-wrapper.model.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/apps/red-ui/src/app/models/audit.model.ts b/apps/red-ui/src/app/models/audit.model.ts index d653e3099..76ca7d7ad 100644 --- a/apps/red-ui/src/app/models/audit.model.ts +++ b/apps/red-ui/src/app/models/audit.model.ts @@ -7,7 +7,7 @@ export class Audit implements IAudit, IListable { readonly details?: unknown; readonly message?: string; readonly objectId?: string; - readonly recordDate?: string; + readonly recordDate: string; readonly userId?: string; constructor(audit: IAudit) { @@ -20,7 +20,7 @@ export class Audit implements IAudit, IListable { this.userId = audit.userId; } - get id() { + get id(): string { return this.recordDate; } diff --git a/apps/red-ui/src/app/models/dictionary.ts b/apps/red-ui/src/app/models/dictionary.ts index bae65a716..53f4d6350 100644 --- a/apps/red-ui/src/app/models/dictionary.ts +++ b/apps/red-ui/src/app/models/dictionary.ts @@ -9,7 +9,7 @@ export class Dictionary implements IDictionary, IListable { readonly entries?: List; readonly hexColor?: string; readonly hint: boolean; - readonly label?: string; + readonly label: string; readonly rank?: number; readonly recommendation: boolean; diff --git a/apps/red-ui/src/app/models/file/file.ts b/apps/red-ui/src/app/models/file/file.ts index 2f7d82d22..e4b788de4 100644 --- a/apps/red-ui/src/app/models/file/file.ts +++ b/apps/red-ui/src/app/models/file/file.ts @@ -11,17 +11,17 @@ const processingStatuses: List = [ ] as const; export class File implements IFile, IListable { - readonly added: string; + readonly added?: string; readonly allManualRedactionsApplied: boolean; - readonly analysisDuration: number; + readonly analysisDuration?: number; readonly analysisRequired: boolean; - readonly approvalDate: string; - readonly currentReviewer: string; - readonly dictionaryVersion: number; - readonly dossierDictionaryVersion: number; + readonly approvalDate?: string; + readonly currentReviewer?: string; + readonly dictionaryVersion?: number; + readonly dossierDictionaryVersion?: number; readonly dossierId: string; readonly excluded: boolean; - readonly fileAttributes: FileAttributes; + readonly fileAttributes?: FileAttributes; readonly fileId: string; readonly filename: string; readonly hasAnnotationComments: boolean; @@ -29,20 +29,20 @@ export class File implements IFile, IListable { readonly hasImages: boolean; readonly hasRedactions: boolean; readonly hasUpdates: boolean; - readonly lastOCRTime: string; - readonly lastProcessed: string; - readonly lastReviewer: string; - readonly lastUpdated: string; - readonly lastUploaded: string; - readonly legalBasisVersion: number; - readonly numberOfAnalyses: number; - readonly numberOfPages: number; - readonly rulesVersion: number; + readonly lastOCRTime?: string; + readonly lastProcessed?: string; + readonly lastReviewer?: string; + readonly lastUpdated?: string; + readonly lastUploaded?: string; + readonly legalBasisVersion?: number; + readonly numberOfAnalyses?: number; + readonly numberOfPages?: number; + readonly rulesVersion?: number; readonly status: FileStatus; - readonly uploader: string; - readonly excludedPages: number[]; + readonly uploader?: string; + readonly excludedPages?: number[]; readonly hasSuggestions: boolean; - readonly dossierTemplateId: string; + readonly dossierTemplateId?: string; primaryAttribute: string; lastOpened: boolean; @@ -64,23 +64,23 @@ export class File implements IFile, IListable { constructor(file: IFile, public reviewerName: string, fileAttributesConfig?: FileAttributesConfig) { this.added = file.added; - this.allManualRedactionsApplied = file.allManualRedactionsApplied; + this.allManualRedactionsApplied = !!file.allManualRedactionsApplied; this.analysisDuration = file.analysisDuration; - this.analysisRequired = file.analysisRequired && !file.excluded; + this.analysisRequired = !!file.analysisRequired && !file.excluded; this.approvalDate = file.approvalDate; this.currentReviewer = file.currentReviewer; this.dictionaryVersion = file.dictionaryVersion; this.dossierDictionaryVersion = file.dossierDictionaryVersion; this.dossierId = file.dossierId; - this.excluded = file.excluded; + this.excluded = !!file.excluded; this.fileAttributes = file.fileAttributes; this.fileId = file.fileId; this.filename = file.filename; - this.hasAnnotationComments = file.hasAnnotationComments; - this.hasHints = file.hasHints; - this.hasImages = file.hasImages; - this.hasRedactions = file.hasRedactions; - this.hasUpdates = file.hasUpdates; + this.hasAnnotationComments = !!file.hasAnnotationComments; + this.hasHints = !!file.hasHints; + this.hasImages = !!file.hasImages; + this.hasRedactions = !!file.hasRedactions; + this.hasUpdates = !!file.hasUpdates; this.lastOCRTime = file.lastOCRTime; this.lastProcessed = file.lastProcessed; this.lastReviewer = file.lastReviewer; @@ -94,11 +94,13 @@ export class File implements IFile, IListable { this.rulesVersion = file.rulesVersion; this.uploader = file.uploader; this.excludedPages = file.excludedPages; - this.hasSuggestions = file.hasSuggestions; + this.hasSuggestions = !!file.hasSuggestions; this.dossierTemplateId = file.dossierTemplateId; this.statusSort = StatusSorter[this.status]; - this.cacheIdentifier = btoa(this.lastUploaded + this.lastOCRTime); + if (this.lastUpdated && this.lastOCRTime) { + this.cacheIdentifier = btoa(this.lastUploaded + this.lastOCRTime); + } this.hintsOnly = this.hasHints && !this.hasRedactions; this.hasNone = !this.hasRedactions && !this.hasHints && !this.hasSuggestions; this.isUnassigned = !this.currentReviewer; diff --git a/apps/red-ui/src/app/models/user.ts b/apps/red-ui/src/app/models/user.ts index 24bb45dd4..75d775736 100644 --- a/apps/red-ui/src/app/models/user.ts +++ b/apps/red-ui/src/app/models/user.ts @@ -5,8 +5,8 @@ import { KeycloakProfile } from 'keycloak-js'; export class User implements IUser, IListable { readonly email: string; readonly username: string; - readonly firstName: string; - readonly lastName: string; + readonly firstName?: string; + readonly lastName?: string; readonly name: string; readonly searchKey: string; diff --git a/apps/red-ui/src/app/modules/dossier/services/dossiers.service.ts b/apps/red-ui/src/app/modules/dossier/services/dossiers.service.ts index 46a87f29b..e037a5b8c 100644 --- a/apps/red-ui/src/app/modules/dossier/services/dossiers.service.ts +++ b/apps/red-ui/src/app/modules/dossier/services/dossiers.service.ts @@ -20,9 +20,9 @@ const getRelatedEvents = filter(event => event instanceof ActivationEnd && event }) export class DossiersService extends EntitiesService { readonly stats$ = this.all$.pipe(map(entities => this._computeStats(entities))); - readonly activeDossierId$: Observable; - readonly activeDossier$: Observable; - private readonly _activeDossierId$ = new BehaviorSubject(null); + readonly activeDossierId$: Observable; + readonly activeDossier$: Observable; + private readonly _activeDossierId$ = new BehaviorSubject(undefined); constructor(protected readonly _injector: Injector, private readonly _router: Router) { super(TEMPORARY_INJECTOR(_injector), 'dossier'); @@ -38,7 +38,7 @@ export class DossiersService extends EntitiesService { } if (dossierId === null || dossierId === undefined) { - return this._activeDossierId$.next(null); + return this._activeDossierId$.next(undefined); } // const notFound = !this.all.some(dossier => dossier.id === dossierId); diff --git a/apps/red-ui/src/app/state/app-state.service.ts b/apps/red-ui/src/app/state/app-state.service.ts index c0eeee9c7..0644fd983 100644 --- a/apps/red-ui/src/app/state/app-state.service.ts +++ b/apps/red-ui/src/app/state/app-state.service.ts @@ -22,10 +22,10 @@ import { FileAttributesService } from '../modules/dossier/services/file-attribut export interface AppState { dossiers: Dossier[]; dossierTemplates: DossierTemplate[]; - activeDossierId: string; - activeFileId: string; - activeDossierTemplateId: string; - activeDictionaryType: string; + activeDossierId?: string; + activeFileId?: string; + activeDossierTemplateId?: string; + activeDictionaryType?: string; totalAnalysedPages?: number; totalPeople?: number; } @@ -56,11 +56,7 @@ export class AppStateService { ) { this._appState = { dossiers: [], - dossierTemplates: [], - activeDossierId: null, - activeFileId: null, - activeDossierTemplateId: null, - activeDictionaryType: null + dossierTemplates: [] }; _router.events.subscribe((event: Event) => { @@ -74,14 +70,14 @@ export class AppStateService { return this.activateDossier(dossierId); } if (AppStateService._isRandomRoute(event)) { - this._appState.activeDossierId = null; + this._appState.activeDossierId = undefined; } }); } - private _dictionaryData: { [key: string]: { [key: string]: TypeValue } } = null; + private _dictionaryData?: { [key: string]: { [key: string]: TypeValue } }; - get dictionaryData(): { [key: string]: { [key: string]: TypeValue } } { + get dictionaryData(): { [key: string]: { [key: string]: TypeValue } } | undefined { return this._dictionaryData; } @@ -89,11 +85,11 @@ export class AppStateService { return this.allDossiers.reduce((acc, { files }) => [...acc, ...files], []); } - get activeDossierTemplateId(): string { + get activeDossierTemplateId(): string | undefined { return this._appState.activeDossierTemplateId; } - get activeDossierTemplate(): DossierTemplate { + get activeDossierTemplate(): DossierTemplate | undefined { return this.getDossierTemplateById(this.activeDossierTemplateId); } @@ -101,17 +97,20 @@ export class AppStateService { return this._appState.dossierTemplates; } - get activeDictionaryType(): string { + get activeDictionaryType(): string | undefined { return this._appState.activeDictionaryType; } - get activeDictionary(): TypeValue { - return this.activeDossierTemplateId && this.dictionaryData[this.activeDossierTemplateId] + get activeDictionary(): TypeValue | undefined { + return this.activeDossierTemplateId && + this.activeDictionaryType && + this.dictionaryData && + this.dictionaryData[this.activeDossierTemplateId] ? this.dictionaryData[this.activeDossierTemplateId][this.activeDictionaryType] - : null; + : undefined; } - get activeDossierId(): string { + get activeDossierId(): string | undefined { return this._appState.activeDossierId; } @@ -131,15 +130,15 @@ export class AppStateService { return this.activeDossier?.files.find(f => f.fileId === this.activeFileId); } - get activeFileId(): string { + get activeFileId(): string | undefined { return this._appState.activeFileId; } - get totalAnalysedPages(): number { + get totalAnalysedPages(): number | undefined { return this._appState.totalAnalysedPages; } - get totalPeople(): number { + get totalPeople(): number | undefined { return this._appState.totalPeople; } @@ -170,18 +169,26 @@ export class AppStateService { if (!dossierTemplateId) { dossierTemplateId = this.dossierTemplates[0]?.dossierTemplateId; } - if (!dossierTemplateId) { + + if (!dossierTemplateId || !this._dictionaryData) { return '#cccccc'; } - const color = this._dictionaryData[dossierTemplateId][type]?.hexColor; + + let color; + if (type) { + color = this._dictionaryData[dossierTemplateId][type]?.hexColor; + } return color ?? this._dictionaryData[dossierTemplateId]['default'].hexColor; } - getDossierTemplateById(id: string): DossierTemplate { + getDossierTemplateById(id?: string): DossierTemplate | undefined { + if (!id) { + return undefined; + } return this.dossierTemplates.find(rs => rs.dossierTemplateId === id); } - getDictionaryTypeValue(key: string, dossierTemplateId?: string): TypeValue { + getDictionaryTypeValue(key: string, dossierTemplateId?: string): TypeValue | undefined { if (!dossierTemplateId && this.activeDossier) { dossierTemplateId = this.activeDossier.dossierTemplateId; } @@ -189,7 +196,7 @@ export class AppStateService { if (!dossierTemplateId) { dossierTemplateId = this.dossierTemplates.length > 0 ? this.dossierTemplates[0].dossierTemplateId : undefined; } - if (!dossierTemplateId) { + if (!dossierTemplateId || !this._dictionaryData) { return undefined; } @@ -216,7 +223,9 @@ export class AppStateService { for (const dossierId of Object.keys(fileData)) { const dossier = mappedDossiers.find(p => p.id === dossierId); - this._processFiles(dossier, fileData[dossierId], emitEvents); + if (dossier) { + this._processFiles(dossier, fileData[dossierId], emitEvents); + } } this._appState.dossiers = mappedDossiers; diff --git a/apps/red-ui/src/app/state/model/dossier-attribute-config.ts b/apps/red-ui/src/app/state/model/dossier-attribute-config.ts index 28da877ca..087c3081b 100644 --- a/apps/red-ui/src/app/state/model/dossier-attribute-config.ts +++ b/apps/red-ui/src/app/state/model/dossier-attribute-config.ts @@ -4,9 +4,10 @@ import { IListable } from '@iqser/common-ui'; export class DossierAttributeConfig implements IDossierAttributeConfig, IListable { readonly id: string; readonly editable: boolean; - readonly label?: string; + readonly label: string; readonly placeholder?: string; readonly type?: DossierAttributeConfigType; + readonly dossierTemplateId: string; constructor(dossierAttributeConfig: IDossierAttributeConfig) { this.id = dossierAttributeConfig.id; @@ -14,6 +15,7 @@ export class DossierAttributeConfig implements IDossierAttributeConfig, IListabl this.label = dossierAttributeConfig.label; this.placeholder = dossierAttributeConfig.placeholder; this.type = dossierAttributeConfig.type; + this.dossierTemplateId = dossierAttributeConfig.dossierTemplateId; } get searchKey(): string { diff --git a/apps/red-ui/src/app/state/model/dossier.ts b/apps/red-ui/src/app/state/model/dossier.ts index 6e2ec7389..e70dc6972 100644 --- a/apps/red-ui/src/app/state/model/dossier.ts +++ b/apps/red-ui/src/app/state/model/dossier.ts @@ -4,20 +4,20 @@ import { IListable } from '@iqser/common-ui'; export class Dossier implements IDossier, IListable { readonly dossierId: string; - readonly ownerId: string; - readonly memberIds: List; - readonly approverIds: List; - readonly reportTemplateIds: List; readonly dossierTemplateId: string; + readonly ownerId: string; + readonly memberIds?: List; + readonly approverIds?: List; + readonly reportTemplateIds?: List; readonly dossierName: string; - readonly date: string; - readonly description: string; - readonly downloadFileTypes: List; - readonly dueDate: string; - readonly hardDeletedTime: string; - readonly reportTypes: List; - readonly softDeletedTime: string; - readonly status: DossierStatus; + readonly date?: string; + readonly dueDate?: string; + readonly description?: string; + readonly downloadFileTypes?: List; + readonly hardDeletedTime?: string; + readonly reportTypes?: List; + readonly softDeletedTime?: string; + readonly status?: DossierStatus; readonly watermarkEnabled: boolean; readonly hasReviewers: boolean; @@ -25,7 +25,7 @@ export class Dossier implements IDossier, IListable { hasFiles = this._files.length > 0; filesLength = this._files.length; - totalNumberOfPages?: number; + totalNumberOfPages = 0; hintsOnly?: boolean; hasRedactions?: boolean; hasSuggestions?: boolean; @@ -51,8 +51,8 @@ export class Dossier implements IDossier, IListable { this.reportTypes = dossier.reportTypes; this.softDeletedTime = dossier.softDeletedTime; this.status = dossier.status; - this.watermarkEnabled = dossier.watermarkEnabled; - this.hasReviewers = this.memberIds.length > 1; + this.watermarkEnabled = !!dossier.watermarkEnabled; + this.hasReviewers = !!this.memberIds && this.memberIds.length > 1; this._recomputeFileStatus(); } @@ -83,7 +83,7 @@ export class Dossier implements IDossier, IListable { } hasMember(memberId: string): boolean { - return this.memberIds.indexOf(memberId) >= 0; + return !!this.memberIds && this.memberIds.indexOf(memberId) >= 0; } private _recomputeFileStatus() { @@ -99,7 +99,7 @@ export class Dossier implements IDossier, IListable { this.hasRedactions = this.hasRedactions || f.hasRedactions; this.hasSuggestions = this.hasSuggestions || f.hasSuggestions; this.allFilesApproved = this.allFilesApproved && f.isApproved; - this.totalNumberOfPages += f.numberOfPages; + this.totalNumberOfPages += f.numberOfPages ?? 0; this.hasPendingOrProcessing = this.hasPendingOrProcessing || f.isPending || f.isProcessing; }); this.hasNone = !this.hasSuggestions && !this.hasRedactions && !this.hintsOnly; diff --git a/apps/red-ui/src/app/state/model/dossier.wrapper.ts b/apps/red-ui/src/app/state/model/dossier.wrapper.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/libs/common-ui b/libs/common-ui index c0b445b06..25d66040d 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit c0b445b06ed86a07c4b9aa1803b29b9384021d54 +Subproject commit 25d66040d01d06520a4497d88395903b95121e3b diff --git a/libs/red-ui-http/src/lib/model/audit.ts b/libs/red-ui-http/src/lib/model/audit.ts index 940f7eb76..2a94b2242 100644 --- a/libs/red-ui-http/src/lib/model/audit.ts +++ b/libs/red-ui-http/src/lib/model/audit.ts @@ -15,7 +15,7 @@ export interface IAudit { readonly details?: unknown; readonly message?: string; readonly objectId?: string; - readonly recordDate?: string; + readonly recordDate: string; readonly recordId?: number; readonly userId?: string; } diff --git a/libs/red-ui-http/src/lib/model/dictionary.ts b/libs/red-ui-http/src/lib/model/dictionary.ts index 5bfd45658..0754fb732 100644 --- a/libs/red-ui-http/src/lib/model/dictionary.ts +++ b/libs/red-ui-http/src/lib/model/dictionary.ts @@ -47,7 +47,7 @@ export interface IDictionary { /** * Label of the type */ - readonly label?: string; + readonly label: string; /** * The rank of this dictionary, higher rank means higher importance. */ diff --git a/libs/red-ui-http/src/lib/model/dossier.ts b/libs/red-ui-http/src/lib/model/dossier.ts index f87e6224b..0e48a239c 100644 --- a/libs/red-ui-http/src/lib/model/dossier.ts +++ b/libs/red-ui-http/src/lib/model/dossier.ts @@ -12,17 +12,17 @@ import { List } from '../red-types'; export interface IDossier { + readonly dossierId: string; + readonly dossierName: string; + readonly dossierTemplateId: string; readonly approverIds?: List; readonly date?: string; readonly description?: string; - readonly dossierId?: string; - readonly dossierName?: string; - readonly dossierTemplateId?: string; readonly downloadFileTypes?: List; readonly dueDate?: string; readonly hardDeletedTime?: string; readonly memberIds?: List; - readonly ownerId?: string; + readonly ownerId: string; readonly reportTemplateIds?: List; readonly reportTypes?: List; readonly softDeletedTime?: string; diff --git a/libs/red-ui-http/src/lib/model/dossierAttributeConfig.ts b/libs/red-ui-http/src/lib/model/dossierAttributeConfig.ts index ba1173cad..d41f90b65 100644 --- a/libs/red-ui-http/src/lib/model/dossierAttributeConfig.ts +++ b/libs/red-ui-http/src/lib/model/dossierAttributeConfig.ts @@ -13,9 +13,9 @@ export interface IDossierAttributeConfig { readonly id: string; readonly editable?: boolean; - readonly label?: string; + readonly label: string; readonly placeholder?: string; - readonly dossierTemplateId?: string; + readonly dossierTemplateId: string; readonly type?: DossierAttributeConfigType; } diff --git a/libs/red-ui-http/src/lib/model/file.ts b/libs/red-ui-http/src/lib/model/file.ts index 1d5212519..82613b308 100644 --- a/libs/red-ui-http/src/lib/model/file.ts +++ b/libs/red-ui-http/src/lib/model/file.ts @@ -9,7 +9,7 @@ * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. */ -import { FileAttributes } from './fileAttributes'; +import { FileAttributes } from "./fileAttributes"; /** * Object containing information on a specific file. @@ -50,7 +50,7 @@ export interface IFile { /** * The ID of the dossier the file belongs to. */ - readonly dossierId?: string; + readonly dossierId: string; /** * The dossierTemplateId for this file. */ @@ -67,11 +67,11 @@ export interface IFile { /** * The ID of the file. */ - readonly fileId?: string; + readonly fileId: string; /** * The file's name. */ - readonly filename?: string; + readonly filename: string; /** * Shows if this file has comments on annotations. */ @@ -147,7 +147,7 @@ export interface IFile { /** * The status of the file with regard to its analysis an review processes. */ - readonly status?: FileStatus; + readonly status: FileStatus; /** * The ID of the user who uploaded the file. */ diff --git a/libs/red-ui-http/src/lib/model/user.ts b/libs/red-ui-http/src/lib/model/user.ts index 12c831294..c51160c70 100644 --- a/libs/red-ui-http/src/lib/model/user.ts +++ b/libs/red-ui-http/src/lib/model/user.ts @@ -17,7 +17,7 @@ export interface IUser { /** * Email of user. */ - readonly email?: string; + readonly email: string; /** * First name of user. */ From 2ebc3060d7f8ca010e9043f043bedfc93ba46378 Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Fri, 1 Oct 2021 11:24:22 +0300 Subject: [PATCH 02/14] fix some errors --- .../page-indicator.component.ts | 21 ++++++------ .../add-dossier-dialog.component.ts | 32 +++++++++---------- .../dossier/services/dossiers.service.ts | 4 +-- .../red-ui/src/app/state/app-state.service.ts | 4 +-- 4 files changed, 30 insertions(+), 31 deletions(-) diff --git a/apps/red-ui/src/app/modules/dossier/components/page-indicator/page-indicator.component.ts b/apps/red-ui/src/app/modules/dossier/components/page-indicator/page-indicator.component.ts index 7e6cdf763..5a0e559f7 100644 --- a/apps/red-ui/src/app/modules/dossier/components/page-indicator/page-indicator.component.ts +++ b/apps/red-ui/src/app/modules/dossier/components/page-indicator/page-indicator.component.ts @@ -1,9 +1,9 @@ -import {Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges} from '@angular/core'; -import {ViewedPages, ViewedPagesControllerService} from '@redaction/red-ui-http'; -import {AppStateService} from '@state/app-state.service'; -import {PermissionsService} from '@services/permissions.service'; -import {ConfigService} from '@services/config.service'; -import {Subscription} from 'rxjs'; +import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core'; +import { ViewedPages, ViewedPagesControllerService } from '@redaction/red-ui-http'; +import { AppStateService } from '@state/app-state.service'; +import { PermissionsService } from '@services/permissions.service'; +import { ConfigService } from '@services/config.service'; +import { Subscription } from 'rxjs'; @Component({ selector: 'redaction-page-indicator', @@ -16,7 +16,7 @@ export class PageIndicatorComponent implements OnChanges, OnInit, OnDestroy { @Input() viewedPages: ViewedPages; @Input() activeSelection = false; - @Output() pageSelected = new EventEmitter(); + @Output() readonly pageSelected = new EventEmitter(); pageReadTimeout: number = null; canMarkPagesAsViewed: boolean; @@ -27,8 +27,7 @@ export class PageIndicatorComponent implements OnChanges, OnInit, OnDestroy { private readonly _appStateService: AppStateService, private readonly _configService: ConfigService, private readonly _permissionService: PermissionsService - ) { - } + ) {} get read() { return this.viewedPages?.pages?.findIndex(p => p.page === this.number) >= 0; @@ -96,9 +95,9 @@ export class PageIndicatorComponent implements OnChanges, OnInit, OnDestroy { private _markPageRead() { this._viewedPagesControllerService - .addPage({page: this.number}, this._appStateService.activeDossierId, this._appStateService.activeFileId) + .addPage({ page: this.number }, this._appStateService.activeDossierId, this._appStateService.activeFileId) .subscribe(() => { - this.viewedPages?.pages?.push({page: this.number, fileId: this._appStateService.activeFileId}); + this.viewedPages?.pages?.push({ page: this.number, fileId: this._appStateService.activeFileId }); }); } diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/add-dossier-dialog/add-dossier-dialog.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/add-dossier-dialog/add-dossier-dialog.component.ts index a894ed1c6..66be39abb 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/add-dossier-dialog/add-dossier-dialog.component.ts +++ b/apps/red-ui/src/app/modules/dossier/dialogs/add-dossier-dialog/add-dossier-dialog.component.ts @@ -1,11 +1,11 @@ -import {Component} from '@angular/core'; -import {MatDialogRef} from '@angular/material/dialog'; -import {DossierRequest, DownloadFileType, IDossierTemplate, ReportTemplate, ReportTemplateControllerService} from '@redaction/red-ui-http'; -import {FormBuilder, FormGroup, Validators} from '@angular/forms'; -import {AppStateService} from '@state/app-state.service'; +import { Component } from '@angular/core'; +import { MatDialogRef } from '@angular/material/dialog'; +import { DownloadFileType, IDossier, IDossierTemplate, ReportTemplate, ReportTemplateControllerService } from '@redaction/red-ui-http'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { AppStateService } from '@state/app-state.service'; import * as moment from 'moment'; -import {downloadTypesTranslations} from '../../../../translations/download-types-translations'; -import {IconButtonTypes} from '@iqser/common-ui'; +import { downloadTypesTranslations } from '../../../../translations/download-types-translations'; +import { IconButtonTypes } from '@iqser/common-ui'; @Component({ templateUrl: './add-dossier-dialog.component.html', @@ -22,7 +22,6 @@ export class AddDossierDialogComponent { })); dossierTemplates: IDossierTemplate[]; availableReportTypes = []; - reportTemplateValueMapper = (reportTemplate: ReportTemplate) => reportTemplate.templateId; constructor( private readonly _appStateService: AppStateService, @@ -45,7 +44,7 @@ export class AddDossierDialogComponent { validators: control => control.value.reportTemplateIds?.length > 0 || control.value.downloadFileTypes?.length > 0 ? null - : {downloadPackage: true} + : { downloadPackage: true } } ); } @@ -66,18 +65,19 @@ export class AddDossierDialogComponent { return this.dossierForm.invalid; } + reportTemplateValueMapper = (reportTemplate: ReportTemplate) => reportTemplate.templateId; + async saveDossier() { const savedDossier = await this._appStateService.createOrUpdateDossier(this._formToObject()); if (savedDossier) { - this.dialogRef.close({dossier: savedDossier}); + this.dialogRef.close({ dossier: savedDossier }); } } async saveDossierAndAddMembers() { - const dossier: DossierRequest = this._formToObject(); - const savedDossier = await this._appStateService.createOrUpdateDossier(dossier); + const savedDossier = await this._appStateService.createOrUpdateDossier(this._formToObject()); if (savedDossier) { - this.dialogRef.close({addMembers: true, dossier: savedDossier}); + this.dialogRef.close({ addMembers: true, dossier: savedDossier }); } } @@ -94,7 +94,7 @@ export class AddDossierDialogComponent { downloadFileTypes: dossierTemplate.downloadFileTypes, reportTemplateIds: [] // TODO DEFAULT }, - {emitEvent: false} + { emitEvent: false } ); } else { this.availableReportTypes = []; @@ -103,7 +103,7 @@ export class AddDossierDialogComponent { downloadFileTypes: [], reportTemplateIds: [] }, - {emitEvent: false} + { emitEvent: false } ); } } @@ -116,7 +116,7 @@ export class AddDossierDialogComponent { }); } - private _formToObject(): DossierRequest { + private _formToObject(): Partial { return { dossierName: this.dossierForm.get('dossierName').value, description: this.dossierForm.get('description').value, diff --git a/apps/red-ui/src/app/modules/dossier/services/dossiers.service.ts b/apps/red-ui/src/app/modules/dossier/services/dossiers.service.ts index e037a5b8c..bb948ad79 100644 --- a/apps/red-ui/src/app/modules/dossier/services/dossiers.service.ts +++ b/apps/red-ui/src/app/modules/dossier/services/dossiers.service.ts @@ -1,5 +1,5 @@ import { Injectable, Injector } from '@angular/core'; -import { IDossier } from '@redaction/red-ui-http'; +import { DossierRequest, IDossier } from '@redaction/red-ui-http'; import { EntitiesService, List, QueryParam } from '@iqser/common-ui'; import { Dossier } from '@state/model/dossier'; import { filter, map } from 'rxjs/operators'; @@ -56,7 +56,7 @@ export class DossiersService extends EntitiesService { return dossierId ? super._getOne([dossierId]) : super.getAll(); } - createOrUpdate(dossier: IDossier): Promise { + createOrUpdate(dossier: DossierRequest): Promise { return this._post(dossier).toPromise(); } diff --git a/apps/red-ui/src/app/state/app-state.service.ts b/apps/red-ui/src/app/state/app-state.service.ts index 0644fd983..eacc863f0 100644 --- a/apps/red-ui/src/app/state/app-state.service.ts +++ b/apps/red-ui/src/app/state/app-state.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { Colors, IDossier, IFile, ReanalysisControllerService } from '@redaction/red-ui-http'; +import { Colors, DossierRequest, IFile, ReanalysisControllerService } from '@redaction/red-ui-http'; import { Toaster } from '@iqser/common-ui'; import { TranslateService } from '@ngx-translate/core'; import { Event, NavigationEnd, ResolveStart, Router } from '@angular/router'; @@ -343,7 +343,7 @@ export class AppStateService { ); } - async createOrUpdateDossier(dossier: IDossier) { + async createOrUpdateDossier(dossier: DossierRequest) { try { const updatedDossier = await this._dossiersService.createOrUpdate(dossier); let foundDossier = this.allDossiers.find(p => p.id === updatedDossier.dossierId); From 55c0d37628fc7627cf2c4f9ae05b2d6b54695f14 Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Fri, 1 Oct 2021 13:06:29 +0300 Subject: [PATCH 03/14] make dossier files readonly --- ...ssier-overview-bulk-actions.component.html | 20 ++--- .../dossier-overview-screen.component.html | 2 +- .../dossiers-listing-actions.component.html | 6 +- .../file-actions/file-actions.component.html | 2 +- .../file-download-btn.component.ts | 13 +--- .../services/file-download.service.ts | 3 +- .../red-ui/src/app/state/app-state.service.ts | 22 +++--- apps/red-ui/src/app/state/model/dossier.ts | 75 ++++++++----------- apps/red-ui/src/app/utils/functions.ts | 3 +- 9 files changed, 67 insertions(+), 79 deletions(-) diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/bulk-actions/dossier-overview-bulk-actions.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/bulk-actions/dossier-overview-bulk-actions.component.html index 8accd8635..6d727f388 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/bulk-actions/dossier-overview-bulk-actions.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/bulk-actions/dossier-overview-bulk-actions.component.html @@ -3,43 +3,43 @@ (action)="delete()" *ngIf="canDelete" [tooltip]="'dossier-overview.bulk.delete' | translate" - icon="red:trash" [type]="circleButtonTypes.dark" + icon="red:trash" > - + @@ -56,23 +56,23 @@ (action)="setToUnderApproval()" *ngIf="canUndoApproval" [tooltip]="'dossier-overview.under-approval' | translate" - icon="red:undo" [type]="circleButtonTypes.dark" + icon="red:undo" > diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.html index d85606bcb..78323fff6 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.html @@ -8,7 +8,7 @@ > diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-actions/dossiers-listing-actions.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-actions/dossiers-listing-actions.component.html index 7c7b364fe..78eac82af 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-actions/dossiers-listing-actions.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-actions/dossiers-listing-actions.component.html @@ -4,17 +4,17 @@ (action)="openEditDossierDialog($event, dossier)" *ngIf="currentUser.isManager" [tooltip]="'dossier-listing.edit.action' | translate" - icon="iqser:edit" [type]="circleButtonTypes.dark" + icon="iqser:edit" > - + diff --git a/apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.html b/apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.html index 8d4e6e637..8329657e7 100644 --- a/apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.html +++ b/apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.html @@ -48,7 +48,7 @@ ; @Input() tooltipPosition: 'above' | 'below' | 'before' | 'after' = 'above'; @Input() type: CircleButtonType = CircleButtonTypes.default; @Input() tooltipClass: string; @@ -34,11 +33,7 @@ export class FileDownloadBtnComponent extends AutoUnsubscribe implements OnDestr } get canDownloadFiles() { - if (!Array.isArray(this.file)) { - return this._permissionsService.canDownloadFiles(this.file); - } - - return this.file.length > 0 && this.file.reduce((acc, file) => acc && this._permissionsService.canDownloadFiles(file), true); + return this.files.length > 0 && this.files.reduce((acc, file) => acc && this._permissionsService.canDownloadFiles(file), true); } get tooltip() { @@ -50,7 +45,7 @@ export class FileDownloadBtnComponent extends AutoUnsubscribe implements OnDestr downloadFiles($event: MouseEvent) { $event.stopPropagation(); this.addSubscription = this._fileDownloadService - .downloadFiles(Array.isArray(this.file) ? this.file : [this.file], this.dossier) + .downloadFiles(this.files, this.dossier) .subscribe(() => this._toaster.info(_('download-status.queued'))); } } diff --git a/apps/red-ui/src/app/modules/upload-download/services/file-download.service.ts b/apps/red-ui/src/app/modules/upload-download/services/file-download.service.ts index 74230877b..45741d33c 100644 --- a/apps/red-ui/src/app/modules/upload-download/services/file-download.service.ts +++ b/apps/red-ui/src/app/modules/upload-download/services/file-download.service.ts @@ -10,6 +10,7 @@ import { DownloadStatusWrapper } from '../model/download-status.wrapper'; import { AppStateService } from '@state/app-state.service'; import { KeycloakService } from 'keycloak-angular'; import { UserService } from '@services/user.service'; +import { List } from '@iqser/common-ui'; @Injectable() export class FileDownloadService { @@ -34,7 +35,7 @@ export class FileDownloadService { }); } - downloadFiles(files: File[], dossier: Dossier): Observable { + downloadFiles(files: List, dossier: Dossier): Observable { return this._downloadControllerService .prepareDownload({ fileIds: files.map(f => f.fileId), diff --git a/apps/red-ui/src/app/state/app-state.service.ts b/apps/red-ui/src/app/state/app-state.service.ts index eacc863f0..63c013fb9 100644 --- a/apps/red-ui/src/app/state/app-state.service.ts +++ b/apps/red-ui/src/app/state/app-state.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { Colors, DossierRequest, IFile, ReanalysisControllerService } from '@redaction/red-ui-http'; -import { Toaster } from '@iqser/common-ui'; +import { List, Toaster } from '@iqser/common-ui'; import { TranslateService } from '@ngx-translate/core'; import { Event, NavigationEnd, ResolveStart, Router } from '@angular/router'; import { UserService } from '@services/user.service'; @@ -246,7 +246,9 @@ export class AppStateService { this._userService.getNameForId(iFile.currentReviewer), this._fileAttributesService.getFileAttributeConfig(iFile.dossierTemplateId) ); - this.activeDossier.files = this.activeDossier?.files.map(file => (file.fileId === activeFile.fileId ? activeFile : file)); + const files = this.activeDossier?.files.map(file => (file.fileId === activeFile.fileId ? activeFile : file)); + const newDossier = new Dossier(this.activeDossier, files); + this._appState.dossiers = [...this._appState.dossiers.filter(d => d.dossierId !== newDossier.dossierId), newDossier]; this._computeStats(); if (activeFile.lastProcessed !== oldProcessedDate) { @@ -672,7 +674,7 @@ export class AppStateService { await this._userPreferenceService.saveLastOpenedFileForDossier(dossierId, fileId); } - private _getExistingFiles(dossierId: string): File[] { + private _getExistingFiles(dossierId: string): List { const dossier = this.allDossiers.find(p => p.id === dossierId); return dossier?.files ?? []; } @@ -717,7 +719,7 @@ export class AppStateService { } } - dossier.files = iFiles.map( + const files = iFiles.map( iFile => new File( iFile, @@ -725,6 +727,12 @@ export class AppStateService { this._fileAttributesService.getFileAttributeConfig(iFile.dossierTemplateId) ) ); + + const lastOpenedFileId = this._userPreferenceService.getLastOpenedFileForDossier(dossier.id); + files.forEach(file => (file.lastOpened = file.fileId === lastOpenedFileId)); + const newDossier = new Dossier(dossier, files); + this._appState.dossiers = [...this._appState.dossiers.filter(d => d.dossierId !== dossier.dossierId), newDossier]; + this._computeStats(); if (emitEvents) { @@ -732,11 +740,7 @@ export class AppStateService { fileChangedEvent.forEach(file => this.fileChanged$.next(file)); } - const lastOpenedFileId = this._userPreferenceService.getLastOpenedFileForDossier(dossier.id); - - dossier.files.forEach(file => (file.lastOpened = file.fileId === lastOpenedFileId)); - - return iFiles; + return files; } private _computeStats() { diff --git a/apps/red-ui/src/app/state/model/dossier.ts b/apps/red-ui/src/app/state/model/dossier.ts index e70dc6972..34acc5b0b 100644 --- a/apps/red-ui/src/app/state/model/dossier.ts +++ b/apps/red-ui/src/app/state/model/dossier.ts @@ -21,21 +21,20 @@ export class Dossier implements IDossier, IListable { readonly watermarkEnabled: boolean; readonly hasReviewers: boolean; - reanalysisRequired = this._files.some(file => file.analysisRequired); - hasFiles = this._files.length > 0; - filesLength = this._files.length; + readonly reanalysisRequired = this.files.some(file => file.analysisRequired); + readonly hasFiles = this.files.length > 0; + readonly filesLength = this.files.length; - totalNumberOfPages = 0; - hintsOnly?: boolean; - hasRedactions?: boolean; - hasSuggestions?: boolean; - hasNone?: boolean; - hasPendingOrProcessing?: boolean; + readonly totalNumberOfPages: number; + readonly hintsOnly: boolean; + readonly hasRedactions: boolean; + readonly hasSuggestions: boolean; + readonly hasNone: boolean; + readonly hasPendingOrProcessing: boolean; - allFilesApproved?: boolean; type?: IDictionary; - constructor(dossier: IDossier, private _files: File[] = []) { + constructor(dossier: IDossier, readonly files: List = []) { this.dossierId = dossier.dossierId; this.approverIds = dossier.approverIds; this.date = dossier.date; @@ -54,7 +53,26 @@ export class Dossier implements IDossier, IListable { this.watermarkEnabled = !!dossier.watermarkEnabled; this.hasReviewers = !!this.memberIds && this.memberIds.length > 1; - this._recomputeFileStatus(); + let hintsOnly = false; + let hasRedactions = false; + let hasSuggestions = false; + let totalNumberOfPages = 0; + let hasPendingOrProcessing = false; + + this.files.forEach(f => { + hintsOnly = hintsOnly || f.hintsOnly; + hasRedactions = hasRedactions || f.hasRedactions; + hasSuggestions = hasSuggestions || f.hasSuggestions; + totalNumberOfPages += f.numberOfPages ?? 0; + hasPendingOrProcessing = hasPendingOrProcessing || f.isPending || f.isProcessing; + }); + + this.hintsOnly = hintsOnly; + this.hasRedactions = hasRedactions; + this.hasSuggestions = hasSuggestions; + this.totalNumberOfPages = totalNumberOfPages; + this.hasPendingOrProcessing = hasPendingOrProcessing; + this.hasNone = !this.hasSuggestions && !this.hasRedactions && !this.hintsOnly; } get id(): string { @@ -69,42 +87,11 @@ export class Dossier implements IDossier, IListable { return this.dossierName; } - get files(): File[] { - return this._files; - } - - set files(files: File[]) { - this._files = files ? files : []; - this._recomputeFileStatus(); - } - hasStatus(status: string): boolean { - return !!this._files.find(f => f.status === status); + return !!this.files.find(f => f.status === status); } hasMember(memberId: string): boolean { return !!this.memberIds && this.memberIds.indexOf(memberId) >= 0; } - - private _recomputeFileStatus() { - this.hintsOnly = false; - this.hasRedactions = false; - this.hasSuggestions = false; - this.hasNone = false; - this.allFilesApproved = true; - this.totalNumberOfPages = 0; - this.hasPendingOrProcessing = false; - this._files.forEach(f => { - this.hintsOnly = this.hintsOnly || f.hintsOnly; - this.hasRedactions = this.hasRedactions || f.hasRedactions; - this.hasSuggestions = this.hasSuggestions || f.hasSuggestions; - this.allFilesApproved = this.allFilesApproved && f.isApproved; - this.totalNumberOfPages += f.numberOfPages ?? 0; - this.hasPendingOrProcessing = this.hasPendingOrProcessing || f.isPending || f.isProcessing; - }); - this.hasNone = !this.hasSuggestions && !this.hasRedactions && !this.hintsOnly; - this.hasFiles = this._files.length > 0; - this.filesLength = this._files.length; - this.reanalysisRequired = this._files.some(file => file.analysisRequired); - } } diff --git a/apps/red-ui/src/app/utils/functions.ts b/apps/red-ui/src/app/utils/functions.ts index 76285fc64..28d8757e9 100644 --- a/apps/red-ui/src/app/utils/functions.ts +++ b/apps/red-ui/src/app/utils/functions.ts @@ -1,8 +1,9 @@ import * as moment from 'moment'; +import { List } from '@iqser/common-ui'; export const FALLBACK_COLOR = '#CCCCCC'; -export function groupBy(xs: any[], key: string) { +export function groupBy(xs: List, key: string) { return xs.reduce((rv, x) => { (rv[x[key]] = rv[x[key]] || []).push(x); return rv; From 4ba75fea07ca2d2e8b05629d76e8ef54b6b87e79 Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Fri, 1 Oct 2021 13:19:18 +0300 Subject: [PATCH 04/14] remove dossier template id from file --- apps/red-ui/src/app/models/file/file.ts | 2 -- .../document-info/document-info.component.ts | 4 ++-- apps/red-ui/src/app/state/app-state.service.ts | 13 +++++-------- libs/red-ui-http/src/lib/model/file.ts | 4 ---- 4 files changed, 7 insertions(+), 16 deletions(-) diff --git a/apps/red-ui/src/app/models/file/file.ts b/apps/red-ui/src/app/models/file/file.ts index e4b788de4..88aac7a6d 100644 --- a/apps/red-ui/src/app/models/file/file.ts +++ b/apps/red-ui/src/app/models/file/file.ts @@ -42,7 +42,6 @@ export class File implements IFile, IListable { readonly uploader?: string; readonly excludedPages?: number[]; readonly hasSuggestions: boolean; - readonly dossierTemplateId?: string; primaryAttribute: string; lastOpened: boolean; @@ -95,7 +94,6 @@ export class File implements IFile, IListable { this.uploader = file.uploader; this.excludedPages = file.excludedPages; this.hasSuggestions = !!file.hasSuggestions; - this.dossierTemplateId = file.dossierTemplateId; this.statusSort = StatusSorter[this.status]; if (this.lastUpdated && this.lastOCRTime) { diff --git a/apps/red-ui/src/app/modules/dossier/components/document-info/document-info.component.ts b/apps/red-ui/src/app/modules/dossier/components/document-info/document-info.component.ts index f367b2ae8..785e0135a 100644 --- a/apps/red-ui/src/app/modules/dossier/components/document-info/document-info.component.ts +++ b/apps/red-ui/src/app/modules/dossier/components/document-info/document-info.component.ts @@ -34,10 +34,10 @@ export class DocumentInfoComponent extends AutoUnsubscribe implements OnInit { } ngOnInit(): void { - this.fileAttributesConfig = this._fileAttributesService.getFileAttributeConfig(this.file.dossierTemplateId); + this.fileAttributesConfig = this._fileAttributesService.getFileAttributeConfig(this.dossier.dossierTemplateId); this.addSubscription = this._appStateService.dossierTemplateChanged$.subscribe(() => { - this.fileAttributesConfig = this._fileAttributesService.getFileAttributeConfig(this.file.dossierTemplateId); + this.fileAttributesConfig = this._fileAttributesService.getFileAttributeConfig(this.dossier.dossierTemplateId); }); } diff --git a/apps/red-ui/src/app/state/app-state.service.ts b/apps/red-ui/src/app/state/app-state.service.ts index 63c013fb9..016324236 100644 --- a/apps/red-ui/src/app/state/app-state.service.ts +++ b/apps/red-ui/src/app/state/app-state.service.ts @@ -212,7 +212,7 @@ export class AppStateService { return this.getDossierById(dossierId)?.files.find(file => file.fileId === fileId); } - async loadAllDossiers(emitEvents: boolean = true) { + async loadAllDossiers(emitEvents = true) { const dossiers = await this._dossiersService.get().toPromise(); if (!dossiers) { return; @@ -237,14 +237,12 @@ export class AppStateService { return null; } const oldProcessedDate = this.activeFile.lastProcessed; - const dossierTemplateId = this.activeFile.dossierTemplateId; const iFile = await this._filesService.get(this.activeDossierId, this.activeFileId).toPromise(); - iFile.dossierTemplateId = dossierTemplateId; const activeFile = new File( iFile, this._userService.getNameForId(iFile.currentReviewer), - this._fileAttributesService.getFileAttributeConfig(iFile.dossierTemplateId) + this._fileAttributesService.getFileAttributeConfig(this.activeDossier?.dossierTemplateId) ); const files = this.activeDossier?.files.map(file => (file.fileId === activeFile.fileId ? activeFile : file)); const newDossier = new Dossier(this.activeDossier, files); @@ -687,7 +685,6 @@ export class AppStateService { for (const iFile of iFiles) { let found = false; - iFile.dossierTemplateId = dossier.dossierTemplateId; for (const oldFile of oldFiles) { if (oldFile.fileId === iFile.fileId) { @@ -695,7 +692,7 @@ export class AppStateService { const file = new File( iFile, this._userService.getNameForId(iFile.currentReviewer), - this._fileAttributesService.getFileAttributeConfig(iFile.dossierTemplateId) + this._fileAttributesService.getFileAttributeConfig(dossier.dossierTemplateId) ); file.lastOpened = file.fileId === this._userPreferenceService.getLastOpenedFileForDossier(dossier.id); if (JSON.stringify(oldFile) !== JSON.stringify(file)) { @@ -713,7 +710,7 @@ export class AppStateService { const file = new File( iFile, this._userService.getNameForId(iFile.currentReviewer), - this._fileAttributesService.getFileAttributeConfig(iFile.dossierTemplateId) + this._fileAttributesService.getFileAttributeConfig(dossier.dossierTemplateId) ); fileChangedEvent.push(file); } @@ -724,7 +721,7 @@ export class AppStateService { new File( iFile, this._userService.getNameForId(iFile.currentReviewer), - this._fileAttributesService.getFileAttributeConfig(iFile.dossierTemplateId) + this._fileAttributesService.getFileAttributeConfig(dossier.dossierTemplateId) ) ); diff --git a/libs/red-ui-http/src/lib/model/file.ts b/libs/red-ui-http/src/lib/model/file.ts index 82613b308..05093c593 100644 --- a/libs/red-ui-http/src/lib/model/file.ts +++ b/libs/red-ui-http/src/lib/model/file.ts @@ -51,10 +51,6 @@ export interface IFile { * The ID of the dossier the file belongs to. */ readonly dossierId: string; - /** - * The dossierTemplateId for this file. - */ - dossierTemplateId?: string; /** * Shows if the file was excluded from analysis. */ From eb4b8b0f1ed9a1310f551b8fa1b22b38663d7745 Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Fri, 1 Oct 2021 13:47:16 +0300 Subject: [PATCH 05/14] move stats to dossiers service --- apps/red-ui/src/app/models/file/file.ts | 4 +-- .../app/modules/dossier/dossiers.module.ts | 1 - .../dossiers-listing-details.component.html | 6 ++-- .../dossiers-listing-details.component.ts | 4 +-- .../dossier/services/dossiers.service.ts | 11 +++--- .../red-ui/src/app/state/app-state.service.ts | 35 +++---------------- 6 files changed, 18 insertions(+), 43 deletions(-) diff --git a/apps/red-ui/src/app/models/file/file.ts b/apps/red-ui/src/app/models/file/file.ts index 88aac7a6d..01c718e09 100644 --- a/apps/red-ui/src/app/models/file/file.ts +++ b/apps/red-ui/src/app/models/file/file.ts @@ -43,7 +43,7 @@ export class File implements IFile, IListable { readonly excludedPages?: number[]; readonly hasSuggestions: boolean; - primaryAttribute: string; + readonly primaryAttribute: string; lastOpened: boolean; readonly statusSort: number; readonly cacheIdentifier: string; @@ -61,7 +61,7 @@ export class File implements IFile, IListable { readonly isWorkable: boolean; readonly canBeOCRed: boolean; - constructor(file: IFile, public reviewerName: string, fileAttributesConfig?: FileAttributesConfig) { + constructor(file: IFile, readonly reviewerName: string, fileAttributesConfig?: FileAttributesConfig) { this.added = file.added; this.allManualRedactionsApplied = !!file.allManualRedactionsApplied; this.analysisDuration = file.analysisDuration; diff --git a/apps/red-ui/src/app/modules/dossier/dossiers.module.ts b/apps/red-ui/src/app/modules/dossier/dossiers.module.ts index c4b617945..dffaa52ad 100644 --- a/apps/red-ui/src/app/modules/dossier/dossiers.module.ts +++ b/apps/red-ui/src/app/modules/dossier/dossiers.module.ts @@ -80,7 +80,6 @@ const components = [ ]; const services = [ - DossiersService, DossiersDialogService, AnnotationActionsService, ManualAnnotationService, diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.html index 48847222d..8bcc76779 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.html @@ -6,11 +6,11 @@ [subtitle]="'dossier-listing.stats.charts.dossiers' | translate" > -
+
-
{{ appStateService.totalAnalysedPages | number }}
+
{{ stats.totalAnalyzedPages | number }}
@@ -18,7 +18,7 @@
-
{{ appStateService.totalPeople }}
+
{{ stats.totalPeople }}
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.ts b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.ts index dfaf1c60a..a8cc96cc8 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.ts @@ -1,7 +1,7 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; import { DoughnutChartConfig } from '@shared/components/simple-doughnut-chart/simple-doughnut-chart.component'; -import { AppStateService } from '@state/app-state.service'; import { FilterService } from '@iqser/common-ui'; +import { DossiersService } from '../../services/dossiers.service'; @Component({ selector: 'redaction-dossiers-listing-details', @@ -13,5 +13,5 @@ export class DossiersListingDetailsComponent { @Input() dossiersChartData: DoughnutChartConfig[]; @Input() documentsChartData: DoughnutChartConfig[]; - constructor(readonly appStateService: AppStateService, readonly filterService: FilterService) {} + constructor(readonly filterService: FilterService, readonly dossiersService: DossiersService) {} } diff --git a/apps/red-ui/src/app/modules/dossier/services/dossiers.service.ts b/apps/red-ui/src/app/modules/dossier/services/dossiers.service.ts index bb948ad79..d90bbf2f3 100644 --- a/apps/red-ui/src/app/modules/dossier/services/dossiers.service.ts +++ b/apps/red-ui/src/app/modules/dossier/services/dossiers.service.ts @@ -1,6 +1,6 @@ import { Injectable, Injector } from '@angular/core'; import { DossierRequest, IDossier } from '@redaction/red-ui-http'; -import { EntitiesService, List, QueryParam } from '@iqser/common-ui'; +import { EntitiesService, List, QueryParam, RequiredParam, Validate } from '@iqser/common-ui'; import { Dossier } from '@state/model/dossier'; import { filter, map } from 'rxjs/operators'; import { TEMPORARY_INJECTOR } from './injector'; @@ -56,7 +56,8 @@ export class DossiersService extends EntitiesService { return dossierId ? super._getOne([dossierId]) : super.getAll(); } - createOrUpdate(dossier: DossierRequest): Promise { + @Validate() + createOrUpdate(@RequiredParam() dossier: DossierRequest): Promise { return this._post(dossier).toPromise(); } @@ -64,11 +65,13 @@ export class DossiersService extends EntitiesService { return this.getAll('deleted-dossiers').toPromise(); } - restore(dossierIds: List): Promise { + @Validate() + restore(@RequiredParam() dossierIds: List): Promise { return this._post(dossierIds, 'deleted-dossiers/restore').toPromise(); } - hardDelete(dossierIds: List): Promise { + @Validate() + hardDelete(@RequiredParam() dossierIds: List): Promise { const body = dossierIds.map(id => ({ key: 'dossierId', value: id })); return this.delete(body, 'deleted-dossiers/hard-delete', body).toPromise(); } diff --git a/apps/red-ui/src/app/state/app-state.service.ts b/apps/red-ui/src/app/state/app-state.service.ts index 016324236..ccd6bc37e 100644 --- a/apps/red-ui/src/app/state/app-state.service.ts +++ b/apps/red-ui/src/app/state/app-state.service.ts @@ -26,8 +26,6 @@ export interface AppState { activeFileId?: string; activeDossierTemplateId?: string; activeDictionaryType?: string; - totalAnalysedPages?: number; - totalPeople?: number; } @Injectable({ @@ -134,14 +132,6 @@ export class AppStateService { return this._appState.activeFileId; } - get totalAnalysedPages(): number | undefined { - return this._appState.totalAnalysedPages; - } - - get totalPeople(): number | undefined { - return this._appState.totalPeople; - } - private static _isFileOverviewRoute(event: Event) { return event instanceof ResolveStart && event.url.includes('/main/dossiers/') && event.url.includes('/file/'); } @@ -227,9 +217,6 @@ export class AppStateService { this._processFiles(dossier, fileData[dossierId], emitEvents); } } - - this._appState.dossiers = mappedDossiers; - this._computeStats(); } async reloadActiveFile() { @@ -247,8 +234,8 @@ export class AppStateService { const files = this.activeDossier?.files.map(file => (file.fileId === activeFile.fileId ? activeFile : file)); const newDossier = new Dossier(this.activeDossier, files); this._appState.dossiers = [...this._appState.dossiers.filter(d => d.dossierId !== newDossier.dossierId), newDossier]; + this._dossiersService.setEntities(this._appState.dossiers); - this._computeStats(); if (activeFile.lastProcessed !== oldProcessedDate) { this.fileReanalysed$.next(activeFile); } @@ -338,6 +325,7 @@ export class AppStateService { () => { const index = this.allDossiers.findIndex(p => p.id === dossier.id); this._appState.dossiers.splice(index, 1); + this._dossiersService.setEntities(this._appState.dossiers); }, () => this._toaster.error(_('dossier-listing.delete.delete-failed'), { params: dossier }) ); @@ -355,6 +343,7 @@ export class AppStateService { } this._appState.dossiers.push(foundDossier); + this._dossiersService.setEntities(this._appState.dossiers); this.dossierChanged$.next(foundDossier); return foundDossier; } catch (error) { @@ -659,8 +648,6 @@ export class AppStateService { }) ); - console.log(dictionaryData); - return forkJoin([typeObs, colorsObs]).pipe(map(() => dictionaryData)); } @@ -729,8 +716,7 @@ export class AppStateService { files.forEach(file => (file.lastOpened = file.fileId === lastOpenedFileId)); const newDossier = new Dossier(dossier, files); this._appState.dossiers = [...this._appState.dossiers.filter(d => d.dossierId !== dossier.dossierId), newDossier]; - - this._computeStats(); + this._dossiersService.setEntities(this._appState.dossiers); if (emitEvents) { fileReanalysedEvent.forEach(file => this.fileReanalysed$.next(file)); @@ -739,17 +725,4 @@ export class AppStateService { return files; } - - private _computeStats() { - let totalAnalysedPages = 0; - const totalPeople = new Set(); - - this.allDossiers.forEach(d => { - d.memberIds?.forEach(m => totalPeople.add(m)); - totalAnalysedPages += d.totalNumberOfPages; - }); - - this._appState.totalPeople = totalPeople.size; - this._appState.totalAnalysedPages = totalAnalysedPages; - } } From 08d23a31186bd2fb00985af9a5475670d7d7404b Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Fri, 1 Oct 2021 14:54:09 +0300 Subject: [PATCH 06/14] move some methods to dossiers service --- .../notifications/notifications.component.ts | 6 ++-- .../confirm-delete-users-dialog.component.ts | 6 ++-- .../document-info/document-info.component.ts | 6 ++-- .../document-info-dialog.component.ts | 6 ++-- .../edit-dossier-dialog.component.ts | 4 ++- .../search-screen/search-screen.component.ts | 10 +++--- .../dossier/services/dossiers.service.ts | 12 +++++++ .../dictionary-manager.component.html | 2 +- .../dictionary-manager.component.ts | 8 ++--- .../src/app/services/permissions.service.ts | 11 ++++-- apps/red-ui/src/app/state/app-state.guard.ts | 6 ++-- .../red-ui/src/app/state/app-state.service.ts | 35 ++++++------------- 12 files changed, 60 insertions(+), 52 deletions(-) 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 841ea9b8c..66b7a888c 100644 --- a/apps/red-ui/src/app/components/notifications/notifications.component.ts +++ b/apps/red-ui/src/app/components/notifications/notifications.component.ts @@ -8,6 +8,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { UserService } from '@services/user.service'; import { NotificationType, NotificationTypeEnum } from '@models/notification-types'; import { notificationsTranslations } from '../../translations/notifications-translations'; +import { DossiersService } from '../../modules/dossier/services/dossiers.service'; @Component({ selector: 'redaction-notifications', @@ -23,6 +24,7 @@ export class NotificationsComponent { private readonly _userService: UserService, private readonly _notificationControllerService: NotificationControllerService, private readonly _appStateService: AppStateService, + private readonly _dossiersService: DossiersService, private readonly _datePipe: DatePipe ) { this._notificationControllerService.getNotifications(false).subscribe((response: NotificationResponse) => { @@ -96,12 +98,12 @@ export class NotificationsComponent { } private _getDossierName(dossierId: string | undefined) { - const dossier = this._appStateService.getDossierById(dossierId); + const dossier = this._dossiersService.find(dossierId); return dossier?.dossierName || this._translateService.instant(_('dossier')); } private _getFileName(dossierId: string | undefined, fileId: string | undefined) { - const file = this._appStateService.getFileById(dossierId, fileId); + const file = this._dossiersService.find(dossierId, fileId); return file?.filename || this._translateService.instant(_('file')); } diff --git a/apps/red-ui/src/app/modules/admin/dialogs/confirm-delete-users-dialog/confirm-delete-users-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/confirm-delete-users-dialog/confirm-delete-users-dialog.component.ts index bd63dad28..8f9c5eb26 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/confirm-delete-users-dialog/confirm-delete-users-dialog.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/confirm-delete-users-dialog/confirm-delete-users-dialog.component.ts @@ -1,10 +1,10 @@ import { Component, Inject } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { UserControllerService } from '@redaction/red-ui-http'; -import { AppStateService } from '@state/app-state.service'; import { LoadingService } from '@iqser/common-ui'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { User } from '@models/user'; +import { DossiersService } from '../../../dossier/services/dossiers.service'; @Component({ selector: 'redaction-confirm-delete-users-dialog', @@ -20,13 +20,13 @@ export class ConfirmDeleteUsersDialogComponent { dossiersCount: number; constructor( - private readonly _appStateService: AppStateService, + private readonly _dossiersService: DossiersService, private readonly _loadingService: LoadingService, private readonly _userControllerService: UserControllerService, readonly dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) readonly users: User[] ) { - this.dossiersCount = this._appStateService.allDossiers.filter(dw => { + this.dossiersCount = this._dossiersService.all.filter(dw => { for (const user of this.users) { if (dw.memberIds.indexOf(user.id) !== -1) { return true; diff --git a/apps/red-ui/src/app/modules/dossier/components/document-info/document-info.component.ts b/apps/red-ui/src/app/modules/dossier/components/document-info/document-info.component.ts index 785e0135a..0331901d1 100644 --- a/apps/red-ui/src/app/modules/dossier/components/document-info/document-info.component.ts +++ b/apps/red-ui/src/app/modules/dossier/components/document-info/document-info.component.ts @@ -5,6 +5,7 @@ import { DossiersDialogService } from '../../services/dossiers-dialog.service'; import { AutoUnsubscribe } from '@iqser/common-ui'; import { File } from '@models/file/file'; import { FileAttributesService } from '../../services/file-attributes.service'; +import { DossiersService } from '../../services/dossiers.service'; @Component({ selector: 'redaction-document-info', @@ -13,12 +14,13 @@ import { FileAttributesService } from '../../services/file-attributes.service'; }) export class DocumentInfoComponent extends AutoUnsubscribe implements OnInit { @Input() file: File; - @Output() closeDocumentInfoView = new EventEmitter(); + @Output() readonly closeDocumentInfoView = new EventEmitter(); fileAttributesConfig: FileAttributesConfig; constructor( private readonly _appStateService: AppStateService, + private readonly _dossiersService: DossiersService, private readonly _fileAttributesService: FileAttributesService, private readonly _dialogService: DossiersDialogService ) { @@ -26,7 +28,7 @@ export class DocumentInfoComponent extends AutoUnsubscribe implements OnInit { } get dossier() { - return this._appStateService.getDossierById(this.file.dossierId); + return this._dossiersService.find(this.file.dossierId); } get dossierTemplateName(): string { diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/document-info-dialog/document-info-dialog.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/document-info-dialog/document-info-dialog.component.ts index 9625d86c1..f00ca3baf 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/document-info-dialog/document-info-dialog.component.ts +++ b/apps/red-ui/src/app/modules/dossier/dialogs/document-info-dialog/document-info-dialog.component.ts @@ -5,6 +5,7 @@ import { AppStateService } from '@state/app-state.service'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Dossier } from '@state/model/dossier'; import { FileAttributesService } from '../../services/file-attributes.service'; +import { DossiersService } from '../../services/dossiers.service'; @Component({ templateUrl: './document-info-dialog.component.html', @@ -15,17 +16,18 @@ export class DocumentInfoDialogComponent implements OnInit { file: IFile; attributes: IFileAttributeConfig[]; - private _dossier: Dossier; + private readonly _dossier: Dossier; constructor( private readonly _appStateService: AppStateService, + private readonly _dossiersService: DossiersService, private readonly _formBuilder: FormBuilder, private readonly _fileAttributesService: FileAttributesService, public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: IFile ) { this.file = this.data; - this._dossier = this._appStateService.getDossierById(this.file.dossierId); + this._dossier = this._dossiersService.find(this.file.dossierId); } async ngOnInit() { diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/edit-dossier-dialog.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/edit-dossier-dialog.component.ts index 8090b67f0..438dce15b 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/edit-dossier-dialog.component.ts +++ b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/edit-dossier-dialog.component.ts @@ -12,6 +12,7 @@ import { EditDossierAttributesComponent } from './attributes/edit-dossier-attrib import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { EditDossierDeletedDocumentsComponent } from './deleted-documents/edit-dossier-deleted-documents.component'; import { AppStateService } from '@state/app-state.service'; +import { DossiersService } from '../../services/dossiers.service'; type Section = 'dossierInfo' | 'downloadPackage' | 'dossierDictionary' | 'members' | 'dossierAttributes' | 'deletedDocuments'; @@ -34,6 +35,7 @@ export class EditDossierDialogComponent { constructor( private readonly _toaster: Toaster, private readonly _appStateService: AppStateService, + private readonly _dossiersService: DossiersService, private readonly _changeRef: ChangeDetectorRef, @Inject(MAT_DIALOG_DATA) private readonly _data: { @@ -106,7 +108,7 @@ export class EditDossierDialogComponent { updatedDossier() { this._toaster.success(_('edit-dossier-dialog.change-successful'), { params: { dossierName: this.dossier.dossierName } }); - this.dossier = this._appStateService.getDossierById(this.dossier.id); + this.dossier = this._dossiersService.find(this.dossier.id); this._changeRef.detectChanges(); this.afterSave(); } diff --git a/apps/red-ui/src/app/modules/dossier/screens/search-screen/search-screen.component.ts b/apps/red-ui/src/app/modules/dossier/screens/search-screen/search-screen.component.ts index bba7db62b..0859f04fd 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/search-screen/search-screen.component.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/search-screen/search-screen.component.ts @@ -12,12 +12,12 @@ import { List, MatchedDocument, SearchControllerService, SearchResult } from '@r import { BehaviorSubject, Observable } from 'rxjs'; import { debounceTime, map, skip, switchMap, tap } from 'rxjs/operators'; import { ActivatedRoute, Router } from '@angular/router'; -import { AppStateService } from '@state/app-state.service'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { fileStatusTranslations } from '../../translations/file-status-translations'; import { SearchPositions } from '@shared/components/page-header/models/search-positions.type'; import { TranslateService } from '@ngx-translate/core'; import { RouterHistoryService } from '@services/router-history.service'; +import { DossiersService } from '../../services/dossiers.service'; interface ListItem extends IListable { readonly dossierId: string; @@ -65,7 +65,7 @@ export class SearchScreenComponent extends ListingComponent implements protected readonly _injector: Injector, private readonly _activatedRoute: ActivatedRoute, private readonly _loadingService: LoadingService, - private readonly _appStateService: AppStateService, + private readonly _dossiersService: DossiersService, readonly routerHistoryService: RouterHistoryService, private readonly _translateService: TranslateService, private readonly _searchControllerService: SearchControllerService @@ -77,7 +77,7 @@ export class SearchScreenComponent extends ListingComponent implements label: this._translateService.instant('search-screen.filters.by-dossier'), filterceptionPlaceholder: this._translateService.instant('search-screen.filters.search-placeholder'), icon: 'red:folder', - filters: this._appStateService.allDossiers.map( + filters: this._dossiersService.all.map( dossier => new NestedFilter({ id: dossier.id, @@ -135,7 +135,7 @@ export class SearchScreenComponent extends ListingComponent implements } private _toListItem({ dossierId, fileId, unmatchedTerms, highlights }: MatchedDocument): ListItem { - const file = this._appStateService.getFileById(dossierId, fileId); + const file = this._dossiersService.find(dossierId, fileId); if (!file) { return undefined; } @@ -147,7 +147,7 @@ export class SearchScreenComponent extends ListingComponent implements highlights, status: file.status, numberOfPages: file.numberOfPages, - dossierName: this._appStateService.getDossierById(dossierId).dossierName, + dossierName: this._dossiersService.find(dossierId).dossierName, filename: file.filename, searchKey: file.filename, routerLink: `/main/dossiers/${dossierId}/file/${fileId}` diff --git a/apps/red-ui/src/app/modules/dossier/services/dossiers.service.ts b/apps/red-ui/src/app/modules/dossier/services/dossiers.service.ts index d90bbf2f3..d07cfa696 100644 --- a/apps/red-ui/src/app/modules/dossier/services/dossiers.service.ts +++ b/apps/red-ui/src/app/modules/dossier/services/dossiers.service.ts @@ -7,6 +7,7 @@ import { TEMPORARY_INJECTOR } from './injector'; import { BehaviorSubject, Observable } from 'rxjs'; import { ActivationEnd, Router } from '@angular/router'; import { BaseScreenComponent } from '@components/base-screen/base-screen.component'; +import { File } from '@models/file/file'; export interface IDossiersStats { totalPeople: number; @@ -50,6 +51,17 @@ export class DossiersService extends EntitiesService { }); } + find(dossierId: string): Dossier | undefined; + find(dossierId: string, fileId: string): File | undefined; + find(dossierId: string, fileId?: string): Dossier | File | undefined { + const getDossier = () => this.all.find(dossier => dossier.dossierId === dossierId); + if (!fileId) { + return getDossier(); + } + + return getDossier().files.find(file => file.fileId === fileId); + } + get(): Observable; get(dossierId: string): Observable; get(dossierId?: string): Observable { diff --git a/apps/red-ui/src/app/modules/shared/components/dictionary-manager/dictionary-manager.component.html b/apps/red-ui/src/app/modules/shared/components/dictionary-manager/dictionary-manager.component.html index f5c16d073..5b097423b 100644 --- a/apps/red-ui/src/app/modules/shared/components/dictionary-manager/dictionary-manager.component.html +++ b/apps/red-ui/src/app/modules/shared/components/dictionary-manager/dictionary-manager.component.html @@ -33,7 +33,7 @@
{{ selectDossier.dossierName | translate }} - + {{ dossier.dossierName }} diff --git a/apps/red-ui/src/app/modules/shared/components/dictionary-manager/dictionary-manager.component.ts b/apps/red-ui/src/app/modules/shared/components/dictionary-manager/dictionary-manager.component.ts index 33bfc20ed..270dd1efe 100644 --- a/apps/red-ui/src/app/modules/shared/components/dictionary-manager/dictionary-manager.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/dictionary-manager/dictionary-manager.component.ts @@ -1,11 +1,11 @@ import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core'; -import { AppStateService } from '@state/app-state.service'; import { Debounce, IconButtonTypes, List } from '@iqser/common-ui'; import { Observable } from 'rxjs'; import { map, take } from 'rxjs/operators'; import { Dossier } from '@state/model/dossier'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { DictionaryService } from '@shared/services/dictionary.service'; +import { DossiersService } from '../../../dossier/services/dossiers.service'; import ICodeEditor = monaco.editor.ICodeEditor; import IDiffEditor = monaco.editor.IDiffEditor; import IModelDeltaDecoration = monaco.editor.IModelDeltaDecoration; @@ -44,7 +44,7 @@ export class DictionaryManagerComponent implements OnChanges, OnInit { private _decorations: string[] = []; private _searchDecorations: string[] = []; - constructor(private readonly _dictionaryService: DictionaryService, private readonly _appStateService: AppStateService) {} + constructor(private readonly _dictionaryService: DictionaryService, readonly dossiersService: DossiersService) {} private _dossier: Dossier = this.selectDossier as Dossier; @@ -72,10 +72,6 @@ export class DictionaryManagerComponent implements OnChanges, OnInit { }); } - get dossiers() { - return this._appStateService.allDossiers; - } - get editorValue(): string { return this.currentEntries.join('\n'); } diff --git a/apps/red-ui/src/app/services/permissions.service.ts b/apps/red-ui/src/app/services/permissions.service.ts index 02a6d9658..3832abb3e 100644 --- a/apps/red-ui/src/app/services/permissions.service.ts +++ b/apps/red-ui/src/app/services/permissions.service.ts @@ -4,12 +4,17 @@ import { UserService } from './user.service'; import { File } from '@models/file/file'; import { Comment } from '@redaction/red-ui-http'; import { Dossier } from '@state/model/dossier'; +import { DossiersService } from '../modules/dossier/services/dossiers.service'; @Injectable({ providedIn: 'root' }) export class PermissionsService { - constructor(private readonly _appStateService: AppStateService, private readonly _userService: UserService) {} + constructor( + private readonly _appStateService: AppStateService, + private readonly _userService: UserService, + private readonly _dossiersService: DossiersService + ) {} private get _activeFile(): File | undefined { return this._appStateService.activeFile; @@ -113,8 +118,8 @@ export class PermissionsService { return ['UNDER_REVIEW', 'UNDER_APPROVAL'].includes(file?.status) && this.isFileReviewer(file); } - canDownloadFiles(file = this._activeFile): boolean { - const dossier = this._appStateService.getDossierById(file?.dossierId); + canDownloadFiles(file: File): boolean { + const dossier = this._dossiersService.find(file?.dossierId); if (!dossier) { return false; } diff --git a/apps/red-ui/src/app/state/app-state.guard.ts b/apps/red-ui/src/app/state/app-state.guard.ts index 39c225494..113c461c2 100644 --- a/apps/red-ui/src/app/state/app-state.guard.ts +++ b/apps/red-ui/src/app/state/app-state.guard.ts @@ -2,6 +2,7 @@ import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router'; import { AppStateService } from './app-state.service'; import { UserService } from '@services/user.service'; +import { DossiersService } from '../modules/dossier/services/dossiers.service'; @Injectable({ providedIn: 'root' @@ -9,6 +10,7 @@ import { UserService } from '@services/user.service'; export class AppStateGuard implements CanActivate { constructor( private readonly _appStateService: AppStateService, + private readonly _dossiersService: DossiersService, private readonly _userService: UserService, private readonly _router: Router ) {} @@ -30,12 +32,12 @@ export class AppStateGuard implements CanActivate { const { dossierId, fileId, dossierTemplateId, type } = route.params; - if (dossierId && !this._appStateService.getDossierById(dossierId)) { + if (dossierId && !this._dossiersService.find(dossierId)) { await this._router.navigate(['main', 'dossiers']); return false; } - if (fileId && !this._appStateService.getFileById(dossierId, fileId)) { + if (fileId && !this._dossiersService.find(dossierId, fileId)) { await this._router.navigate(['main', 'dossiers', dossierId]); return false; } diff --git a/apps/red-ui/src/app/state/app-state.service.ts b/apps/red-ui/src/app/state/app-state.service.ts index ccd6bc37e..12cfe91de 100644 --- a/apps/red-ui/src/app/state/app-state.service.ts +++ b/apps/red-ui/src/app/state/app-state.service.ts @@ -80,7 +80,7 @@ export class AppStateService { } get aggregatedFiles(): File[] { - return this.allDossiers.reduce((acc, { files }) => [...acc, ...files], []); + return this._dossiersService.all.reduce((acc, { files }) => [...acc, ...files], []); } get activeDossierTemplateId(): string | undefined { @@ -113,15 +113,7 @@ export class AppStateService { } get activeDossier(): Dossier | undefined { - return this.allDossiers.find(p => p.id === this.activeDossierId); - } - - get allDossiers(): Dossier[] { - return this._appState.dossiers; - } - - get hasDossiers() { - return this.allDossiers?.length > 0; + return this._dossiersService.all.find(p => p.id === this.activeDossierId); } get activeFile(): File | undefined { @@ -194,14 +186,6 @@ export class AppStateService { return data ? data : this._dictionaryData[dossierTemplateId]['default']; } - getDossierById(id: string) { - return this.allDossiers.find(dossier => dossier.id === id); - } - - getFileById(dossierId: string, fileId: string) { - return this.getDossierById(dossierId)?.files.find(file => file.fileId === fileId); - } - async loadAllDossiers(emitEvents = true) { const dossiers = await this._dossiersService.get().toPromise(); if (!dossiers) { @@ -267,7 +251,7 @@ export class AppStateService { async updateDossierDictionary(dossierTemplateId: string, dossierId: string) { // dossier exists, load its dictionary - const dossier = this.getDossierById(dossierId); + const dossier = this._dossiersService.find(dossierId); try { dossier.type = await this._dictionaryService.getFor(dossierTemplateId, 'dossier_redaction', dossierId).toPromise(); } catch (e) { @@ -323,9 +307,10 @@ export class AppStateService { .toPromise() .then( () => { - const index = this.allDossiers.findIndex(p => p.id === dossier.id); - this._appState.dossiers.splice(index, 1); - this._dossiersService.setEntities(this._appState.dossiers); + const dossiers = this._dossiersService.all; + const index = dossiers.findIndex(p => p.id === dossier.id); + dossiers.splice(index, 1); + this._dossiersService.setEntities([...dossiers]); }, () => this._toaster.error(_('dossier-listing.delete.delete-failed'), { params: dossier }) ); @@ -334,7 +319,7 @@ export class AppStateService { async createOrUpdateDossier(dossier: DossierRequest) { try { const updatedDossier = await this._dossiersService.createOrUpdate(dossier); - let foundDossier = this.allDossiers.find(p => p.id === updatedDossier.dossierId); + let foundDossier = this._dossiersService.find(updatedDossier.dossierId); if (foundDossier) { this._appState.dossiers.splice(this._appState.dossiers.indexOf(foundDossier), 1); foundDossier = new Dossier(updatedDossier, foundDossier.files); @@ -389,7 +374,7 @@ export class AppStateService { } async loadAllDossiersIfNecessary() { - if (!this.allDossiers.length) { + if (!this._dossiersService.all.length) { await this.loadAllDossiers(); } } @@ -660,7 +645,7 @@ export class AppStateService { } private _getExistingFiles(dossierId: string): List { - const dossier = this.allDossiers.find(p => p.id === dossierId); + const dossier = this._dossiersService.find(dossierId); return dossier?.files ?? []; } From e32ee45d9cdf9971ce1aff4f874d2318efa84657 Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Fri, 1 Oct 2021 17:13:57 +0300 Subject: [PATCH 07/14] move active dossier to dossiers service --- .../base-screen/base-screen.component.html | 63 +++------ .../base-screen/base-screen.component.ts | 30 ++-- .../page-indicator.component.ts | 6 +- ...sign-reviewer-approver-dialog.component.ts | 10 +- .../change-legal-basis-dialog.component.ts | 4 +- .../edit-dossier-dictionary.component.ts | 12 +- .../force-redaction-dialog.component.ts | 6 +- .../manual-annotation-dialog.component.ts | 22 +-- .../dossier-details-stats.component.html | 116 ++++++++-------- .../dossier-details.component.html | 14 +- .../dossier-details.component.ts | 26 ++-- .../dossier-overview-screen.component.html | 7 +- .../file-preview-screen.component.html | 8 +- .../file-preview-screen.component.ts | 45 ++---- .../services/annotation-draw.service.ts | 4 +- .../dossier/services/dossiers.service.ts | 66 +++++++-- .../services/manual-annotation.service.ts | 10 +- .../services/pdf-viewer-data.service.ts | 6 +- .../file-actions/file-actions.component.html | 2 +- .../file-drop/file-drop.component.ts | 6 +- .../services/file-upload.service.ts | 4 +- .../src/app/services/permissions.service.ts | 8 +- .../red-ui/src/app/state/app-state.service.ts | 131 +++++------------- .../src/assets/styles/red-media-queries.scss | 15 -- apps/red-ui/src/assets/styles/red-theme.scss | 1 - 25 files changed, 285 insertions(+), 337 deletions(-) delete mode 100644 apps/red-ui/src/assets/styles/red-media-queries.scss diff --git a/apps/red-ui/src/app/components/base-screen/base-screen.component.html b/apps/red-ui/src/app/components/base-screen/base-screen.component.html index ab473f6c6..7a9ca807c 100644 --- a/apps/red-ui/src/app/components/base-screen/base-screen.component.html +++ b/apps/red-ui/src/app/components/base-screen/base-screen.component.html @@ -4,30 +4,7 @@
- - -