diff --git a/apps/red-ui/src/app/components/base-screen/base-screen.component.ts b/apps/red-ui/src/app/components/base-screen/base-screen.component.ts index e834bc426..1b1ad4387 100644 --- a/apps/red-ui/src/app/components/base-screen/base-screen.component.ts +++ b/apps/red-ui/src/app/components/base-screen/base-screen.component.ts @@ -64,7 +64,7 @@ export class BaseScreenComponent { text: this._translateService.instant('search.this-dossier'), icon: 'red:enter', hide: (): boolean => !this.appStateService.activeDossier, - action: (query): void => this._search(query, this.appStateService.activeDossier.dossierId) + action: (query): void => this._search(query, this.appStateService.activeDossier.id) }, { text: this._translateService.instant('search.entire-platform'), diff --git a/apps/red-ui/src/app/components/downloads-list-screen/downloads-list-screen.component.ts b/apps/red-ui/src/app/components/downloads-list-screen/downloads-list-screen.component.ts index dd7ed4d72..41207582a 100644 --- a/apps/red-ui/src/app/components/downloads-list-screen/downloads-list-screen.component.ts +++ b/apps/red-ui/src/app/components/downloads-list-screen/downloads-list-screen.component.ts @@ -21,7 +21,6 @@ export class DownloadsListScreenComponent extends ListingComponent; @ViewChild('creationDateTemplate', { static: true }) creationDateTemplate: TemplateRef; @ViewChild('statusTemplate', { static: true }) statusTemplate: TemplateRef; - protected readonly _primaryKey = 'storageId'; constructor( protected readonly _injector: Injector, 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 f14207327..000000000 --- a/apps/red-ui/src/app/models/audit-model-wrapper.model.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { AuditModel } from '@redaction/red-ui-http'; -import { Listable } from '@iqser/common-ui'; - -export class AuditModelWrapper implements Listable { - constructor(public auditModel: AuditModel) {} - - get category(): string { - return this.auditModel.category; - } - - get details(): any { - return this.auditModel.details; - } - - get message(): string { - return this.auditModel.message; - } - - get recordId(): string { - return this.auditModel.recordId; - } - - get recordDate(): string { - return this.auditModel.recordDate; - } - - get objectId(): string { - return this.auditModel.objectId; - } - - get userId(): string { - return this.auditModel.userId; - } - - get id() { - return this.auditModel.recordDate; - } -} diff --git a/apps/red-ui/src/app/models/audit.model.ts b/apps/red-ui/src/app/models/audit.model.ts new file mode 100644 index 000000000..3fab0969d --- /dev/null +++ b/apps/red-ui/src/app/models/audit.model.ts @@ -0,0 +1,30 @@ +import { IAudit } from '@redaction/red-ui-http'; +import { IListable } from '@iqser/common-ui'; + +export class Audit implements IAudit, IListable { + readonly category?: string; + readonly details?: unknown; + readonly message?: string; + readonly objectId?: string; + readonly recordDate?: string; + readonly recordId?: string; + readonly userId?: string; + + constructor(audit: IAudit) { + this.category = audit.category; + this.details = audit.details; + this.message = audit.message; + this.objectId = audit.objectId; + this.recordDate = audit.recordDate; + this.recordId = audit.recordId; + this.userId = audit.userId; + } + + get id() { + return this.recordDate; + } + + get searchKey(): string { + return this.recordDate; + } +} diff --git a/apps/red-ui/src/app/models/dictionary.ts b/apps/red-ui/src/app/models/dictionary.ts new file mode 100644 index 000000000..bae65a716 --- /dev/null +++ b/apps/red-ui/src/app/models/dictionary.ts @@ -0,0 +1,36 @@ +import { IDictionary } from '@redaction/red-ui-http'; +import { IListable, List } from '@iqser/common-ui'; + +export class Dictionary implements IDictionary, IListable { + readonly addToDictionaryAction: boolean; + readonly caseInsensitive: boolean; + readonly description?: string; + readonly dossierTemplateId?: string; + readonly entries?: List; + readonly hexColor?: string; + readonly hint: boolean; + readonly label?: string; + readonly rank?: number; + readonly recommendation: boolean; + + constructor(dictionary: IDictionary) { + this.addToDictionaryAction = !!dictionary.addToDictionaryAction; + this.caseInsensitive = !!dictionary.caseInsensitive; + this.description = dictionary.description; + this.dossierTemplateId = dictionary.dossierTemplateId; + this.entries = dictionary.entries; + this.hexColor = dictionary.hexColor; + this.hint = !!dictionary.hint; + this.label = dictionary.label; + this.rank = dictionary.rank; + this.recommendation = !!dictionary.recommendation; + } + + get id(): string { + return this.label; + } + + get searchKey(): string { + return this.label; + } +} diff --git a/apps/red-ui/src/app/models/dossier-attributes.model.ts b/apps/red-ui/src/app/models/dossier-attributes.model.ts index 59b49755e..cf99a25cc 100644 --- a/apps/red-ui/src/app/models/dossier-attributes.model.ts +++ b/apps/red-ui/src/app/models/dossier-attributes.model.ts @@ -1,3 +1,3 @@ -import { DossierAttributeConfig } from '@redaction/red-ui-http'; +import { IDossierAttributeConfig } from '@redaction/red-ui-http'; -export type DossierAttributeWithValue = DossierAttributeConfig & { value: any }; +export type DossierAttributeWithValue = IDossierAttributeConfig & { value: any }; diff --git a/apps/red-ui/src/app/models/file/annotation.permissions.ts b/apps/red-ui/src/app/models/file/annotation.permissions.ts index 431ad80da..e8bdc1fd0 100644 --- a/apps/red-ui/src/app/models/file/annotation.permissions.ts +++ b/apps/red-ui/src/app/models/file/annotation.permissions.ts @@ -1,6 +1,6 @@ -import { UserWrapper } from '@services/user.service'; import { AnnotationWrapper } from './annotation.wrapper'; import { isArray } from 'rxjs/internal-compatibility'; +import { User } from '@models/user'; export class AnnotationPermissions { canUndo = true; @@ -14,7 +14,7 @@ export class AnnotationPermissions { canChangeLegalBasis = true; canRecategorizeImage = true; - static forUser(isApprover: boolean, user: UserWrapper, annotations: AnnotationWrapper | AnnotationWrapper[]) { + static forUser(isApprover: boolean, user: User, annotations: AnnotationWrapper | AnnotationWrapper[]) { if (!isArray(annotations)) { annotations = [annotations]; } diff --git a/apps/red-ui/src/app/models/file/dossier-template-model.wrapper.ts b/apps/red-ui/src/app/models/file/dossier-template-model.wrapper.ts deleted file mode 100644 index 7c751350b..000000000 --- a/apps/red-ui/src/app/models/file/dossier-template-model.wrapper.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { DossierTemplateModel, FileAttributesConfig } from '@redaction/red-ui-http'; -import { Listable } from '@iqser/common-ui'; - -export class DossierTemplateModelWrapper implements Listable { - dictionariesCount = 0; - totalDictionaryEntries = 0; - - constructor(public dossierTemplateModel: DossierTemplateModel, public fileAttributesConfig: FileAttributesConfig) {} - - get id() { - return this.dossierTemplateModel.dossierTemplateId; - } - - get createdBy() { - return this.dossierTemplateModel.createdBy; - } - - get dateAdded() { - return this.dossierTemplateModel.dateAdded; - } - - get dateModified() { - return this.dossierTemplateModel.dateModified; - } - - get description() { - return this.dossierTemplateModel.description; - } - - get dossierTemplateId() { - return this.dossierTemplateModel.dossierTemplateId; - } - - get downloadFileTypes() { - return this.dossierTemplateModel.downloadFileTypes; - } - - get modifiedBy() { - return this.dossierTemplateModel.modifiedBy; - } - - get name() { - return this.dossierTemplateModel.name; - } - - get reportTemplateIds() { - return this.dossierTemplateModel.reportTemplateIds; - } - - get validFrom() { - return this.dossierTemplateModel.validFrom; - } - - get validTo() { - return this.dossierTemplateModel.validTo; - } -} diff --git a/apps/red-ui/src/app/models/file/dossier-template.ts b/apps/red-ui/src/app/models/file/dossier-template.ts new file mode 100644 index 000000000..265d29d5f --- /dev/null +++ b/apps/red-ui/src/app/models/file/dossier-template.ts @@ -0,0 +1,44 @@ +import { DownloadFileType, FileAttributesConfig, IDossierTemplate, List } from '@redaction/red-ui-http'; +import { IListable } from '@iqser/common-ui'; + +export class DossierTemplate implements IDossierTemplate, IListable { + readonly createdBy?: string; + readonly dateAdded?: string; + readonly dateModified?: string; + readonly description?: string; + readonly dossierTemplateId?: string; + readonly downloadFileTypes?: List; + readonly modifiedBy?: string; + readonly name?: string; + readonly reportTemplateIds?: List; + readonly validFrom?: string; + readonly validTo?: string; + dictionariesCount = 0; + totalDictionaryEntries = 0; + + constructor(dossierTemplate: IDossierTemplate, public fileAttributesConfig: FileAttributesConfig) { + this.createdBy = dossierTemplate.createdBy; + this.dateAdded = dossierTemplate.dateAdded; + this.dateModified = dossierTemplate.dateModified; + this.description = dossierTemplate.description; + this.dossierTemplateId = dossierTemplate.dossierTemplateId; + this.downloadFileTypes = dossierTemplate.downloadFileTypes; + this.modifiedBy = dossierTemplate.modifiedBy; + this.name = dossierTemplate.name; + this.reportTemplateIds = dossierTemplate.reportTemplateIds; + this.validFrom = dossierTemplate.validFrom; + this.validTo = dossierTemplate.validTo; + } + + get id(): string { + return this.dossierTemplateId; + } + + get searchKey(): string { + return this.name; + } + + get routerLink(): string { + return `/main/admin/dossier-templates/${this.dossierTemplateId}/dictionaries`; + } +} diff --git a/apps/red-ui/src/app/models/file/file-attribute-config.ts b/apps/red-ui/src/app/models/file/file-attribute-config.ts new file mode 100644 index 000000000..1b61ac423 --- /dev/null +++ b/apps/red-ui/src/app/models/file/file-attribute-config.ts @@ -0,0 +1,30 @@ +import { FileAttributeConfigType, IFileAttributeConfig } from '@redaction/red-ui-http'; +import { IListable } from '@iqser/common-ui'; + +export class FileAttributeConfig implements IFileAttributeConfig, IListable { + readonly id: string; + readonly csvColumnHeader?: string; + readonly editable?: boolean; + readonly label?: string; + readonly placeholder?: string; + readonly primaryAttribute?: boolean; + readonly displayedInFileList?: boolean; + readonly filterable?: boolean; + readonly type?: FileAttributeConfigType; + + constructor(fileAttributeConfig: IFileAttributeConfig) { + this.id = fileAttributeConfig.id; + this.csvColumnHeader = fileAttributeConfig.csvColumnHeader; + this.editable = !!fileAttributeConfig.editable; + this.label = fileAttributeConfig.label; + this.placeholder = fileAttributeConfig.placeholder; + this.primaryAttribute = fileAttributeConfig.primaryAttribute; + this.displayedInFileList = fileAttributeConfig.displayedInFileList; + this.filterable = !!fileAttributeConfig.filterable; + this.type = fileAttributeConfig.type; + } + + get searchKey(): string { + return this.label; + } +} diff --git a/apps/red-ui/src/app/models/file/file-data.model.ts b/apps/red-ui/src/app/models/file/file-data.model.ts index 036d91ad1..8644abaf0 100644 --- a/apps/red-ui/src/app/models/file/file-data.model.ts +++ b/apps/red-ui/src/app/models/file/file-data.model.ts @@ -1,10 +1,10 @@ import { RedactionChangeLog, RedactionLog, ViewedPages } from '@redaction/red-ui-http'; -import { FileStatusWrapper } from './file-status.wrapper'; -import { UserWrapper } from '@services/user.service'; +import { File } from './file'; import { AnnotationWrapper } from './annotation.wrapper'; import { RedactionLogEntryWrapper } from './redaction-log-entry.wrapper'; import { ViewMode } from './view-mode'; -import { TypeValueWrapper } from './type-value.wrapper'; +import { TypeValue } from './type-value'; +import { User } from '@models/user'; export class AnnotationData { visibleAnnotations: AnnotationWrapper[]; @@ -13,7 +13,7 @@ export class AnnotationData { export class FileDataModel { constructor( - public fileStatus: FileStatusWrapper, + public file: File, public fileData: Blob, public redactionLog: RedactionLog, public redactionChangeLog: RedactionChangeLog, @@ -21,15 +21,15 @@ export class FileDataModel { ) {} getAnnotations( - dictionaryData: { [p: string]: TypeValueWrapper }, - currentUser: UserWrapper, + dictionaryData: { [p: string]: TypeValue }, + currentUser: User, viewMode: ViewMode, areDevFeaturesEnabled: boolean ): AnnotationData { const entries: RedactionLogEntryWrapper[] = this._convertData(); let allAnnotations = entries .map(entry => AnnotationWrapper.fromData(entry)) - .filter(ann => !this.fileStatus.excludedPages.includes(ann.pageNumber)); + .filter(ann => !this.file.excludedPages.includes(ann.pageNumber)); if (!areDevFeaturesEnabled) { allAnnotations = allAnnotations.filter(annotation => !annotation.isFalsePositive); diff --git a/apps/red-ui/src/app/models/file/file-status.wrapper.ts b/apps/red-ui/src/app/models/file/file-status.wrapper.ts deleted file mode 100644 index 7caf8e6d7..000000000 --- a/apps/red-ui/src/app/models/file/file-status.wrapper.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { Listable } from '@iqser/common-ui'; -import { FileAttributesConfig, FileStatus } from '@redaction/red-ui-http'; -import { StatusSorter } from '@utils/sorters/status-sorter'; - -const processingStatuses = [ - FileStatus.StatusEnum.REPROCESS, - FileStatus.StatusEnum.FULLREPROCESS, - FileStatus.StatusEnum.OCRPROCESSING, - FileStatus.StatusEnum.INDEXING, - FileStatus.StatusEnum.PROCESSING -] as const; - -export class FileStatusWrapper implements FileStatus, Listable { - readonly added = this.fileStatus.added; - readonly allManualRedactionsApplied = this.fileStatus.allManualRedactionsApplied; - readonly analysisDuration = this.fileStatus.analysisDuration; - readonly analysisRequired = this.fileStatus.analysisRequired && !this.fileStatus.excluded; - readonly approvalDate = this.fileStatus.approvalDate; - readonly currentReviewer = this.fileStatus.currentReviewer; - readonly dictionaryVersion = this.fileStatus.dictionaryVersion; - readonly dossierDictionaryVersion = this.fileStatus.dossierDictionaryVersion; - readonly dossierId = this.fileStatus.dossierId; - readonly excluded = this.fileStatus.excluded; - readonly fileAttributes = this.fileStatus.fileAttributes; - readonly fileId = this.fileStatus.fileId; - readonly filename = this.fileStatus.filename; - readonly hasAnnotationComments = this.fileStatus.hasAnnotationComments; - readonly hasHints = this.fileStatus.hasHints; - readonly hasImages = this.fileStatus.hasImages; - readonly hasRedactions = this.fileStatus.hasRedactions; - readonly hasUpdates = this.fileStatus.hasUpdates; - readonly lastOCRTime = this.fileStatus.lastOCRTime; - readonly lastProcessed = this.fileStatus.lastProcessed; - readonly lastReviewer = this.fileStatus.lastReviewer; - readonly lastUpdated = this.fileStatus.lastUpdated; - readonly lastUploaded = this.fileStatus.lastUploaded; - readonly legalBasisVersion = this.fileStatus.legalBasisVersion; - readonly numberOfAnalyses = this.fileStatus.numberOfAnalyses; - readonly numberOfPages = this.fileStatus.numberOfPages; - readonly rulesVersion = this.fileStatus.rulesVersion; - readonly status = this._status; - readonly uploader = this.fileStatus.uploader; - readonly excludedPages = this.fileStatus.excludedPages; - readonly hasSuggestions = this.fileStatus.hasSuggestions; - readonly dossierTemplateId = this.fileStatus.dossierTemplateId; - - primaryAttribute: string; - lastOpened: boolean; - - constructor(readonly fileStatus: FileStatus, public reviewerName: string, fileAttributesConfig?: FileAttributesConfig) { - if (fileAttributesConfig) { - const primary = fileAttributesConfig.fileAttributeConfigs?.find(c => c.primaryAttribute); - if (primary && fileStatus.fileAttributes?.attributeIdToValue) { - this.primaryAttribute = fileStatus.fileAttributes?.attributeIdToValue[primary.id]; - } - - if (!this.primaryAttribute) { - // Fallback here - this.primaryAttribute = '-'; - } - } - if (!this.fileAttributes || !this.fileAttributes.attributeIdToValue) { - this.fileAttributes = { attributeIdToValue: {} }; - } - } - - readonly excludedPagesCount = this.excludedPages?.length ?? 0; - readonly statusSort = StatusSorter[this.status]; - readonly pages = this._pages; - readonly cacheIdentifier = btoa(this.lastUploaded + this.lastOCRTime); - - readonly hintsOnly = this.hasHints && !this.hasRedactions; - readonly hasNone = !this.hasRedactions && !this.hasHints && !this.hasSuggestions; - - readonly isUnassigned = !this.currentReviewer; - readonly isError = this.status === FileStatus.StatusEnum.ERROR; - readonly isProcessing = processingStatuses.includes(this.status); - readonly isApproved = this.status === FileStatus.StatusEnum.APPROVED; - readonly isPending = this.status === FileStatus.StatusEnum.UNPROCESSED; - readonly isUnderReview = this.status === FileStatus.StatusEnum.UNDERREVIEW; - readonly isUnderApproval = this.status === FileStatus.StatusEnum.UNDERAPPROVAL; - readonly canBeApproved = !this.analysisRequired && !this.hasSuggestions; - readonly canBeOpened = !this.isError && !this.isPending; - readonly isWorkable = !this.isProcessing && this.canBeOpened; - readonly canBeOCRed = !this.excluded && !this.lastOCRTime && ['UNASSIGNED', 'UNDER_REVIEW', 'UNDER_APPROVAL'].includes(this.status); - - get id() { - return this.fileId; - } - - private get _pages() { - if (this.fileStatus.status === 'ERROR') { - return -1; - } - return this.fileStatus.numberOfPages ? this.fileStatus.numberOfPages : 0; - } - - private get _status(): FileStatus.StatusEnum { - return this.fileStatus.status === FileStatus.StatusEnum.REPROCESS || this.fileStatus.status === FileStatus.StatusEnum.FULLREPROCESS - ? FileStatus.StatusEnum.PROCESSING - : this.fileStatus.status; - } -} diff --git a/apps/red-ui/src/app/models/file/file.ts b/apps/red-ui/src/app/models/file/file.ts new file mode 100644 index 000000000..830e19487 --- /dev/null +++ b/apps/red-ui/src/app/models/file/file.ts @@ -0,0 +1,142 @@ +import { IListable } from '@iqser/common-ui'; +import { FileAttributes, FileAttributesConfig, FileStatus, FileStatuses, IFile, List } from '@redaction/red-ui-http'; +import { StatusSorter } from '@utils/sorters/status-sorter'; + +const processingStatuses: List = [ + FileStatuses.REPROCESS, + FileStatuses.FULLREPROCESS, + FileStatuses.OCR_PROCESSING, + FileStatuses.INDEXING, + FileStatuses.PROCESSING +] as const; + +export class File implements IFile, IListable { + readonly added: string; + readonly allManualRedactionsApplied: boolean; + readonly analysisDuration: number; + readonly analysisRequired: boolean; + readonly approvalDate: string; + readonly currentReviewer: string; + readonly dictionaryVersion: number; + readonly dossierDictionaryVersion: number; + readonly dossierId: string; + readonly excluded: boolean; + readonly fileAttributes: FileAttributes; + readonly fileId: string; + readonly filename: string; + readonly hasAnnotationComments: boolean; + readonly hasHints: boolean; + 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 status: FileStatus; + readonly uploader: string; + readonly excludedPages: number[]; + readonly hasSuggestions: boolean; + readonly dossierTemplateId: string; + + primaryAttribute: string; + lastOpened: boolean; + readonly statusSort: number; + readonly cacheIdentifier: string; + readonly hintsOnly: boolean; + readonly hasNone: boolean; + readonly isUnassigned: boolean; + readonly isError: boolean; + readonly isProcessing: boolean; + readonly isApproved: boolean; + readonly isPending: boolean; + readonly isUnderReview: boolean; + readonly isUnderApproval: boolean; + readonly canBeApproved: boolean; + readonly canBeOpened: boolean; + readonly isWorkable: boolean; + readonly canBeOCRed: boolean; + + constructor(file: IFile, public reviewerName: string, fileAttributesConfig?: FileAttributesConfig) { + this.added = file.added; + this.allManualRedactionsApplied = file.allManualRedactionsApplied; + this.analysisDuration = file.analysisDuration; + 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.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.lastOCRTime = file.lastOCRTime; + this.lastProcessed = file.lastProcessed; + this.lastReviewer = file.lastReviewer; + this.lastUpdated = file.lastUpdated; + this.lastUploaded = file.lastUploaded; + this.legalBasisVersion = file.legalBasisVersion; + this.numberOfAnalyses = file.numberOfAnalyses; + this.status = ['REPROCESS', 'FULLREPROCESS'].includes(file.status) ? FileStatuses.PROCESSING : file.status; + this.isError = this.status === FileStatuses.ERROR; + this.numberOfPages = this.isError ? -1 : file.numberOfPages ?? 0; + this.rulesVersion = file.rulesVersion; + this.uploader = file.uploader; + this.excludedPages = file.excludedPages; + this.hasSuggestions = file.hasSuggestions; + this.dossierTemplateId = file.dossierTemplateId; + + this.statusSort = StatusSorter[this.status]; + 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; + this.isProcessing = processingStatuses.includes(this.status); + this.isApproved = this.status === FileStatuses.APPROVED; + this.isPending = this.status === FileStatuses.UNPROCESSED; + this.isUnderReview = this.status === FileStatuses.UNDER_REVIEW; + this.isUnderApproval = this.status === FileStatuses.UNDER_APPROVAL; + this.canBeApproved = !this.analysisRequired && !this.hasSuggestions; + this.canBeOpened = !this.isError && !this.isPending; + this.isWorkable = !this.isProcessing && this.canBeOpened; + this.canBeOCRed = !this.excluded && !this.lastOCRTime && ['UNASSIGNED', 'UNDER_REVIEW', 'UNDER_APPROVAL'].includes(this.status); + + if (fileAttributesConfig) { + const primary = fileAttributesConfig.fileAttributeConfigs?.find(c => c.primaryAttribute); + if (primary && file.fileAttributes?.attributeIdToValue) { + this.primaryAttribute = file.fileAttributes?.attributeIdToValue[primary.id]; + } + + if (!this.primaryAttribute) { + // Fallback here + this.primaryAttribute = '-'; + } + } + if (!this.fileAttributes || !this.fileAttributes.attributeIdToValue) { + this.fileAttributes = { attributeIdToValue: {} }; + } + } + + get id(): string { + return this.fileId; + } + + get searchKey(): string { + return this.filename; + } + + get routerLink(): string | undefined { + return this.canBeOpened ? `/main/dossiers/${this.dossierId}/file/${this.fileId}` : undefined; + } +} diff --git a/apps/red-ui/src/app/models/file/type-value.ts b/apps/red-ui/src/app/models/file/type-value.ts new file mode 100644 index 000000000..d9c3a5b04 --- /dev/null +++ b/apps/red-ui/src/app/models/file/type-value.ts @@ -0,0 +1,41 @@ +import { IListable } from '@iqser/common-ui'; +import { ITypeValue } from '@redaction/red-ui-http'; + +export class TypeValue implements ITypeValue, IListable { + readonly type: string; + readonly addToDictionaryAction: boolean; + readonly caseInsensitive: boolean; + readonly description?: string; + readonly dossierTemplateId?: string; + readonly hexColor?: string; + readonly label?: string; + readonly hint: boolean; + readonly rank?: number; + readonly recommendation: boolean; + entries: string[] = []; + + constructor(typeValue: ITypeValue, readonly virtual = false) { + this.type = typeValue.type; + this.addToDictionaryAction = !!typeValue.addToDictionaryAction; + this.caseInsensitive = !!typeValue.caseInsensitive; + this.description = typeValue.description; + this.dossierTemplateId = typeValue.dossierTemplateId; + this.hexColor = typeValue.hexColor; + this.hint = !!typeValue.hint; + this.rank = typeValue.rank; + this.recommendation = !!typeValue.recommendation; + this.label = typeValue.label; + } + + get id(): string { + return this.type; + } + + get searchKey(): string { + return this.type; + } + + get routerLink(): string { + return `/main/admin/dossier-templates/${this.dossierTemplateId}/dictionaries/${this.type}`; + } +} diff --git a/apps/red-ui/src/app/models/file/type-value.wrapper.ts b/apps/red-ui/src/app/models/file/type-value.wrapper.ts deleted file mode 100644 index ae93d08ab..000000000 --- a/apps/red-ui/src/app/models/file/type-value.wrapper.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { Listable } from '@iqser/common-ui'; -import { TypeValue } from '@redaction/red-ui-http'; - -export class TypeValueWrapper implements Listable { - entries: string[] = []; - - constructor(public typeValue: TypeValue, public label?: string, public virtual?: boolean) { - this.label = label || typeValue.label; - } - - get id() { - return this.typeValue.type; - } - - get addToDictionaryAction() { - return this.typeValue.addToDictionaryAction; - } - - get caseInsensitive() { - return this.typeValue.caseInsensitive; - } - - get description() { - return this.typeValue.description; - } - - get dossierTemplateId() { - return this.typeValue.dossierTemplateId; - } - - get hexColor() { - return this.typeValue.hexColor; - } - - get hint() { - return this.typeValue.hint; - } - - get rank() { - return this.typeValue.rank; - } - - get recommendation() { - return this.typeValue.recommendation; - } - - get type() { - return this.typeValue.type; - } -} diff --git a/apps/red-ui/src/app/models/user.ts b/apps/red-ui/src/app/models/user.ts new file mode 100644 index 000000000..24bb45dd4 --- /dev/null +++ b/apps/red-ui/src/app/models/user.ts @@ -0,0 +1,28 @@ +import { IUser, List } from '@redaction/red-ui-http'; +import { IListable } from '@iqser/common-ui'; +import { KeycloakProfile } from 'keycloak-js'; + +export class User implements IUser, IListable { + readonly email: string; + readonly username: string; + readonly firstName: string; + readonly lastName: string; + readonly name: string; + readonly searchKey: string; + + readonly isActive = this.roles.length > 0; + readonly isManager = this.roles.indexOf('RED_MANAGER') >= 0; + readonly isUserAdmin = this.roles.indexOf('RED_USER_ADMIN') >= 0; + readonly isUser = this.roles.indexOf('RED_USER') >= 0; + readonly isAdmin = this.roles.indexOf('RED_ADMIN') >= 0; + readonly hasAnyREDRoles = this.isUser || this.isManager || this.isAdmin || this.isUserAdmin; + + constructor(user: KeycloakProfile | IUser, readonly roles: List, readonly id: string) { + this.email = user.email; + this.username = user.username || this.email; + this.firstName = user.firstName; + this.lastName = user.lastName; + this.name = this.firstName && this.lastName ? `${this.firstName} ${this.lastName}` : this.username; + this.searchKey = this.name + this.username + this.email; + } +} diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dictionary-dialog/add-edit-dictionary-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dictionary-dialog/add-edit-dictionary-dialog.component.ts index 8ca6130a2..7814a4b95 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dictionary-dialog/add-edit-dictionary-dialog.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dictionary-dialog/add-edit-dictionary-dialog.component.ts @@ -1,14 +1,15 @@ import { Component, Inject } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { DictionaryControllerService, TypeValue } from '@redaction/red-ui-http'; +import { ITypeValue } from '@redaction/red-ui-http'; import { Observable } from 'rxjs'; import { Toaster } from '@iqser/common-ui'; import { TranslateService } from '@ngx-translate/core'; -import { TypeValueWrapper } from '@models/file/type-value.wrapper'; +import { TypeValue } from '@models/file/type-value'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { AppStateService } from '@state/app-state.service'; import { toKebabCase } from '@utils/functions'; +import { DictionaryService } from '@shared/services/dictionary.service'; @Component({ selector: 'redaction-add-edit-dictionary-dialog', @@ -17,19 +18,19 @@ import { toKebabCase } from '@utils/functions'; }) export class AddEditDictionaryDialogComponent { dictionaryForm: FormGroup; - readonly dictionary: TypeValueWrapper; + readonly dictionary: TypeValue; technicalName = ''; private readonly _dossierTemplateId: string; constructor( - private readonly _dictionaryControllerService: DictionaryControllerService, + private readonly _dictionaryService: DictionaryService, private readonly _appStateService: AppStateService, private readonly _formBuilder: FormBuilder, private readonly _toaster: Toaster, private readonly _translateService: TranslateService, private readonly _dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) - private readonly _data: { dictionary: TypeValueWrapper; dossierTemplateId: string } + private readonly _data: { dictionary: TypeValue; dossierTemplateId: string } ) { this.dictionary = _data.dictionary; this._dossierTemplateId = _data.dossierTemplateId; @@ -81,17 +82,16 @@ export class AddEditDictionaryDialogComponent { return false; } - async saveDictionary() { - const typeValue: TypeValue = this._formToObject(); - let observable: Observable; + async saveDictionary(): Promise { + const typeValue: ITypeValue = this._formToObject(); + let observable: Observable; if (this.dictionary) { // edit mode - observable = this._dictionaryControllerService.updateType(typeValue, this._dossierTemplateId, typeValue.type); + observable = this._dictionaryService.updateType(typeValue, this._dossierTemplateId, typeValue.type); } else { // create mode - typeValue.dossierTemplateId = this._dossierTemplateId; - observable = this._dictionaryControllerService.addType(typeValue); + observable = this._dictionaryService.addType({ ...typeValue, dossierTemplateId: this._dossierTemplateId }); } observable.subscribe( @@ -120,7 +120,7 @@ export class AddEditDictionaryDialogComponent { this.technicalName = technicalName; } - private _formToObject(): TypeValue { + private _formToObject(): ITypeValue { return { type: this.dictionary?.type || this.technicalName, label: this.dictionaryForm.get('label').value, diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-attribute-dialog/add-edit-dossier-attribute-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-attribute-dialog/add-edit-dossier-attribute-dialog.component.ts index dcb61f207..8c4aed934 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-attribute-dialog/add-edit-dossier-attribute-dialog.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-attribute-dialog/add-edit-dossier-attribute-dialog.component.ts @@ -1,10 +1,9 @@ import { Component, Inject, OnDestroy } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; -import { DossierAttributeConfig, FileAttributeConfig } from '@redaction/red-ui-http'; +import { DossierAttributeConfigTypes, FileAttributeConfigTypes, IDossierAttributeConfig } from '@redaction/red-ui-http'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { AutoUnsubscribe, LoadingService } from '@iqser/common-ui'; +import { AutoUnsubscribe, LoadingService, Toaster } from '@iqser/common-ui'; import { HttpErrorResponse } from '@angular/common/http'; -import { Toaster } from '@iqser/common-ui'; import { DossierAttributesService } from '@shared/services/controller-wrappers/dossier-attributes.service'; import { dossierAttributeTypesTranslations } from '../../translations/dossier-attribute-types-translations'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; @@ -15,14 +14,9 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; }) export class AddEditDossierAttributeDialogComponent extends AutoUnsubscribe implements OnDestroy { dossierAttributeForm: FormGroup; - dossierAttribute: DossierAttributeConfig; + dossierAttribute: IDossierAttributeConfig; readonly translations = dossierAttributeTypesTranslations; - readonly typeOptions = [ - DossierAttributeConfig.TypeEnum.TEXT, - DossierAttributeConfig.TypeEnum.NUMBER, - DossierAttributeConfig.TypeEnum.DATE, - DossierAttributeConfig.TypeEnum.IMAGE - ]; + readonly typeOptions = Object.keys(DossierAttributeConfigTypes); constructor( private readonly _formBuilder: FormBuilder, @@ -31,7 +25,7 @@ export class AddEditDossierAttributeDialogComponent extends AutoUnsubscribe impl private readonly _toaster: Toaster, readonly dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) - readonly data: { readonly dossierAttribute: DossierAttributeConfig } + readonly data: { readonly dossierAttribute: IDossierAttributeConfig } ) { super(); this.dossierAttribute = data.dossierAttribute; @@ -44,7 +38,7 @@ export class AddEditDossierAttributeDialogComponent extends AutoUnsubscribe impl disabled: true } }), - type: [this.dossierAttribute?.type || FileAttributeConfig.TypeEnum.TEXT, Validators.required] + type: [this.dossierAttribute?.type || FileAttributeConfigTypes.TEXT, Validators.required] }); } @@ -65,7 +59,7 @@ export class AddEditDossierAttributeDialogComponent extends AutoUnsubscribe impl saveFileAttribute() { this._loadingService.start(); - const attribute: DossierAttributeConfig = { + const attribute: IDossierAttributeConfig = { id: this.dossierAttribute?.id, editable: true, ...this.dossierAttributeForm.getRawValue() diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component.ts index 305b6ddd6..fd062b7b8 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component.ts @@ -5,9 +5,9 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import * as moment from 'moment'; import { Moment } from 'moment'; import { - Dossier, DossierTemplateControllerService, - DossierTemplateModel, + DownloadFileType, + IDossierTemplate, ReportTemplate, ReportTemplateControllerService } from '@redaction/red-ui-http'; @@ -23,8 +23,8 @@ export class AddEditDossierTemplateDialogComponent implements OnInit { dossierTemplateForm: FormGroup; hasValidFrom: boolean; hasValidTo: boolean; - downloadTypesEnum: Dossier.DownloadFileTypesEnum[] = ['ORIGINAL', 'PREVIEW', 'REDACTED']; - downloadTypes: { key: Dossier.DownloadFileTypesEnum; label: string }[] = this.downloadTypesEnum.map(type => ({ + downloadTypesEnum: DownloadFileType[] = ['ORIGINAL', 'PREVIEW', 'REDACTED']; + downloadTypes: { key: DownloadFileType; label: string }[] = this.downloadTypesEnum.map(type => ({ key: type, label: downloadTypesTranslations[type] })); @@ -39,7 +39,7 @@ export class AddEditDossierTemplateDialogComponent implements OnInit { private readonly _dossierTemplateController: DossierTemplateControllerService, private readonly _reportTemplateController: ReportTemplateControllerService, public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public dossierTemplate: DossierTemplateModel + @Inject(MAT_DIALOG_DATA) readonly dossierTemplate: IDossierTemplate ) { this.dossierTemplateForm = this._formBuilder.group({ name: [this.dossierTemplate?.name, Validators.required], diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component.ts index d330096a7..a7abc108c 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component.ts @@ -1,7 +1,7 @@ import { Component, Inject } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { AppStateService } from '@state/app-state.service'; -import { FileAttributeConfig } from '@redaction/red-ui-http'; +import { FileAttributeConfigTypes, IFileAttributeConfig } from '@redaction/red-ui-http'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { fileAttributeTypesTranslations } from '../../translations/file-attribute-types-translations'; @@ -12,9 +12,9 @@ import { fileAttributeTypesTranslations } from '../../translations/file-attribut }) export class AddEditFileAttributeDialogComponent { fileAttributeForm: FormGroup; - fileAttribute: FileAttributeConfig; + fileAttribute: IFileAttributeConfig; dossierTemplateId: string; - readonly typeOptions = [FileAttributeConfig.TypeEnum.TEXT, FileAttributeConfig.TypeEnum.NUMBER, FileAttributeConfig.TypeEnum.DATE]; + readonly typeOptions = Object.keys(FileAttributeConfigTypes); translations = fileAttributeTypesTranslations; constructor( @@ -22,7 +22,7 @@ export class AddEditFileAttributeDialogComponent { private readonly _formBuilder: FormBuilder, public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) - public data: { fileAttribute: FileAttributeConfig; dossierTemplateId: string } + public data: { fileAttribute: IFileAttributeConfig; dossierTemplateId: string } ) { this.fileAttribute = data.fileAttribute; this.dossierTemplateId = data.dossierTemplateId; @@ -30,7 +30,7 @@ export class AddEditFileAttributeDialogComponent { this.fileAttributeForm = this._formBuilder.group({ label: [this.fileAttribute?.label, Validators.required], csvColumnHeader: [this.fileAttribute?.csvColumnHeader, Validators.required], - type: [this.fileAttribute?.type || FileAttributeConfig.TypeEnum.TEXT, Validators.required], + type: [this.fileAttribute?.type || FileAttributeConfigTypes.TEXT, Validators.required], readonly: [this.fileAttribute ? !this.fileAttribute.editable : false], primaryAttribute: [this.fileAttribute?.primaryAttribute], filterable: [this.fileAttribute?.filterable], @@ -57,7 +57,7 @@ export class AddEditFileAttributeDialogComponent { } async saveFileAttribute() { - const fileAttribute: FileAttributeConfig = { + const fileAttribute: IFileAttributeConfig = { id: this.fileAttribute?.id, editable: !this.fileAttributeForm.get('readonly').value, ...this.fileAttributeForm.getRawValue() diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/add-edit-user-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/add-edit-user-dialog.component.ts index 8753a57bc..95222870a 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/add-edit-user-dialog.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/add-edit-user-dialog.component.ts @@ -1,6 +1,6 @@ import { Component, Inject } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { UserWrapper } from '@services/user.service'; +import { User } from '@models/user'; @Component({ selector: 'redaction-add-edit-user-dialog', @@ -10,7 +10,7 @@ import { UserWrapper } from '@services/user.service'; export class AddEditUserDialogComponent { resettingPassword = false; - constructor(readonly dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) readonly user: UserWrapper) {} + constructor(readonly dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) readonly user: User) {} toggleResetPassword() { this.resettingPassword = !this.resettingPassword; diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/reset-password/reset-password.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/reset-password/reset-password.component.ts index 7dfb3d7b3..a8a7b7c96 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/reset-password/reset-password.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/reset-password/reset-password.component.ts @@ -1,8 +1,9 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { FormBuilder, Validators } from '@angular/forms'; import { UserControllerService } from '@redaction/red-ui-http'; -import { UserService, UserWrapper } from '@services/user.service'; +import { UserService } from '@services/user.service'; import { LoadingService } from '@iqser/common-ui'; +import { User } from '@models/user'; @Component({ selector: 'redaction-reset-password', @@ -13,8 +14,8 @@ export class ResetPasswordComponent { readonly passwordForm = this._formBuilder.group({ temporaryPassword: [null, Validators.required] }); - @Input() user: UserWrapper; - @Output() toggleResetPassword = new EventEmitter(); + @Input() user: User; + @Output() readonly toggleResetPassword = new EventEmitter(); constructor( private readonly _formBuilder: FormBuilder, diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/user-details/user-details.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/user-details/user-details.component.ts index f9165c1ee..a9a6f9406 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/user-details/user-details.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/user-details/user-details.component.ts @@ -4,8 +4,8 @@ import { UserControllerService } from '@redaction/red-ui-http'; import { AdminDialogService } from '../../../services/admin-dialog.service'; import { IconButtonTypes, LoadingService, Toaster } from '@iqser/common-ui'; import { rolesTranslations } from '../../../../../translations/roles-translations'; -import { UserWrapper } from '@services/user.service'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { User } from '@models/user'; @Component({ selector: 'redaction-user-details', @@ -15,9 +15,10 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; export class UserDetailsComponent implements OnInit { readonly iconButtonTypes = IconButtonTypes; - @Input() user: UserWrapper; - @Output() toggleResetPassword = new EventEmitter(); - @Output() closeDialog = new EventEmitter(); + @Input() user: User; + @Output() readonly toggleResetPassword = new EventEmitter(); + @Output() readonly closeDialog = new EventEmitter(); + userForm: FormGroup; readonly ROLES = ['RED_USER', 'RED_MANAGER', 'RED_USER_ADMIN', 'RED_ADMIN']; readonly translations = rolesTranslations; diff --git a/apps/red-ui/src/app/modules/admin/dialogs/confirm-delete-file-attribute-dialog/confirm-delete-file-attribute-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/confirm-delete-file-attribute-dialog/confirm-delete-file-attribute-dialog.component.ts index bad6ea1d0..d35d500d3 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/confirm-delete-file-attribute-dialog/confirm-delete-file-attribute-dialog.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/confirm-delete-file-attribute-dialog/confirm-delete-file-attribute-dialog.component.ts @@ -1,5 +1,5 @@ import { Component, Inject } from '@angular/core'; -import { FileAttributeConfig } from '@redaction/red-ui-http'; +import { IFileAttributeConfig } from '@redaction/red-ui-http'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; @@ -9,7 +9,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; styleUrls: ['./confirm-delete-file-attribute-dialog.component.scss'] }) export class ConfirmDeleteFileAttributeDialogComponent { - fileAttribute: FileAttributeConfig; + fileAttribute: IFileAttributeConfig; checkboxes = [ { value: false, label: _('confirm-delete-file-attribute.impacted-documents') }, { value: false, label: _('confirm-delete-file-attribute.lost-details') } @@ -18,7 +18,7 @@ export class ConfirmDeleteFileAttributeDialogComponent { constructor( public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: FileAttributeConfig + @Inject(MAT_DIALOG_DATA) public data: IFileAttributeConfig ) { this.fileAttribute = data; } 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 e70d72999..bd63dad28 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 @@ -4,7 +4,7 @@ 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 { UserWrapper } from '@services/user.service'; +import { User } from '@models/user'; @Component({ selector: 'redaction-confirm-delete-users-dialog', @@ -24,7 +24,7 @@ export class ConfirmDeleteUsersDialogComponent { private readonly _loadingService: LoadingService, private readonly _userControllerService: UserControllerService, readonly dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) readonly users: UserWrapper[] + @Inject(MAT_DIALOG_DATA) readonly users: User[] ) { this.dossiersCount = this._appStateService.allDossiers.filter(dw => { for (const user of this.users) { diff --git a/apps/red-ui/src/app/modules/admin/dialogs/edit-color-dialog/edit-color-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/edit-color-dialog/edit-color-dialog.component.ts index 6846684b7..6f4711c25 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/edit-color-dialog/edit-color-dialog.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/edit-color-dialog/edit-color-dialog.component.ts @@ -1,12 +1,13 @@ import { Component, Inject } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { Colors, DictionaryControllerService } from '@redaction/red-ui-http'; +import { Colors } from '@redaction/red-ui-http'; import { Toaster } from '@iqser/common-ui'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { TranslateService } from '@ngx-translate/core'; import { DefaultColorType } from '@models/default-color-key.model'; import { defaultColorsTranslations } from '../../translations/default-colors-translations'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { DictionaryService } from '@shared/services/dictionary.service'; @Component({ selector: 'redaction-edit-color-dialog', @@ -23,7 +24,7 @@ export class EditColorDialogComponent { constructor( private readonly _formBuilder: FormBuilder, - private readonly _dictionaryControllerService: DictionaryControllerService, + private readonly _dictionaryService: DictionaryService, private readonly _toaster: Toaster, private readonly _translateService: TranslateService, private readonly _dialogRef: MatDialogRef, @@ -51,7 +52,7 @@ export class EditColorDialogComponent { }; try { - await this._dictionaryControllerService.setColors(colors, this._dossierTemplateId).toPromise(); + await this._dictionaryService.setColors(colors, this._dossierTemplateId).toPromise(); this._dialogRef.close(true); const color = this._translateService.instant(defaultColorsTranslations[this.colorKey]); this._toaster.info(_('edit-color-dialog.success'), { params: { color: color } }); diff --git a/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/active-fields-listing/active-fields-listing.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/active-fields-listing/active-fields-listing.component.ts index 126288f6a..b267c26a1 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/active-fields-listing/active-fields-listing.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/active-fields-listing/active-fields-listing.component.ts @@ -12,7 +12,7 @@ import { ViewChild } from '@angular/core'; import { Field } from '../file-attributes-csv-import-dialog.component'; -import { FileAttributeConfig } from '@redaction/red-ui-http'; +import { FileAttributeConfigTypes } from '@redaction/red-ui-http'; import { CircleButtonTypes, DefaultListingServices, ListingComponent, TableColumnConfig } from '@iqser/common-ui'; import { fileAttributeTypesTranslations } from '../../../translations/file-attribute-types-translations'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; @@ -28,20 +28,15 @@ export class ActiveFieldsListingComponent extends ListingComponent implem readonly translations = fileAttributeTypesTranslations; readonly tableHeaderLabel = _('file-attributes-csv-import.table-header.title'); tableColumnConfigs: TableColumnConfig[]; - readonly typeOptions = [ - FileAttributeConfig.TypeEnum.TEXT, - FileAttributeConfig.TypeEnum.NUMBER, - FileAttributeConfig.TypeEnum.DATE - ] as const; + readonly typeOptions = Object.keys(FileAttributeConfigTypes); @ViewChild('labelTemplate', { static: true }) labelTemplate: TemplateRef; @ViewChild('typeTemplate', { static: true }) typeTemplate: TemplateRef; @ViewChild('readonlyTemplate', { static: true }) readonlyTemplate: TemplateRef; @ViewChild('primaryTemplate', { static: true }) primaryTemplate: TemplateRef; @Input() entities: Field[]; - @Output() entitiesChange = new EventEmitter(); - @Output() setHoveredColumn = new EventEmitter(); - @Output() toggleFieldActive = new EventEmitter(); - protected readonly _primaryKey = 'csvColumn'; + @Output() readonly entitiesChange = new EventEmitter(); + @Output() readonly setHoveredColumn = new EventEmitter(); + @Output() readonly toggleFieldActive = new EventEmitter(); constructor(protected readonly _injector: Injector) { super(_injector); diff --git a/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.html b/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.html index 1fbc14715..0357d5eb5 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.html +++ b/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.html @@ -100,7 +100,7 @@ (click)="toggleFieldActive(field)" (mouseenter)="setHoveredColumn(field.csvColumn)" (mouseleave)="setHoveredColumn()" - *ngFor="let field of sortedDisplayedEntities$ | async; trackBy: trackByPrimaryKey" + *ngFor="let field of sortedDisplayedEntities$ | async" class="csv-header-pill-wrapper" >
diff --git a/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.ts index 6c5f23c5b..48ec927cc 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.ts @@ -2,17 +2,23 @@ import { Component, Inject, Injector } from '@angular/core'; import { AbstractControl, FormBuilder, FormGroup, ValidatorFn, Validators } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import * as Papa from 'papaparse'; -import { FileAttributeConfig, FileAttributesConfig, FileAttributesControllerService } from '@redaction/red-ui-http'; +import { + FileAttributeConfigType, + FileAttributeConfigTypes, + FileAttributesConfig, + FileAttributesControllerService +} from '@redaction/red-ui-http'; import { Observable } from 'rxjs'; import { map, startWith } from 'rxjs/operators'; -import { DefaultListingServices, Listable, ListingComponent, TableColumnConfig, Toaster } from '@iqser/common-ui'; +import { DefaultListingServices, IListable, ListingComponent, TableColumnConfig, Toaster } from '@iqser/common-ui'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { FileAttributeConfig } from '@models/file/file-attribute-config'; -export interface Field extends Listable { +export interface Field extends IListable { id: string; csvColumn: string; name: string; - type: FileAttributeConfig.TypeEnum; + type: FileAttributeConfigType; readonly: boolean; primaryAttribute: boolean; } @@ -35,7 +41,6 @@ export class FileAttributesCsvImportDialogComponent extends ListingComponent ({ ...item, searchKey: item.csvColumn }))]; } deactivateAll() { @@ -165,17 +170,15 @@ export class FileAttributesCsvImportDialogComponent extends ListingComponent attr.primaryAttribute); - + let fileAttributeConfigs = this.data.existingConfiguration.fileAttributeConfigs; if (newPrimary) { - this.data.existingConfiguration.fileAttributeConfigs.forEach(attr => (attr.primaryAttribute = false)); + fileAttributeConfigs = fileAttributeConfigs.map(attr => new FileAttributeConfig({ ...attr, primaryAttribute: false })); } const fileAttributes = { ...this.baseConfigForm.getRawValue(), fileAttributeConfigs: [ - ...this.data.existingConfiguration.fileAttributeConfigs.filter( - a => !this.allEntities.find(entity => entity.csvColumn === a.csvColumnHeader) - ), + ...fileAttributeConfigs.filter(a => !this.allEntities.find(entity => entity.csvColumn === a.csvColumnHeader)), ...this.activeFields.map(field => ({ id: field.id, csvColumnHeader: field.csvColumn, @@ -228,7 +231,8 @@ export class FileAttributesCsvImportDialogComponent extends ListingComponent AuditScreenComponent) }] }) -export class AuditScreenComponent extends ListingComponent implements OnDestroy, OnInit { +export class AuditScreenComponent extends ListingComponent implements OnDestroy, OnInit { readonly ALL_CATEGORIES = 'allCategories'; readonly ALL_USERS = _('audit-screen.all-users'); readonly translations = auditCategoriesTranslations; readonly currentUser = this._userService.currentUser; - @ViewChild('messageTemplate', { static: true }) messageTemplate: TemplateRef; - @ViewChild('dateTemplate', { static: true }) dateTemplate: TemplateRef; - @ViewChild('userTemplate', { static: true }) userTemplate: TemplateRef; - @ViewChild('categoryTemplate', { static: true }) categoryTemplate: TemplateRef; + @ViewChild('messageTemplate', { static: true }) messageTemplate: TemplateRef; + @ViewChild('dateTemplate', { static: true }) dateTemplate: TemplateRef; + @ViewChild('userTemplate', { static: true }) userTemplate: TemplateRef; + @ViewChild('categoryTemplate', { static: true }) categoryTemplate: TemplateRef; filterForm: FormGroup; categories: string[] = []; userIds: Set; logs: AuditResponse; - tableColumnConfigs: TableColumnConfig[]; + tableColumnConfigs: TableColumnConfig[]; readonly tableHeaderLabel = _('audit-screen.table-header.title'); - protected readonly _primaryKey: KeysOf = 'recordDate'; private _previousFrom: Moment; private _previousTo: Moment; @@ -133,7 +132,7 @@ export class AuditScreenComponent extends ListingComponent im this.categories = data[0].map(c => c.category); this.categories.splice(0, 0, this.ALL_CATEGORIES); this.logs = data[1]; - const entities = this.logs.data.map((log: AuditModel) => new AuditModelWrapper(log)); + const entities = this.logs.data.map((log: IAudit) => new Audit(log)); this.entitiesService.setEntities(entities); this.userIds = new Set([this.ALL_USERS]); for (const id of this.logs.data.map(log => log.userId).filter(uid => !!uid)) { diff --git a/apps/red-ui/src/app/modules/admin/screens/default-colors/default-colors-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/default-colors/default-colors-screen.component.ts index 65dd139b6..26ed04f75 100644 --- a/apps/red-ui/src/app/modules/admin/screens/default-colors/default-colors-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/default-colors/default-colors-screen.component.ts @@ -1,15 +1,23 @@ import { ChangeDetectionStrategy, Component, forwardRef, Injector, OnInit, TemplateRef, ViewChild } from '@angular/core'; import { AppStateService } from '@state/app-state.service'; -import { Colors, DictionaryControllerService } from '@redaction/red-ui-http'; +import { Colors } from '@redaction/red-ui-http'; import { ActivatedRoute } from '@angular/router'; import { AdminDialogService } from '../../services/admin-dialog.service'; -import { CircleButtonTypes, DefaultListingServices, Listable, ListingComponent, LoadingService, TableColumnConfig } from '@iqser/common-ui'; +import { + CircleButtonTypes, + DefaultListingServices, + IListable, + ListingComponent, + LoadingService, + TableColumnConfig +} from '@iqser/common-ui'; import { DefaultColorType } from '@models/default-color-key.model'; import { defaultColorsTranslations } from '../../translations/default-colors-translations'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { UserService } from '@services/user.service'; +import { DictionaryService } from '@shared/services/dictionary.service'; -interface ListItem extends Listable { +interface ListItem extends IListable { readonly key: string; readonly value: string; } @@ -21,14 +29,13 @@ interface ListItem extends Listable { providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => DefaultColorsScreenComponent) }] }) export class DefaultColorsScreenComponent extends ListingComponent implements OnInit { - @ViewChild('nameTemplate', { static: true }) nameTemplate: TemplateRef; - @ViewChild('colorTemplate', { static: true }) colorTemplate: TemplateRef; + @ViewChild('nameTemplate', { static: true }) nameTemplate: TemplateRef; + @ViewChild('colorTemplate', { static: true }) colorTemplate: TemplateRef; readonly circleButtonTypes = CircleButtonTypes; readonly currentUser = this._userService.currentUser; readonly translations = defaultColorsTranslations; readonly tableHeaderLabel = _('default-colors-screen.table-header.title'); tableColumnConfigs: TableColumnConfig[]; - protected readonly _primaryKey = 'key'; private _colorsObj: Colors; constructor( @@ -38,7 +45,7 @@ export class DefaultColorsScreenComponent extends ListingComponent imp private readonly _activatedRoute: ActivatedRoute, private readonly _appStateService: AppStateService, private readonly _dialogService: AdminDialogService, - private readonly _dictionaryControllerService: DictionaryControllerService + private readonly _dictionaryService: DictionaryService ) { super(_injector); _appStateService.activateDossierTemplate(_activatedRoute.snapshot.params.dossierTemplateId); @@ -69,7 +76,7 @@ export class DefaultColorsScreenComponent extends ListingComponent imp this.tableColumnConfigs = [ { label: _('default-colors-screen.table-col-names.key'), - sortByKey: 'key', + sortByKey: 'searchKey', template: this.nameTemplate, width: '2fr' }, @@ -83,11 +90,12 @@ export class DefaultColorsScreenComponent extends ListingComponent imp private async _loadColors() { this._loadingService.start(); - const data = await this._dictionaryControllerService.getColors(this._appStateService.activeDossierTemplateId).toPromise(); + const data = await this._dictionaryService.getColors(this._appStateService.activeDossierTemplateId).toPromise(); this._colorsObj = data; - const entities = Object.keys(data).map(key => ({ + const entities: ListItem[] = Object.keys(data).map(key => ({ id: key, key, + searchKey: key, value: data[key] })); this.entitiesService.setEntities(entities); diff --git a/apps/red-ui/src/app/modules/admin/screens/dictionary-listing/dictionary-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/dictionary-listing/dictionary-listing-screen.component.ts index e6eff876d..6d9ed2807 100644 --- a/apps/red-ui/src/app/modules/admin/screens/dictionary-listing/dictionary-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/dictionary-listing/dictionary-listing-screen.component.ts @@ -1,11 +1,10 @@ import { Component, forwardRef, Injector, OnInit, TemplateRef, ViewChild } from '@angular/core'; import { DoughnutChartConfig } from '@shared/components/simple-doughnut-chart/simple-doughnut-chart.component'; -import { DictionaryControllerService } from '@redaction/red-ui-http'; import { AppStateService } from '@state/app-state.service'; import { catchError, defaultIfEmpty, tap } from 'rxjs/operators'; import { forkJoin, of } from 'rxjs'; import { ActivatedRoute } from '@angular/router'; -import { TypeValueWrapper } from '@models/file/type-value.wrapper'; +import { TypeValue } from '@models/file/type-value'; import { TranslateService } from '@ngx-translate/core'; import { CircleButtonTypes, @@ -18,8 +17,9 @@ import { import { AdminDialogService } from '../../services/admin-dialog.service'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { UserService } from '@services/user.service'; +import { DictionaryService } from '@shared/services/dictionary.service'; -const toChartConfig = (dict: TypeValueWrapper): DoughnutChartConfig => ({ +const toChartConfig = (dict: TypeValue): DoughnutChartConfig => ({ value: dict.entries?.length ?? 0, color: dict.hexColor, label: dict.label, @@ -31,17 +31,16 @@ const toChartConfig = (dict: TypeValueWrapper): DoughnutChartConfig => ({ styleUrls: ['./dictionary-listing-screen.component.scss'], providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => DictionaryListingScreenComponent) }] }) -export class DictionaryListingScreenComponent extends ListingComponent implements OnInit { +export class DictionaryListingScreenComponent extends ListingComponent implements OnInit { readonly iconButtonTypes = IconButtonTypes; readonly circleButtonTypes = CircleButtonTypes; readonly currentUser = this._userService.currentUser; readonly tableHeaderLabel = _('dictionary-listing.table-header.title'); - tableColumnConfigs: TableColumnConfig[]; + tableColumnConfigs: TableColumnConfig[]; chartData: DoughnutChartConfig[] = []; @ViewChild('labelTemplate', { static: true }) labelTemplate: TemplateRef; @ViewChild('rankTemplate', { static: true }) rankTemplate: TemplateRef; @ViewChild('iconTemplate', { static: true }) iconTemplate: TemplateRef; - protected readonly _primaryKey = 'type'; constructor( protected readonly _injector: Injector, @@ -51,15 +50,13 @@ export class DictionaryListingScreenComponent extends ListingComponent [entity.type]; - ngOnInit(): void { this._configureTableColumns(); this._loadDictionaryData(); @@ -68,7 +65,7 @@ export class DictionaryListingScreenComponent extends ListingComponent { this._loadingService.start(); - await this._dictionaryControllerService + await this._dictionaryService .deleteTypes( types.map(t => t.type), this._appStateService.activeDossierTemplateId @@ -82,7 +79,7 @@ export class DictionaryListingScreenComponent extends ListingComponent - this._dictionaryControllerService.getDictionaryForType(this._appStateService.activeDossierTemplateId, dict.type).pipe( - tap(values => (dict.entries = values.entries ?? [])), + this._dictionaryService.getFor(this._appStateService.activeDossierTemplateId, dict.type).pipe( + tap(values => (dict.entries = [...values.entries] ?? [])), catchError(() => { dict.entries = []; return of({}); diff --git a/apps/red-ui/src/app/modules/admin/screens/dictionary-overview/dictionary-overview-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/dictionary-overview/dictionary-overview-screen.component.ts index 1c95c9f1f..a16484207 100644 --- a/apps/red-ui/src/app/modules/admin/screens/dictionary-overview/dictionary-overview-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/dictionary-overview/dictionary-overview-screen.component.ts @@ -1,5 +1,4 @@ import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; -import { DictionaryControllerService } from '@redaction/red-ui-http'; import { AppStateService } from '@state/app-state.service'; import { ActivatedRoute, Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; @@ -7,8 +6,8 @@ import { saveAs } from 'file-saver'; import { ComponentHasChanges } from '@guards/can-deactivate.guard'; import { AdminDialogService } from '../../services/admin-dialog.service'; import { DictionaryManagerComponent } from '@shared/components/dictionary-manager/dictionary-manager.component'; -import { DictionarySaveService } from '@shared/services/dictionary-save.service'; -import { TypeValueWrapper } from '@models/file/type-value.wrapper'; +import { DictionaryService } from '@shared/services/dictionary.service'; +import { TypeValue } from '@models/file/type-value'; import { CircleButtonTypes, LoadingService } from '@iqser/common-ui'; import { UserService } from '@services/user.service'; @@ -21,7 +20,7 @@ export class DictionaryOverviewScreenComponent extends ComponentHasChanges imple readonly currentUser = this._userService.currentUser; entries: string[] = []; - dictionary: TypeValueWrapper; + dictionary: TypeValue; @ViewChild('dictionaryManager', { static: false }) private readonly _dictionaryManager: DictionaryManagerComponent; @@ -35,8 +34,7 @@ export class DictionaryOverviewScreenComponent extends ComponentHasChanges imple private readonly _appStateService: AppStateService, private readonly _dialogService: AdminDialogService, protected readonly _translateService: TranslateService, - private readonly _dictionarySaveService: DictionarySaveService, - private readonly _dictionaryControllerService: DictionaryControllerService + private readonly _dictionaryService: DictionaryService ) { super(_translateService); } @@ -51,7 +49,7 @@ export class DictionaryOverviewScreenComponent extends ComponentHasChanges imple this._activatedRoute.snapshot.params.dossierTemplateId ); this.dictionary = this._appStateService.activeDictionary; - this._loadEntries(); + await this._loadEntries(); } openEditDictionaryDialog($event: any) { @@ -75,7 +73,7 @@ export class DictionaryOverviewScreenComponent extends ComponentHasChanges imple $event?.stopPropagation(); this._dialogService.openDialog('confirm', $event, null, async () => { - await this._dictionaryControllerService.deleteTypes([this.dictionary.type], this.dictionary.dossierTemplateId).toPromise(); + await this._dictionaryService.deleteTypes([this.dictionary.type], this.dictionary.dossierTemplateId).toPromise(); await this._appStateService.loadDictionaryData(); await this._router.navigate([ '/main', @@ -110,30 +108,34 @@ export class DictionaryOverviewScreenComponent extends ComponentHasChanges imple saveEntries(entries: string[]) { this._loadingService.start(); - this._dictionarySaveService - .saveEntries(entries, this.entries, this.dictionary.dossierTemplateId, this.dictionary.type, null) - .subscribe( - () => { - this._loadingService.stop(); - this._loadEntries(); - }, - () => { - this._loadingService.stop(); - } - ); - } - - private _loadEntries() { - this._loadingService.start(); - this._dictionaryControllerService.getDictionaryForType(this.dictionary.dossierTemplateId, this.dictionary.type).subscribe( - data => { - this._loadingService.stop(); - this.entries = data.entries.sort((str1, str2) => str1.localeCompare(str2, undefined, { sensitivity: 'accent' })); + this._dictionaryService.saveEntries(entries, this.entries, this.dictionary.dossierTemplateId, this.dictionary.type, null).subscribe( + async () => { + await this._loadEntries(); }, () => { this._loadingService.stop(); - this.entries = []; } ); } + + private async _loadEntries() { + this._loadingService.start(); + await this._dictionaryService + .getFor(this.dictionary.dossierTemplateId, this.dictionary.type) + .toPromise() + .then( + data => { + this._loadingService.stop(); + this.entries = [...data.entries].sort((str1, str2) => str1.localeCompare(str2, undefined, { sensitivity: 'accent' })); + }, + () => { + this._loadingService.stop(); + this.entries = []; + } + ) + .catch(() => { + this._loadingService.stop(); + this.entries = []; + }); + } } diff --git a/apps/red-ui/src/app/modules/admin/screens/dossier-attributes-listing/dossier-attributes-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/dossier-attributes-listing/dossier-attributes-listing-screen.component.ts index 8ed266871..09cd2466f 100644 --- a/apps/red-ui/src/app/modules/admin/screens/dossier-attributes-listing/dossier-attributes-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/dossier-attributes-listing/dossier-attributes-listing-screen.component.ts @@ -7,7 +7,7 @@ import { LoadingService, TableColumnConfig } from '@iqser/common-ui'; -import { DossierAttributeConfig } from '@redaction/red-ui-http'; +import { IDossierAttributeConfig } from '@redaction/red-ui-http'; import { AppStateService } from '@state/app-state.service'; import { ActivatedRoute } from '@angular/router'; import { AdminDialogService } from '../../services/admin-dialog.service'; @@ -15,6 +15,7 @@ import { DossierAttributesService } from '@shared/services/controller-wrappers/d import { dossierAttributeTypesTranslations } from '../../translations/dossier-attribute-types-translations'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { UserService } from '@services/user.service'; +import { DossierAttributeConfig } from '@state/model/dossier-attribute-config'; @Component({ templateUrl: './dossier-attributes-listing-screen.component.html', @@ -34,7 +35,6 @@ export class DossierAttributesListingScreenComponent extends ListingComponent; @ViewChild('placeholderTemplate', { static: true }) placeholderTemplate: TemplateRef; @ViewChild('typeTemplate', { static: true }) typeTemplate: TemplateRef; - protected readonly _primaryKey = 'label'; constructor( protected readonly _injector: Injector, @@ -54,7 +54,7 @@ export class DossierAttributesListingScreenComponent extends ListingComponent { this._loadingService.start(); const ids = dossierAttribute ? [dossierAttribute.id] : this.entitiesService.selected.map(item => item.id); @@ -64,7 +64,7 @@ export class DossierAttributesListingScreenComponent extends ListingComponent DossierTemplatesListingScreenComponent) } ] }) -export class DossierTemplatesListingScreenComponent extends ListingComponent implements OnInit { +export class DossierTemplatesListingScreenComponent extends ListingComponent implements OnInit { readonly iconButtonTypes = IconButtonTypes; readonly circleButtonTypes = CircleButtonTypes; readonly currentUser = this._userService.currentUser; readonly tableHeaderLabel = _('dossier-templates-listing.table-header.title'); - tableColumnConfigs: TableColumnConfig[]; - @ViewChild('nameTemplate', { static: true }) nameTemplate: TemplateRef; - @ViewChild('userTemplate', { static: true }) userTemplate: TemplateRef; - @ViewChild('dateAddedTemplate', { static: true }) dateAddedTemplate: TemplateRef; - @ViewChild('dateModifiedTemplate', { static: true }) dateModifiedTemplate: TemplateRef; - protected readonly _primaryKey = 'name'; + tableColumnConfigs: TableColumnConfig[]; + @ViewChild('nameTemplate', { static: true }) nameTemplate: TemplateRef; + @ViewChild('userTemplate', { static: true }) userTemplate: TemplateRef; + @ViewChild('dateAddedTemplate', { static: true }) dateAddedTemplate: TemplateRef; + @ViewChild('dateModifiedTemplate', { static: true }) dateModifiedTemplate: TemplateRef; constructor( protected readonly _injector: Injector, @@ -52,8 +51,6 @@ export class DossierTemplatesListingScreenComponent extends ListingComponent [dossierTemplate.dossierTemplateId, 'dictionaries']; - ngOnInit(): void { this._configureTableColumns(); this.loadDossierTemplatesData(); @@ -81,7 +78,7 @@ export class DossierTemplatesListingScreenComponent extends ListingComponent[]; - @ViewChild('labelTemplate', { static: true }) labelTemplate: TemplateRef; - @ViewChild('typeTemplate', { static: true }) typeTemplate: TemplateRef; - @ViewChild('readonlyTemplate', { static: true }) readonlyTemplate: TemplateRef; - @ViewChild('csvColumnHeaderTemplate', { static: true }) csvColumnHeaderTemplate: TemplateRef; - @ViewChild('filterableTemplate', { static: true }) filterableTemplate: TemplateRef; - @ViewChild('displayedInFileListTemplate', { static: true }) displayedInFileListTemplate: TemplateRef; - @ViewChild('primaryAttributeTemplate', { static: true }) primaryAttributeTemplate: TemplateRef; - protected readonly _primaryKey = 'label'; + @ViewChild('labelTemplate', { static: true }) labelTemplate: TemplateRef; + @ViewChild('typeTemplate', { static: true }) typeTemplate: TemplateRef; + @ViewChild('readonlyTemplate', { static: true }) readonlyTemplate: TemplateRef; + @ViewChild('csvColumnHeaderTemplate', { static: true }) csvColumnHeaderTemplate: TemplateRef; + @ViewChild('filterableTemplate', { static: true }) filterableTemplate: TemplateRef; + @ViewChild('displayedInFileListTemplate', { static: true }) displayedInFileListTemplate: TemplateRef; + @ViewChild('primaryAttributeTemplate', { static: true }) primaryAttributeTemplate: TemplateRef; private _existingConfiguration: FileAttributesConfig; @ViewChild('fileInput') private _fileInput: ElementRef; @@ -70,7 +70,7 @@ export class FileAttributesListingScreenComponent extends ListingComponent { this._loadingService.start(); if (fileAttribute) { @@ -126,7 +126,7 @@ export class FileAttributesListingScreenComponent extends ListingComponent new FileAttributeConfig(item)) || []; + this.entitiesService.setEntities(fileAttributeConfig); } catch (e) {} this._loadingService.stop(); diff --git a/apps/red-ui/src/app/modules/admin/screens/trash/trash-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/trash/trash-screen.component.ts index c30fdfdbd..bed1882f5 100644 --- a/apps/red-ui/src/app/modules/admin/screens/trash/trash-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/trash/trash-screen.component.ts @@ -1,9 +1,9 @@ import { ChangeDetectionStrategy, Component, forwardRef, Injector, OnInit, TemplateRef, ViewChild } from '@angular/core'; -import { Dossier } from '@redaction/red-ui-http'; +import { IDossier } from '@redaction/red-ui-http'; import { CircleButtonTypes, DefaultListingServices, - Listable, + IListable, ListingComponent, LoadingService, SortingOrders, @@ -20,7 +20,7 @@ import { distinctUntilChanged, map } from 'rxjs/operators'; import { getLeftDateTime } from '@utils/functions'; import { RouterHistoryService } from '@services/router-history.service'; -interface DossierListItem extends Dossier, Listable { +interface DossierListItem extends IDossier, IListable { readonly canRestore: boolean; readonly restoreDate: string; } @@ -29,11 +29,7 @@ interface DossierListItem extends Dossier, Listable { templateUrl: './trash-screen.component.html', styleUrls: ['./trash-screen.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, - providers: [ - ...DefaultListingServices, - DossiersService, - { provide: ListingComponent, useExisting: forwardRef(() => TrashScreenComponent) } - ] + providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => TrashScreenComponent) }] }) export class TrashScreenComponent extends ListingComponent implements OnInit { readonly circleButtonTypes = CircleButtonTypes; @@ -44,8 +40,6 @@ export class TrashScreenComponent extends ListingComponent impl @ViewChild('ownerTemplate', { static: true }) ownerTemplate: TemplateRef; @ViewChild('deletedTimeTemplate', { static: true }) deletedTimeTemplate: TemplateRef; @ViewChild('restoreDateTemplate', { static: true }) restoreDateTemplate: TemplateRef; - protected readonly _primaryKey = 'dossierName'; - private readonly _deleteRetentionHours = this._configService.values.DELETE_RETENTION_HOURS; constructor( protected readonly _injector: Injector, @@ -78,7 +72,7 @@ export class TrashScreenComponent extends ListingComponent impl this._loadingService.stop(); } - hardDelete(dossiers = this.entitiesService.selected) { + hardDelete(dossiers = this.entitiesService.selected): void { const data = new ConfirmationDialogInput({ title: _('confirmation-dialog.delete-dossier.title'), titleColor: TitleColors.PRIMARY, @@ -97,7 +91,7 @@ export class TrashScreenComponent extends ListingComponent impl }); } - restore(dossiers = this.entitiesService.selected) { + restore(dossiers = this.entitiesService.selected): void { this._loadingService.loadWhile(this._restore(dossiers)); } @@ -105,7 +99,7 @@ export class TrashScreenComponent extends ListingComponent impl this.tableColumnConfigs = [ { label: _('trash.table-col-names.name'), - sortByKey: 'dossierName', + sortByKey: 'searchKey', template: this.filenameTemplate }, { @@ -127,7 +121,7 @@ export class TrashScreenComponent extends ListingComponent impl } private _getRestoreDate(softDeletedTime: string): string { - return moment(softDeletedTime).add(this._deleteRetentionHours, 'hours').toISOString(); + return moment(softDeletedTime).add(this._configService.values.DELETE_RETENTION_HOURS, 'hours').toISOString(); } private async _loadDossiersData(): Promise { @@ -140,15 +134,16 @@ export class TrashScreenComponent extends ListingComponent impl return daysLeft >= 0 && hoursLeft >= 0 && minutesLeft > 0; } - private _toListItems(dossiers: Dossier[]): DossierListItem[] { + private _toListItems(dossiers: IDossier[]): DossierListItem[] { return dossiers.map(dossier => this._toListItem(dossier)); } - private _toListItem(dossier: Dossier): DossierListItem { + private _toListItem(dossier: IDossier): DossierListItem { const restoreDate = this._getRestoreDate(dossier.softDeletedTime); return { id: dossier.dossierId, ...dossier, + searchKey: dossier.dossierName, restoreDate, canRestore: this._canRestoreDossier(restoreDate), // Because of migrations, for some this is not set @@ -157,19 +152,19 @@ export class TrashScreenComponent extends ListingComponent impl } private async _restore(dossiers: DossierListItem[]): Promise { - const dossierIds = dossiers.map(d => d.dossierId); + const dossierIds = dossiers.map(d => d.id); await this._dossiersService.restore(dossierIds); this._removeFromList(dossierIds); } private async _hardDelete(dossiers: DossierListItem[]) { - const dossierIds = dossiers.map(d => d.dossierId); + const dossierIds = dossiers.map(d => d.id); await this._dossiersService.hardDelete(dossierIds); this._removeFromList(dossierIds); } private _removeFromList(ids: string[]): void { - const entities = this.entitiesService.all.filter(e => !ids.includes(e.dossierId)); + const entities = this.entitiesService.all.filter(e => !ids.includes(e.id)); this.entitiesService.setEntities(entities); this.entitiesService.setSelected([]); } diff --git a/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.ts index 0bb3f1e65..fa92bdd2f 100644 --- a/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.ts @@ -1,5 +1,5 @@ import { Component, forwardRef, Injector, OnInit, QueryList, TemplateRef, ViewChild, ViewChildren } from '@angular/core'; -import { UserService, UserWrapper } from '@services/user.service'; +import { UserService } from '@services/user.service'; import { UserControllerService } from '@redaction/red-ui-http'; import { AdminDialogService } from '../../services/admin-dialog.service'; import { TranslateService } from '@ngx-translate/core'; @@ -18,27 +18,27 @@ import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { rolesTranslations } from '../../../../translations/roles-translations'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { User } from '@models/user'; @Component({ templateUrl: './user-listing-screen.component.html', styleUrls: ['./user-listing-screen.component.scss'], providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => UserListingScreenComponent) }] }) -export class UserListingScreenComponent extends ListingComponent implements OnInit { +export class UserListingScreenComponent extends ListingComponent implements OnInit { readonly translations = rolesTranslations; readonly iconButtonTypes = IconButtonTypes; readonly circleButtonTypes = CircleButtonTypes; readonly currentUser = this.userService.currentUser; readonly canDeleteSelected$ = this._canDeleteSelected$; readonly tableHeaderLabel = _('user-listing.table-header.title'); - tableColumnConfigs: TableColumnConfig[]; + tableColumnConfigs: TableColumnConfig[]; collapsedDetails = false; chartData: DoughnutChartConfig[] = []; @ViewChild('nameTemplate', { static: true }) nameTemplate: TemplateRef; @ViewChild('emailTemplate', { static: true }) emailTemplate: TemplateRef; @ViewChild('activeTemplate', { static: true }) activeTemplate: TemplateRef; @ViewChild('rolesTemplate', { static: true }) rolesTemplate: TemplateRef; - protected readonly _primaryKey = 'id'; @ViewChildren(InitialsAvatarComponent) private readonly _avatars: QueryList; @@ -62,22 +62,21 @@ export class UserListingScreenComponent extends ListingComponent im async ngOnInit() { this._configureTableColumns(); await this._loadData(); - this.searchService.setSearchKey('searchKey'); } - openAddEditUserDialog($event: MouseEvent, user?: UserWrapper) { + openAddEditUserDialog($event: MouseEvent, user?: User) { this._dialogService.openDialog('addEditUser', $event, user, async () => { await this._loadData(); }); } - openDeleteUsersDialog(users: UserWrapper[], $event?: MouseEvent) { + openDeleteUsersDialog(users: User[], $event?: MouseEvent) { this._dialogService.openDialog('deleteUsers', $event, users, async () => { await this._loadData(); }); } - getDisplayRoles(user: UserWrapper) { + getDisplayRoles(user: User) { const separator = ', '; return ( user.roles.map(role => this._translateService.instant(this.translations[role])).join(separator) || @@ -85,10 +84,10 @@ export class UserListingScreenComponent extends ListingComponent im ); } - async toggleActive(user: UserWrapper) { + async toggleActive(user: User) { this._loadingService.start(); - user.roles = user.isActive ? [] : ['RED_USER']; - await this._userControllerService.updateProfile(user, user.id).toPromise(); + const requestBody = { ...user, roles: user.isActive ? [] : ['RED_USER'] }; + await this._userControllerService.updateProfile(requestBody, user.id).toPromise(); await this._loadData(); this._avatars.find(item => item.userId === user.id).detectChanges(); } diff --git a/apps/red-ui/src/app/modules/admin/translations/dossier-attribute-types-translations.ts b/apps/red-ui/src/app/modules/admin/translations/dossier-attribute-types-translations.ts index bb325e3c9..7c24b71e2 100644 --- a/apps/red-ui/src/app/modules/admin/translations/dossier-attribute-types-translations.ts +++ b/apps/red-ui/src/app/modules/admin/translations/dossier-attribute-types-translations.ts @@ -1,7 +1,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -import { DossierAttributeConfig } from '@redaction/red-ui-http'; +import { DossierAttributeConfigType } from '@redaction/red-ui-http'; -export const dossierAttributeTypesTranslations: { [key in DossierAttributeConfig.TypeEnum]: string } = { +export const dossierAttributeTypesTranslations: { [key in DossierAttributeConfigType]: string } = { TEXT: _('dossier-attribute-types.text'), NUMBER: _('dossier-attribute-types.number'), DATE: _('dossier-attribute-types.date'), diff --git a/apps/red-ui/src/app/modules/admin/translations/file-attribute-types-translations.ts b/apps/red-ui/src/app/modules/admin/translations/file-attribute-types-translations.ts index 5262ab6c9..84898cdb8 100644 --- a/apps/red-ui/src/app/modules/admin/translations/file-attribute-types-translations.ts +++ b/apps/red-ui/src/app/modules/admin/translations/file-attribute-types-translations.ts @@ -1,7 +1,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -import { FileAttributeConfig } from '@redaction/red-ui-http'; +import { FileAttributeConfigType } from '@redaction/red-ui-http'; -export const fileAttributeTypesTranslations: { [key in FileAttributeConfig.TypeEnum]: string } = { +export const fileAttributeTypesTranslations: { [key in FileAttributeConfigType]: string } = { TEXT: _('file-attribute-types.text'), NUMBER: _('file-attribute-types.number'), DATE: _('file-attribute-types.date') diff --git a/apps/red-ui/src/app/modules/dossier/components/bulk-actions/dossier-overview-bulk-actions.component.ts b/apps/red-ui/src/app/modules/dossier/components/bulk-actions/dossier-overview-bulk-actions.component.ts index adf787f8f..f98e39318 100644 --- a/apps/red-ui/src/app/modules/dossier/components/bulk-actions/dossier-overview-bulk-actions.component.ts +++ b/apps/red-ui/src/app/modules/dossier/components/bulk-actions/dossier-overview-bulk-actions.component.ts @@ -2,7 +2,7 @@ import { Component, EventEmitter, Output } from '@angular/core'; import { AppStateService } from '@state/app-state.service'; import { FileManagementControllerService, ReanalysisControllerService } from '@redaction/red-ui-http'; import { PermissionsService } from '@services/permissions.service'; -import { FileStatusWrapper } from '@models/file/file-status.wrapper'; +import { File } from '@models/file/file'; import { FileActionService } from '../../services/file-action.service'; import { Observable } from 'rxjs'; import { DossiersDialogService } from '../../services/dossiers-dialog.service'; @@ -19,8 +19,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; export class DossierOverviewBulkActionsComponent { readonly circleButtonTypes = CircleButtonTypes; - @Output() - reload = new EventEmitter(); + @Output() readonly reload = new EventEmitter(); constructor( private readonly _appStateService: AppStateService, @@ -31,14 +30,14 @@ export class DossierOverviewBulkActionsComponent { private readonly _fileActionService: FileActionService, private readonly _loadingService: LoadingService, private readonly _translateService: TranslateService, - private readonly _entitiesService: EntitiesService + private readonly _entitiesService: EntitiesService ) {} get dossier() { return this._appStateService?.activeDossier; } - get selectedFiles(): FileStatusWrapper[] { + get selectedFiles(): File[] { return this._entitiesService.selected; } @@ -91,21 +90,18 @@ export class DossierOverviewBulkActionsComponent { return this.selectedFiles.reduce((acc, file) => acc && file.canBeOCRed, true); } - get fileStatuses() { - return this.selectedFiles.map(file => file.fileStatus.status); + get files() { + return this.selectedFiles.map(file => file.status); } - // Under review get canSetToUnderReview() { return this.selectedFiles.reduce((acc, file) => acc && this._permissionsService.canSetUnderReview(file), true); } - // Under approval get canSetToUnderApproval() { return this.selectedFiles.reduce((acc, file) => acc && this._permissionsService.canSetUnderApproval(file), true); } - // Approve get isReadyForApproval() { return this.selectedFiles.reduce((acc, file) => acc && this._permissionsService.isReadyForApproval(file), true); } @@ -114,7 +110,6 @@ export class DossierOverviewBulkActionsComponent { return this.selectedFiles.reduce((acc, file) => acc && file.canBeApproved, true); } - // Undo approval get canUndoApproval() { return this.selectedFiles.reduce((acc, file) => acc && this._permissionsService.canUndoApproval(file), true); } @@ -156,7 +151,7 @@ export class DossierOverviewBulkActionsComponent { this._assignFiles('approver', true); } else { this._performBulkAction( - this._fileActionService.setFileUnderApproval(this.selectedFiles, this._appStateService.activeDossier.approverIds[0]) + this._fileActionService.setFilesUnderApproval(this.selectedFiles, this._appStateService.activeDossier.approverIds[0]) ); } } @@ -164,16 +159,16 @@ export class DossierOverviewBulkActionsComponent { async reanalyse() { const fileIds = this.selectedFiles.filter(file => file.analysisRequired).map(file => file.fileId); this._performBulkAction( - this._reanalysisControllerService.reanalyzeFilesForDossier(fileIds, this._appStateService.activeDossier.dossierId) + this._reanalysisControllerService.reanalyzeFilesForDossier(fileIds, this._appStateService.activeDossier.id) ); } ocr() { - this._performBulkAction(this._fileActionService.ocrFile(this.selectedFiles)); + this._performBulkAction(this._fileActionService.ocrFiles(this.selectedFiles)); } setToUnderReview() { - this._performBulkAction(this._fileActionService.setFileUnderReview(this.selectedFiles)); + this._performBulkAction(this._fileActionService.setFilesUnderReview(this.selectedFiles)); } approveDocuments() { @@ -187,11 +182,11 @@ export class DossierOverviewBulkActionsComponent { question: _('confirmation-dialog.approve-multiple-files.question') }), () => { - this._performBulkAction(this._fileActionService.setFileApproved(this.selectedFiles)); + this._performBulkAction(this._fileActionService.setFilesApproved(this.selectedFiles)); } ); } else { - this._performBulkAction(this._fileActionService.setFileApproved(this.selectedFiles)); + this._performBulkAction(this._fileActionService.setFilesApproved(this.selectedFiles)); } } 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 899820d09..638890d3d 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 @@ -3,7 +3,7 @@ import { FileAttributesConfig } from '@redaction/red-ui-http'; import { AppStateService } from '@state/app-state.service'; import { DossiersDialogService } from '../../services/dossiers-dialog.service'; import { AutoUnsubscribe } from '@iqser/common-ui'; -import { FileStatusWrapper } from '@models/file/file-status.wrapper'; +import { File } from '@models/file/file'; @Component({ selector: 'redaction-document-info', @@ -11,7 +11,7 @@ import { FileStatusWrapper } from '@models/file/file-status.wrapper'; styleUrls: ['./document-info.component.scss'] }) export class DocumentInfoComponent extends AutoUnsubscribe implements OnInit { - @Input() file: FileStatusWrapper; + @Input() file: File; @Output() closeDocumentInfoView = new EventEmitter(); fileAttributesConfig: FileAttributesConfig; diff --git a/apps/red-ui/src/app/modules/dossier/components/dossier-details-stats/dossier-details-stats.component.html b/apps/red-ui/src/app/modules/dossier/components/dossier-details-stats/dossier-details-stats.component.html index 41a6e3db3..e237e4559 100644 --- a/apps/red-ui/src/app/modules/dossier/components/dossier-details-stats/dossier-details-stats.component.html +++ b/apps/red-ui/src/app/modules/dossier/components/dossier-details-stats/dossier-details-stats.component.html @@ -4,7 +4,7 @@
- {{ 'dossier-overview.dossier-details.stats.people' | translate: { count: activeDossier.memberCount } }} + {{ 'dossier-overview.dossier-details.stats.people' | translate: { count: activeDossier.memberIds.length } }}
diff --git a/apps/red-ui/src/app/modules/dossier/components/dossier-details-stats/dossier-details-stats.component.scss b/apps/red-ui/src/app/modules/dossier/components/dossier-details-stats/dossier-details-stats.component.scss index dd9794cb1..a4e86e553 100644 --- a/apps/red-ui/src/app/modules/dossier/components/dossier-details-stats/dossier-details-stats.component.scss +++ b/apps/red-ui/src/app/modules/dossier/components/dossier-details-stats/dossier-details-stats.component.scss @@ -14,7 +14,7 @@ border-radius: 4px; width: 100%; justify-content: flex-start; - padding: 0 8px; + padding: 4px 8px; margin-left: -8px; &.link-property { diff --git a/apps/red-ui/src/app/modules/dossier/components/dossier-details-stats/dossier-details-stats.component.ts b/apps/red-ui/src/app/modules/dossier/components/dossier-details-stats/dossier-details-stats.component.ts index 2b8bb00a2..045dec7e8 100644 --- a/apps/red-ui/src/app/modules/dossier/components/dossier-details-stats/dossier-details-stats.component.ts +++ b/apps/red-ui/src/app/modules/dossier/components/dossier-details-stats/dossier-details-stats.component.ts @@ -1,8 +1,8 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { DossierAttributeWithValue } from '@models/dossier-attributes.model'; import { AppStateService } from '@state/app-state.service'; -import { DossierWrapper } from '@state/model/dossier.wrapper'; -import { DossierTemplateModel } from '@redaction/red-ui-http'; +import { Dossier } from '@state/model/dossier'; +import { IDossierTemplate } from '@redaction/red-ui-http'; import { DossiersDialogService } from '../../services/dossiers-dialog.service'; @Component({ @@ -13,21 +13,21 @@ import { DossiersDialogService } from '../../services/dossiers-dialog.service'; export class DossierDetailsStatsComponent { attributesExpanded = false; @Input() dossierAttributes: DossierAttributeWithValue[]; - @Output() openDossierDictionaryDialog = new EventEmitter(); + @Output() readonly openDossierDictionaryDialog = new EventEmitter(); constructor(private readonly _appStateService: AppStateService, private readonly _dialogService: DossiersDialogService) {} - get activeDossier(): DossierWrapper { + get activeDossier(): Dossier { return this._appStateService.activeDossier; } - get dossierTemplate(): DossierTemplateModel { + get dossierTemplate(): IDossierTemplate { return this._appStateService.getDossierTemplateById(this.activeDossier.dossierTemplateId); } openEditDossierAttributesDialog() { this._dialogService.openDialog('editDossier', null, { - dossierWrapper: this.activeDossier, + dossier: this.activeDossier, section: 'dossierAttributes' }); } diff --git a/apps/red-ui/src/app/modules/dossier/components/dossier-details/dossier-details.component.html b/apps/red-ui/src/app/modules/dossier/components/dossier-details/dossier-details.component.html index 53e587bae..056f88103 100644 --- a/apps/red-ui/src/app/modules/dossier/components/dossier-details/dossier-details.component.html +++ b/apps/red-ui/src/app/modules/dossier/components/dossier-details/dossier-details.component.html @@ -50,7 +50,7 @@
diff --git a/apps/red-ui/src/app/modules/dossier/components/dossier-details/dossier-details.component.ts b/apps/red-ui/src/app/modules/dossier/components/dossier-details/dossier-details.component.ts index 5b8d6a7c1..4c0d85d8a 100644 --- a/apps/red-ui/src/app/modules/dossier/components/dossier-details/dossier-details.component.ts +++ b/apps/red-ui/src/app/modules/dossier/components/dossier-details/dossier-details.component.ts @@ -4,12 +4,13 @@ import { groupBy } from '@utils/functions'; import { DoughnutChartConfig } from '@shared/components/simple-doughnut-chart/simple-doughnut-chart.component'; import { TranslateChartService } from '@services/translate-chart.service'; import { StatusSorter } from '@utils/sorters/status-sorter'; -import { UserService, UserWrapper } from '@services/user.service'; -import { Toaster } from '@iqser/common-ui'; -import { FilterService } from '@iqser/common-ui'; +import { UserService } from '@services/user.service'; +import { FilterService, Toaster } from '@iqser/common-ui'; import { DossierAttributeWithValue } from '@models/dossier-attributes.model'; import { fileStatusTranslations } from '../../translations/file-status-translations'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { List } from '@redaction/red-ui-http'; +import { User } from '@models/user'; @Component({ selector: 'redaction-dossier-details', @@ -18,12 +19,12 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; }) export class DossierDetailsComponent implements OnInit { documentsChartData: DoughnutChartConfig[] = []; - owner: UserWrapper; + owner: User; editingOwner = false; @Input() dossierAttributes: DossierAttributeWithValue[]; - @Output() openAssignDossierMembersDialog = new EventEmitter(); - @Output() openDossierDictionaryDialog = new EventEmitter(); - @Output() toggleCollapse = new EventEmitter(); + @Output() readonly openAssignDossierMembersDialog = new EventEmitter(); + @Output() readonly openDossierDictionaryDialog = new EventEmitter(); + @Output() readonly toggleCollapse = new EventEmitter(); collapseTooltip = _('dossier-details.collapse'); expandTooltip = _('dossier-details.expand'); @@ -39,7 +40,7 @@ export class DossierDetailsComponent implements OnInit { private readonly _toaster: Toaster ) {} - get memberIds(): string[] { + get memberIds(): List { return this.appStateService.activeDossier.memberIds; } @@ -66,12 +67,12 @@ export class DossierDetailsComponent implements OnInit { const groups = groupBy(this.appStateService.activeDossier?.files, 'status'); this.documentsChartData = []; - for (const key of Object.keys(groups)) { + for (const status of Object.keys(groups)) { this.documentsChartData.push({ - value: groups[key].length, - color: key, - label: fileStatusTranslations[key], - key: key + value: groups[status].length, + color: status, + label: fileStatusTranslations[status], + key: status }); } this.documentsChartData.sort(StatusSorter.byStatus); @@ -79,7 +80,7 @@ export class DossierDetailsComponent implements OnInit { this._changeDetectorRef.detectChanges(); } - async assignOwner(user: UserWrapper | string) { + async assignOwner(user: User | string) { this.owner = typeof user === 'string' ? this._userService.getRedUserById(user) : user; const dw = { ...this.appStateService.activeDossier, ownerId: this.owner.id }; await this.appStateService.createOrUpdateDossier(dw); diff --git a/apps/red-ui/src/app/modules/dossier/components/dossier-listing-actions/dossier-listing-actions.component.ts b/apps/red-ui/src/app/modules/dossier/components/dossier-listing-actions/dossier-listing-actions.component.ts index 4699138eb..9493e4fee 100644 --- a/apps/red-ui/src/app/modules/dossier/components/dossier-listing-actions/dossier-listing-actions.component.ts +++ b/apps/red-ui/src/app/modules/dossier/components/dossier-listing-actions/dossier-listing-actions.component.ts @@ -1,6 +1,6 @@ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; import { PermissionsService } from '@services/permissions.service'; -import { DossierWrapper } from '@state/model/dossier.wrapper'; +import { Dossier } from '../../../../state/model/dossier'; import { StatusSorter } from '@utils/sorters/status-sorter'; import { AppStateService } from '@state/app-state.service'; import { DossiersDialogService } from '../../services/dossiers-dialog.service'; @@ -17,8 +17,8 @@ export class DossierListingActionsComponent { readonly circleButtonTypes = CircleButtonTypes; readonly currentUser = this._userService.currentUser; - @Input() dossier: DossierWrapper; - @Output() actionPerformed = new EventEmitter(); + @Input() dossier: Dossier; + @Output() readonly actionPerformed = new EventEmitter(); constructor( readonly permissionsService: PermissionsService, @@ -27,14 +27,14 @@ export class DossierListingActionsComponent { private readonly _userService: UserService ) {} - openEditDossierDialog($event: MouseEvent, dossierWrapper: DossierWrapper): void { + openEditDossierDialog($event: MouseEvent, dossier: Dossier): void { this._dialogService.openDialog('editDossier', $event, { - dossierWrapper, + dossier, afterSave: () => this.actionPerformed.emit() }); } - reanalyseDossier($event: MouseEvent, dossier: DossierWrapper): void { + reanalyseDossier($event: MouseEvent, dossier: Dossier): void { $event.stopPropagation(); this.appStateService.reanalyzeDossier(dossier).then(() => { this.appStateService.loadAllDossiers().then(() => this.actionPerformed.emit()); diff --git a/apps/red-ui/src/app/modules/dossier/components/file-actions/file-actions.component.html b/apps/red-ui/src/app/modules/dossier/components/file-actions/file-actions.component.html index de9884ca6..8d4e6e637 100644 --- a/apps/red-ui/src/app/modules/dossier/components/file-actions/file-actions.component.html +++ b/apps/red-ui/src/app/modules/dossier/components/file-actions/file-actions.component.html @@ -1,17 +1,26 @@ -
+
- +
- + - -
+ +
+ + @@ -100,7 +107,7 @@
*:not(:last-child) { margin-right: 2px; diff --git a/apps/red-ui/src/app/modules/dossier/components/file-actions/file-actions.component.ts b/apps/red-ui/src/app/modules/dossier/components/file-actions/file-actions.component.ts index 2057d0114..01c179aa4 100644 --- a/apps/red-ui/src/app/modules/dossier/components/file-actions/file-actions.component.ts +++ b/apps/red-ui/src/app/modules/dossier/components/file-actions/file-actions.component.ts @@ -1,17 +1,17 @@ import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core'; import { PermissionsService } from '@services/permissions.service'; -import { FileStatusWrapper } from '@models/file/file-status.wrapper'; +import { File } from '@models/file/file'; import { AppStateService } from '@state/app-state.service'; import { FileActionService } from '../../services/file-action.service'; import { DossiersDialogService } from '../../services/dossiers-dialog.service'; import { ConfirmationDialogInput } from '@shared/dialogs/confirmation-dialog/confirmation-dialog.component'; -import { AutoUnsubscribe, CircleButtonType, CircleButtonTypes, LoadingService, StatusBarConfig, Toaster } from '@iqser/common-ui'; +import { AutoUnsubscribe, CircleButtonType, CircleButtonTypes, LoadingService, Required, StatusBarConfig, Toaster } from '@iqser/common-ui'; import { FileManagementControllerService, FileStatus } from '@redaction/red-ui-http'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { UserService } from '@services/user.service'; import { filter } from 'rxjs/operators'; -import { UserPreferenceService } from '../../../../services/user-preference.service'; -import { LongPressEvent } from '../../../shared/directives/long-press.directive'; +import { UserPreferenceService } from '@services/user-preference.service'; +import { LongPressEvent } from '@shared/directives/long-press.directive'; @Component({ selector: 'redaction-file-actions', @@ -22,28 +22,32 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD readonly circleButtonTypes = CircleButtonTypes; readonly currentUser = this._userService.currentUser; - @Input() fileStatus: FileStatusWrapper; + @Input() file: File; @Input() activeDocumentInfo: boolean; @Input() activeExcludePages: boolean; - @Output() actionPerformed = new EventEmitter(); + @Input() @Required() type: 'file-preview' | 'dossier-overview-list' | 'dossier-overview-workflow'; + @Output() readonly actionPerformed = new EventEmitter(); - screen: 'file-preview' | 'dossier-overview'; - statusBarConfig?: readonly StatusBarConfig[]; + statusBarConfig?: readonly StatusBarConfig[]; tooltipPosition?: 'below' | 'above'; toggleTooltip?: string; assignTooltip?: string; buttonType?: CircleButtonType; - isWorkable: boolean; - canUndoApproval: boolean; - canAssignToSelf: boolean; - canAssign: boolean; - canDelete: boolean; + showUndoApproval: boolean; + showAssignToSelf: boolean; + showAssign: boolean; + showDelete: boolean; + showOCR: boolean; canReanalyse: boolean; - canSetToUnderReview: boolean; - canSetToUnderApproval: boolean; - readyForApproval: boolean; + showUnderReview: boolean; + showUnderApproval: boolean; + showApprove: boolean; canToggleAnalysis: boolean; + showExcludePages: boolean; + showDocumentInfo: boolean; + showStatusBar: boolean; + showOpenDocument: boolean; constructor( readonly permissionsService: PermissionsService, @@ -59,29 +63,39 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD super(); } + get isDossierOverviewList(): boolean { + return this.type === 'dossier-overview-list'; + } + + get isDossierOverviewWorkflow(): boolean { + return this.type === 'dossier-overview-workflow'; + } + + get isFilePreview(): boolean { + return this.type === 'file-preview'; + } + + get isDossierOverview(): boolean { + return this.type.startsWith('dossier-overview-list'); + } + private get _toggleTooltip(): string { if (!this.currentUser.isManager) { return _('file-preview.toggle-analysis.only-managers'); } - return this.fileStatus?.excluded ? _('file-preview.toggle-analysis.enable') : _('file-preview.toggle-analysis.disable'); + return this.file?.excluded ? _('file-preview.toggle-analysis.enable') : _('file-preview.toggle-analysis.disable'); } ngOnInit(): void { - if (this.fileStatus) { - this.screen = 'dossier-overview'; - } else { - this.fileStatus = this.appStateService.activeFile; - this.screen = 'file-preview'; + if (!this.file) { + this.file = this.appStateService.activeFile; } - this._setup(); - this.addSubscription = this.appStateService.fileChanged$ - .pipe(filter(file => file.fileId === this.fileStatus?.fileId)) - .subscribe(fileStatus => { - this.fileStatus = fileStatus; - this._setup(); - }); + this.addSubscription = this.appStateService.fileChanged$.pipe(filter(file => file.fileId === this.file?.fileId)).subscribe(file => { + this.file = file; + this._setup(); + }); this.addSubscription = this.appStateService.dossierChanged$.subscribe(() => { this._setup(); @@ -96,6 +110,10 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD this.actionPerformed.emit('view-exclude-pages'); } + openDocument() { + this.actionPerformed.emit('navigate'); + } + openDeleteFileDialog($event: MouseEvent) { this._dialogService.openDialog( 'confirm', @@ -107,7 +125,7 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD async () => { this._loadingService.start(); await this._fileManagementControllerService - .deleteFiles([this.fileStatus.fileId], this.fileStatus.dossierId) + .deleteFiles([this.file.fileId], this.file.dossierId) .toPromise() .catch(error => { this._toaster.error(_('error.http.generic'), { params: error }); @@ -120,8 +138,8 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD } assign($event: MouseEvent) { - const mode = this.fileStatus.isUnderApproval ? 'approver' : 'reviewer'; - const files = [this.fileStatus]; + const mode = this.file.isUnderApproval ? 'approver' : 'reviewer'; + const files = [this.file]; this._dialogService.openDialog('assignFile', $event, { mode, files }, () => { this.actionPerformed.emit('assign-reviewer'); }); @@ -130,7 +148,7 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD async assignToMe($event: MouseEvent) { $event.stopPropagation(); - await this._fileActionService.assignToMe(this.fileStatus, () => { + await this._fileActionService.assignToMe([this.file], () => { this.reloadDossiers('reanalyse'); }); } @@ -139,7 +157,7 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD if ($event) { $event.stopPropagation(); } - this.addSubscription = this._fileActionService.reanalyseFile(this.fileStatus).subscribe(() => { + this.addSubscription = this._fileActionService.reanalyseFile(this.file).subscribe(() => { this.reloadDossiers('reanalyse'); }); } @@ -147,9 +165,9 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD setFileUnderApproval($event: MouseEvent) { $event.stopPropagation(); if (this.appStateService.activeDossier.approverIds.length > 1) { - this._fileActionService.assignFile('approver', $event, this.fileStatus, () => this.reloadDossiers('assign-reviewer'), true); + this._fileActionService.assignFile('approver', $event, this.file, () => this.reloadDossiers('assign-reviewer'), true); } else { - this.addSubscription = this._fileActionService.setFileUnderApproval(this.fileStatus).subscribe(() => { + this.addSubscription = this._fileActionService.setFilesUnderApproval([this.file]).subscribe(() => { this.reloadDossiers('set-under-approval'); }); } @@ -157,7 +175,7 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD setFileApproved($event: MouseEvent) { $event.stopPropagation(); - if (this.fileStatus.hasUpdates) { + if (this.file.hasUpdates) { this._dialogService.openDialog( 'confirm', $event, @@ -176,7 +194,7 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD ocrFile($event: MouseEvent) { $event.stopPropagation(); - this.addSubscription = this._fileActionService.ocrFile(this.fileStatus).subscribe(() => { + this.addSubscription = this._fileActionService.ocrFiles([this.file]).subscribe(() => { this.reloadDossiers('ocr-file'); }); } @@ -185,7 +203,7 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD this._fileActionService.assignFile( 'reviewer', $event, - this.fileStatus, + this.file, () => this.reloadDossiers('assign-reviewer'), ignoreDialogChanges ); @@ -198,47 +216,54 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD } async toggleAnalysis() { - await this._fileActionService.toggleAnalysis(this.fileStatus).toPromise(); + await this._fileActionService.toggleAnalysis(this.file).toPromise(); await this.appStateService.getFiles(); - this.actionPerformed.emit(this.fileStatus?.excluded ? 'enable-analysis' : 'disable-analysis'); + this.actionPerformed.emit(this.file?.excluded ? 'enable-analysis' : 'disable-analysis'); } ngOnChanges(changes: SimpleChanges): void { - if (changes.fileStatus) { + if (changes.file) { this._setup(); } } forceReanalysisAction($event: LongPressEvent) { if (this._userPreferenceService.areDevFeaturesEnabled) { - this.canReanalyse = $event.touchEnd ? this.permissionsService.canReanalyseFile(this.fileStatus) : true; + this.canReanalyse = $event.touchEnd ? this.permissionsService.canReanalyseFile(this.file) : true; } } private _setFileApproved() { - this.addSubscription = this._fileActionService.setFileApproved(this.fileStatus).subscribe(() => { + this.addSubscription = this._fileActionService.setFilesApproved([this.file]).subscribe(() => { this.reloadDossiers('set-approved'); }); } private _setup() { - this.statusBarConfig = [{ color: this.fileStatus.status, length: 1 }]; - this.tooltipPosition = this.screen === 'file-preview' ? 'below' : 'above'; - this.assignTooltip = this.fileStatus.isUnderApproval - ? _('dossier-overview.assign-approver') - : _('dossier-overview.assign-reviewer'); - this.buttonType = this.screen === 'file-preview' ? CircleButtonTypes.default : CircleButtonTypes.dark; - this.isWorkable = this.fileStatus.isWorkable; + this.statusBarConfig = [{ color: this.file.status, length: 1 }]; + this.tooltipPosition = this.isFilePreview ? 'below' : 'above'; + this.assignTooltip = this.file.isUnderApproval ? _('dossier-overview.assign-approver') : _('dossier-overview.assign-reviewer'); + this.buttonType = this.isFilePreview ? CircleButtonTypes.default : CircleButtonTypes.dark; this.toggleTooltip = this._toggleTooltip; - this.canUndoApproval = this.permissionsService.canUndoApproval(this.fileStatus); - this.canAssignToSelf = this.permissionsService.canAssignToSelf(this.fileStatus); - this.canAssign = this.permissionsService.canAssignUser(this.fileStatus); - this.canDelete = this.permissionsService.canDeleteFile(this.fileStatus); - this.canReanalyse = this.permissionsService.canReanalyseFile(this.fileStatus); - this.canSetToUnderReview = this.permissionsService.canSetUnderReview(this.fileStatus); - this.canSetToUnderApproval = this.permissionsService.canSetUnderApproval(this.fileStatus); - this.readyForApproval = this.permissionsService.isReadyForApproval(this.fileStatus); - this.canToggleAnalysis = this.permissionsService.canToggleAnalysis(this.fileStatus); + this.showUndoApproval = this.permissionsService.canUndoApproval(this.file) && !this.isDossierOverviewWorkflow; + this.showUnderReview = this.permissionsService.canSetUnderReview(this.file) && !this.isDossierOverviewWorkflow; + this.showUnderApproval = this.permissionsService.canSetUnderApproval(this.file) && !this.isDossierOverviewWorkflow; + this.showApprove = this.permissionsService.isReadyForApproval(this.file) && !this.isDossierOverviewWorkflow; + + this.canToggleAnalysis = this.permissionsService.canToggleAnalysis(this.file); + this.showDelete = this.permissionsService.canDeleteFile(this.file); + this.showOCR = this.file.canBeOCRed; + this.canReanalyse = this.permissionsService.canReanalyseFile(this.file); + + this.showStatusBar = this.file.isWorkable && this.isDossierOverviewList; + + this.showAssignToSelf = this.permissionsService.canAssignToSelf(this.file) && this.isDossierOverview; + this.showAssign = this.permissionsService.canAssignUser(this.file) && this.isDossierOverview; + + this.showOpenDocument = this.file.canBeOpened && this.isDossierOverviewWorkflow; + + this.showExcludePages = this.isFilePreview; + this.showDocumentInfo = this.isFilePreview; } } diff --git a/apps/red-ui/src/app/modules/dossier/components/file-workload/file-workload.component.html b/apps/red-ui/src/app/modules/dossier/components/file-workload/file-workload.component.html index 05ec345ea..31e2e95ba 100644 --- a/apps/red-ui/src/app/modules/dossier/components/file-workload/file-workload.component.html +++ b/apps/red-ui/src/app/modules/dossier/components/file-workload/file-workload.component.html @@ -93,7 +93,7 @@
- + {{ 'file-preview.tabs.annotations.page-is' | translate }}
@@ -187,7 +187,7 @@
diff --git a/apps/red-ui/src/app/modules/dossier/components/file-workload/file-workload.component.ts b/apps/red-ui/src/app/modules/dossier/components/file-workload/file-workload.component.ts index e58b9455b..a0fc2b05a 100644 --- a/apps/red-ui/src/app/modules/dossier/components/file-workload/file-workload.component.ts +++ b/apps/red-ui/src/app/modules/dossier/components/file-workload/file-workload.component.ts @@ -3,7 +3,7 @@ import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { AnnotationProcessingService } from '../../services/annotation-processing.service'; import { MatDialogRef, MatDialogState } from '@angular/material/dialog'; import scrollIntoView from 'scroll-into-view-if-needed'; -import { CircleButtonTypes, Debounce, FilterService, IconButtonTypes, IqserEventTarget, NestedFilter } from '@iqser/common-ui'; +import { CircleButtonTypes, Debounce, FilterService, IconButtonTypes, INestedFilter, IqserEventTarget } from '@iqser/common-ui'; import { FileDataModel } from '@models/file/file-data.model'; import { PermissionsService } from '@services/permissions.service'; import { WebViewerInstance } from '@pdftron/webviewer'; @@ -43,8 +43,10 @@ export class FileWorkloadComponent { @Output() readonly actionPerformed = new EventEmitter(); displayedPages: number[] = []; pagesPanelActive = true; + readonly displayedAnnotations$ = this._displayedAnnotations$; @ViewChild('annotationsElement') private readonly _annotationsElement: ElementRef; @ViewChild('quickNavigation') private readonly _quickNavigationElement: ElementRef; + private _annotations$ = new BehaviorSubject([]); constructor( private readonly _permissionsService: PermissionsService, @@ -53,9 +55,6 @@ export class FileWorkloadComponent { private readonly _annotationProcessingService: AnnotationProcessingService ) {} - private _annotations$ = new BehaviorSubject([]); - readonly displayedAnnotations$ = this._displayedAnnotations$; - @Input() set annotations(value: AnnotationWrapper[]) { this._annotations$.next(value); @@ -78,7 +77,7 @@ export class FileWorkloadComponent { } get isProcessing(): boolean { - return this.fileData?.fileStatus?.isProcessing; + return this.fileData?.file?.isProcessing; } get activeAnnotations(): AnnotationWrapper[] | undefined { @@ -93,6 +92,14 @@ export class FileWorkloadComponent { return this.selectedAnnotations?.length ? this.selectedAnnotations[0] : null; } + private get _displayedAnnotations$(): Observable> { + const primary$ = this._filterService.getFilterModels$('primaryFilters'); + const secondary$ = this._filterService.getFilterModels$('secondaryFilters'); + return combineLatest([this._annotations$, primary$, secondary$]).pipe( + map(([annotations, primary, secondary]) => this._filterAnnotations(annotations, primary, secondary)) + ); + } + private static _scrollToFirstElement(elements: HTMLElement[], mode: 'always' | 'if-needed' = 'if-needed') { if (elements.length > 0) { scrollIntoView(elements[0], { @@ -120,19 +127,6 @@ export class FileWorkloadComponent { this.deselectAnnotations.emit(this.activeAnnotations); } - private _filterAnnotations( - annotations: AnnotationWrapper[], - primary: NestedFilter[], - secondary: NestedFilter[] = [] - ): Map { - if (!primary) { - return; - } - this.displayedAnnotations = this._annotationProcessingService.filterAndGroupAnnotations(annotations, primary, secondary); - this.displayedPages = [...this.displayedAnnotations.keys()]; - return this.displayedAnnotations; - } - @HostListener('window:keyup', ['$event']) handleKeyEvent($event: KeyboardEvent): void { if ( @@ -210,7 +204,7 @@ export class FileWorkloadComponent { } scrollQuickNavLast(): void { - this.selectPage.emit(this.fileData.fileStatus.numberOfPages); + this.selectPage.emit(this.fileData.file.numberOfPages); } pageSelectedByClick($event: number): void { @@ -232,12 +226,17 @@ export class FileWorkloadComponent { this.selectPage.emit(this._nextPageWithAnnotations()); } - private get _displayedAnnotations$(): Observable> { - const primary$ = this._filterService.getFilterModels$('primaryFilters'); - const secondary$ = this._filterService.getFilterModels$('secondaryFilters'); - return combineLatest([this._annotations$, primary$, secondary$]).pipe( - map(([annotations, primary, secondary]) => this._filterAnnotations(annotations, primary, secondary)) - ); + private _filterAnnotations( + annotations: AnnotationWrapper[], + primary: INestedFilter[], + secondary: INestedFilter[] = [] + ): Map { + if (!primary) { + return; + } + this.displayedAnnotations = this._annotationProcessingService.filterAndGroupAnnotations(annotations, primary, secondary); + this.displayedPages = [...this.displayedAnnotations.keys()]; + return this.displayedAnnotations; } private _selectFirstAnnotationOnCurrentPageIfNecessary() { diff --git a/apps/red-ui/src/app/modules/dossier/components/needs-work-badge/needs-work-badge.component.ts b/apps/red-ui/src/app/modules/dossier/components/needs-work-badge/needs-work-badge.component.ts index bb205433f..b04bb5e76 100644 --- a/apps/red-ui/src/app/modules/dossier/components/needs-work-badge/needs-work-badge.component.ts +++ b/apps/red-ui/src/app/modules/dossier/components/needs-work-badge/needs-work-badge.component.ts @@ -1,7 +1,7 @@ import { Component, Input } from '@angular/core'; import { AppStateService } from '@state/app-state.service'; -import { FileStatusWrapper } from '@models/file/file-status.wrapper'; -import { DossierWrapper } from '@state/model/dossier.wrapper'; +import { File } from '@models/file/file'; +import { Dossier } from '../../../../state/model/dossier'; @Component({ selector: 'redaction-needs-work-badge', @@ -9,7 +9,7 @@ import { DossierWrapper } from '@state/model/dossier.wrapper'; styleUrls: ['./needs-work-badge.component.scss'] }) export class NeedsWorkBadgeComponent { - @Input() needsWorkInput: FileStatusWrapper | DossierWrapper; + @Input() needsWorkInput: File | Dossier; constructor(private readonly _appStateService: AppStateService) {} @@ -38,19 +38,19 @@ export class NeedsWorkBadgeComponent { } get hasImages() { - return this.needsWorkInput instanceof FileStatusWrapper && this.needsWorkInput.hasImages; + return this.needsWorkInput instanceof File && this.needsWorkInput.hasImages; } get hasUpdates() { - return this.needsWorkInput instanceof FileStatusWrapper && this.needsWorkInput.hasUpdates; + return this.needsWorkInput instanceof File && this.needsWorkInput.hasUpdates; } get hasAnnotationComments(): boolean { - return this.needsWorkInput instanceof FileStatusWrapper && (this.needsWorkInput).hasAnnotationComments; + return this.needsWorkInput instanceof File && (this.needsWorkInput).hasAnnotationComments; } reanalysisRequired() { - if (this.needsWorkInput instanceof DossierWrapper) { + if (this.needsWorkInput instanceof Dossier) { return this.needsWorkInput.reanalysisRequired; } else { return this.needsWorkInput.analysisRequired; diff --git a/apps/red-ui/src/app/modules/dossier/components/page-exclusion/page-exclusion.component.ts b/apps/red-ui/src/app/modules/dossier/components/page-exclusion/page-exclusion.component.ts index 95c64f892..901096a0a 100644 --- a/apps/red-ui/src/app/modules/dossier/components/page-exclusion/page-exclusion.component.ts +++ b/apps/red-ui/src/app/modules/dossier/components/page-exclusion/page-exclusion.component.ts @@ -1,9 +1,9 @@ import { Component, EventEmitter, Input, OnChanges, Output, ViewChild } from '@angular/core'; import { PermissionsService } from '@services/permissions.service'; import { PageRange, ReanalysisControllerService } from '@redaction/red-ui-http'; -import { InputWithActionComponent, Toaster, LoadingService } from '@iqser/common-ui'; +import { InputWithActionComponent, LoadingService, Toaster } from '@iqser/common-ui'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -import { FileStatusWrapper } from '@models/file/file-status.wrapper'; +import { File } from '@models/file/file'; @Component({ selector: 'redaction-page-exclusion', @@ -11,7 +11,7 @@ import { FileStatusWrapper } from '@models/file/file-status.wrapper'; styleUrls: ['./page-exclusion.component.scss'] }) export class PageExclusionComponent implements OnChanges { - @Input() fileStatus: FileStatusWrapper; + @Input() file: File; @Output() readonly actionPerformed = new EventEmitter(); excludedPagesRanges: PageRange[] = []; @@ -25,7 +25,7 @@ export class PageExclusionComponent implements OnChanges { ) {} ngOnChanges(): void { - const excludedPages = (this.fileStatus?.excludedPages || []).sort((p1, p2) => p1 - p2); + const excludedPages = (this.file?.excludedPages || []).sort((p1, p2) => p1 - p2); this.excludedPagesRanges = excludedPages.reduce((ranges, page) => { if (!ranges.length) { return [{ startPage: page, endPage: page }]; @@ -60,8 +60,8 @@ export class PageExclusionComponent implements OnChanges { { pageRanges: pageRanges }, - this.fileStatus.dossierId, - this.fileStatus.fileId + this.file.dossierId, + this.file.fileId ) .toPromise(); this._inputComponent.reset(); @@ -79,8 +79,8 @@ export class PageExclusionComponent implements OnChanges { { pageRanges: [range] }, - this.fileStatus.dossierId, - this.fileStatus.fileId + this.file.dossierId, + this.file.fileId ) .toPromise(); this._inputComponent.reset(); diff --git a/apps/red-ui/src/app/modules/dossier/components/pdf-viewer/pdf-viewer.component.html b/apps/red-ui/src/app/modules/dossier/components/pdf-viewer/pdf-viewer.component.html index e20a2f31b..251630448 100644 --- a/apps/red-ui/src/app/modules/dossier/components/pdf-viewer/pdf-viewer.component.html +++ b/apps/red-ui/src/app/modules/dossier/components/pdf-viewer/pdf-viewer.component.html @@ -1,5 +1,5 @@
-
+
diff --git a/apps/red-ui/src/app/modules/dossier/components/pdf-viewer/pdf-viewer.component.ts b/apps/red-ui/src/app/modules/dossier/components/pdf-viewer/pdf-viewer.component.ts index 13a55434d..94b20a5d0 100644 --- a/apps/red-ui/src/app/modules/dossier/components/pdf-viewer/pdf-viewer.component.ts +++ b/apps/red-ui/src/app/modules/dossier/components/pdf-viewer/pdf-viewer.component.ts @@ -17,7 +17,7 @@ import { TranslateService } from '@ngx-translate/core'; import { ManualRedactionEntryWrapper } from '@models/file/manual-redaction-entry.wrapper'; import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { ManualAnnotationService } from '../../services/manual-annotation.service'; -import { FileStatusWrapper } from '@models/file/file-status.wrapper'; +import { File } from '@models/file/file'; import { environment } from '@environments/environment'; import { AnnotationDrawService } from '../../services/annotation-draw.service'; import { AnnotationActionsService } from '../../services/annotation-actions.service'; @@ -43,18 +43,18 @@ import Annotation = Core.Annotations.Annotation; }) export class PdfViewerComponent implements OnInit, OnChanges { @Input() fileData: Blob; - @Input() fileStatus: FileStatusWrapper; + @Input() file: File; @Input() canPerformActions = false; @Input() annotations: AnnotationWrapper[]; @Input() shouldDeselectAnnotationsOnPageChange = true; @Input() multiSelectActive: boolean; - @Output() fileReady = new EventEmitter(); - @Output() annotationSelected = new EventEmitter(); - @Output() manualAnnotationRequested = new EventEmitter(); - @Output() pageChanged = new EventEmitter(); - @Output() keyUp = new EventEmitter(); - @Output() viewerReady = new EventEmitter(); - @Output() annotationsChanged = new EventEmitter(); + @Output() readonly fileReady = new EventEmitter(); + @Output() readonly annotationSelected = new EventEmitter(); + @Output() readonly manualAnnotationRequested = new EventEmitter(); + @Output() readonly pageChanged = new EventEmitter(); + @Output() readonly keyUp = new EventEmitter(); + @Output() readonly viewerReady = new EventEmitter(); + @Output() readonly annotationsChanged = new EventEmitter(); @ViewChild('viewer', { static: true }) viewer: ElementRef; @ViewChild('compareFileInput', { static: true }) compareFileInput: ElementRef; instance: WebViewerInstance; @@ -146,7 +146,7 @@ export class PdfViewerComponent implements OnInit, OnChanges { compareDocument, mergedDocument, this.instance, - this.fileStatus, + this.file, () => { this.viewMode = 'COMPARE'; }, @@ -188,7 +188,7 @@ export class PdfViewerComponent implements OnInit, OnChanges { await pdfNet.initialize(environment.licenseKey ? atob(environment.licenseKey) : null); const currentDocument = await pdfNet.PDFDoc.createFromBuffer(await this.fileData.arrayBuffer()); this.instance.UI.loadDocument(currentDocument, { - filename: this.fileStatus ? this.fileStatus.filename : 'document.pdf' + filename: this.file ? this.file.filename : 'document.pdf' }); this.instance.UI.disableElements(['closeCompareButton']); this.instance.UI.enableElements(['compareButton']); @@ -571,7 +571,7 @@ export class PdfViewerComponent implements OnInit, OnChanges { private _loadDocument() { if (this.fileData) { this.instance.UI.loadDocument(this.fileData, { - filename: this.fileStatus ? this.fileStatus.filename : 'document.pdf' + filename: this.file ? this.file.filename : 'document.pdf' }); } } diff --git a/apps/red-ui/src/app/modules/dossier/components/team-members-manager/team-members-manager.component.ts b/apps/red-ui/src/app/modules/dossier/components/team-members-manager/team-members-manager.component.ts index 62cdbb367..be0aef561 100644 --- a/apps/red-ui/src/app/modules/dossier/components/team-members-manager/team-members-manager.component.ts +++ b/apps/red-ui/src/app/modules/dossier/components/team-members-manager/team-members-manager.component.ts @@ -1,10 +1,10 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { Dossier } from '@redaction/red-ui-http'; +import { IDossier } from '@redaction/red-ui-http'; import { AppStateService } from '@state/app-state.service'; import { UserService } from '@services/user.service'; import { Toaster } from '@iqser/common-ui'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; -import { DossierWrapper } from '@state/model/dossier.wrapper'; +import { Dossier } from '../../../../state/model/dossier'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; @Component({ @@ -16,9 +16,9 @@ export class TeamMembersManagerComponent implements OnInit { teamForm: FormGroup; searchQuery = ''; - @Input() dossierWrapper: DossierWrapper; + @Input() dossier: Dossier; + @Output() readonly save = new EventEmitter(); - @Output() readonly save = new EventEmitter(); readonly ownersSelectOptions = this.userService.managerUsers.map(m => m.id); selectedReviewersList: string[] = []; membersSelectOptions: string[] = []; @@ -58,7 +58,7 @@ export class TeamMembersManagerComponent implements OnInit { const memberIds = this.selectedMembersList; const approverIds = this.selectedApproversList; const dw = { - ...this.dossierWrapper, + ...this.dossier, memberIds, approverIds, ownerId @@ -120,15 +120,15 @@ export class TeamMembersManagerComponent implements OnInit { } private _updateChanged() { - if (this.dossierWrapper.ownerId !== this.selectedOwnerId) { + if (this.dossier.ownerId !== this.selectedOwnerId) { this.changed = true; return; } - const initialMembers = this.dossierWrapper.memberIds.sort(); + const initialMembers = [...this.dossier.memberIds].sort(); const currentMembers = this.selectedMembersList.sort(); - const initialApprovers = this.dossierWrapper.approverIds.sort(); + const initialApprovers = [...this.dossier.approverIds].sort(); const currentApprovers = this.selectedApproversList.sort(); this.changed = this._compareLists(initialMembers, currentMembers) || this._compareLists(initialApprovers, currentApprovers); @@ -147,9 +147,9 @@ export class TeamMembersManagerComponent implements OnInit { private _loadData() { this.teamForm = this._formBuilder.group({ - owner: [this.dossierWrapper?.ownerId, Validators.required], - approvers: [[...this.dossierWrapper?.approverIds]], - members: [[...this.dossierWrapper?.memberIds]] + owner: [this.dossier?.ownerId, Validators.required], + approvers: [[...this.dossier?.approverIds]], + members: [[...this.dossier?.memberIds]] }); this.teamForm.get('owner').valueChanges.subscribe(owner => { if (!this.isApprover(owner)) { diff --git a/apps/red-ui/src/app/modules/dossier/components/team-members/team-members.component.ts b/apps/red-ui/src/app/modules/dossier/components/team-members/team-members.component.ts index 6a3320345..497aafafe 100644 --- a/apps/red-ui/src/app/modules/dossier/components/team-members/team-members.component.ts +++ b/apps/red-ui/src/app/modules/dossier/components/team-members/team-members.component.ts @@ -1,6 +1,7 @@ import { Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core'; import { CircleButtonTypes } from '@iqser/common-ui'; import { UserService } from '@services/user.service'; +import { List } from '@redaction/red-ui-http'; @Component({ selector: 'redaction-team-members', @@ -11,7 +12,7 @@ export class TeamMembersComponent { readonly circleButtonTypes = CircleButtonTypes; readonly currentUser = this._userService.currentUser; - @Input() memberIds: string[]; + @Input() memberIds: List; @Input() perLine: number; @Input() canAdd = true; @Input() largeSpacing = false; @@ -30,7 +31,7 @@ export class TeamMembersComponent { return this.perLine - (this.canAdd ? 1 : 0); } - get displayedMembers(): string[] { + get displayedMembers(): List { return this.expandedTeam || !this.overflowCount ? this.memberIds : this.memberIds.slice(0, this.maxTeamMembersBeforeExpand - 1); } diff --git a/apps/red-ui/src/app/modules/dossier/components/type-filter/type-filter.component.html b/apps/red-ui/src/app/modules/dossier/components/type-filter/type-filter.component.html index fc518b945..8de42a9c4 100644 --- a/apps/red-ui/src/app/modules/dossier/components/type-filter/type-filter.component.html +++ b/apps/red-ui/src/app/modules/dossier/components/type-filter/type-filter.component.html @@ -1,57 +1,57 @@ - + - + - + -
+
diff --git a/apps/red-ui/src/app/modules/dossier/components/type-filter/type-filter.component.ts b/apps/red-ui/src/app/modules/dossier/components/type-filter/type-filter.component.ts index 3de66f8b4..9d2866f9d 100644 --- a/apps/red-ui/src/app/modules/dossier/components/type-filter/type-filter.component.ts +++ b/apps/red-ui/src/app/modules/dossier/components/type-filter/type-filter.component.ts @@ -1,6 +1,6 @@ import { Component, Input, OnInit } from '@angular/core'; import { AppStateService } from '@state/app-state.service'; -import { NestedFilter } from '@iqser/common-ui'; +import { INestedFilter } from '@iqser/common-ui'; @Component({ selector: 'redaction-type-filter', @@ -8,7 +8,7 @@ import { NestedFilter } from '@iqser/common-ui'; styleUrls: ['./type-filter.component.scss'] }) export class TypeFilterComponent implements OnInit { - @Input() filter: NestedFilter; + @Input() filter: INestedFilter; dictionaryColor: string; @@ -36,6 +36,6 @@ export class TypeFilterComponent implements OnInit { needsAnalysis = (key: string) => this._needsAnalysisKeys.includes(key); ngOnInit(): void { - this.dictionaryColor = this._appStateService.getDictionaryColor(this.filter.key); + this.dictionaryColor = this._appStateService.getDictionaryColor(this.filter.id); } } 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 b7783e492..0aee65cd9 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,6 +1,6 @@ import { Component } from '@angular/core'; import { MatDialogRef } from '@angular/material/dialog'; -import { Dossier, DossierTemplateModel, ReportTemplate, ReportTemplateControllerService } from '@redaction/red-ui-http'; +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'; @@ -16,12 +16,11 @@ export class AddDossierDialogComponent { dossierForm: FormGroup; hasDueDate = false; - downloadTypesEnum: Dossier.DownloadFileTypesEnum[] = ['ORIGINAL', 'PREVIEW', 'REDACTED']; - downloadTypes: { key: Dossier.DownloadFileTypesEnum; label: string }[] = this.downloadTypesEnum.map(type => ({ + downloadTypes: { key: DownloadFileType; label: string }[] = ['ORIGINAL', 'PREVIEW', 'REDACTED'].map((type: DownloadFileType) => ({ key: type, label: downloadTypesTranslations[type] })); - dossierTemplates: DossierTemplateModel[]; + dossierTemplates: IDossierTemplate[]; availableReportTypes = []; reportTemplateValueMapper = (reportTemplate: ReportTemplate) => reportTemplate.templateId; @@ -29,7 +28,7 @@ export class AddDossierDialogComponent { private readonly _appStateService: AppStateService, private readonly _formBuilder: FormBuilder, private readonly _reportTemplateController: ReportTemplateControllerService, - public dialogRef: MatDialogRef + readonly dialogRef: MatDialogRef ) { this._filterInvalidDossierTemplates(); this.dossierForm = this._formBuilder.group( @@ -68,21 +67,14 @@ export class AddDossierDialogComponent { } async saveDossier() { - const dossier: Dossier = this._formToObject(); - - const foundDossier = this._appStateService.allDossiers.find(p => p.dossierId === dossier.dossierId); - if (foundDossier) { - dossier.memberIds = foundDossier.memberIds; - } - - const savedDossier = await this._appStateService.createOrUpdateDossier(dossier); + const savedDossier = await this._appStateService.createOrUpdateDossier(this._formToObject()); if (savedDossier) { this.dialogRef.close({ dossier: savedDossier }); } } async saveDossierAndAddMembers() { - const dossier: Dossier = this._formToObject(); + const dossier: IDossier = this._formToObject(); const savedDossier = await this._appStateService.createOrUpdateDossier(dossier); if (savedDossier) { this.dialogRef.close({ addMembers: true, dossier: savedDossier }); @@ -124,7 +116,7 @@ export class AddDossierDialogComponent { }); } - private _formToObject(): Dossier { + private _formToObject(): IDossier { return { dossierName: this.dossierForm.get('dossierName').value, description: this.dossierForm.get('description').value, diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component.ts index 92be25dcd..7bbbd4ff5 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component.ts +++ b/apps/red-ui/src/app/modules/dossier/dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component.ts @@ -1,18 +1,18 @@ import { Component, Inject } from '@angular/core'; -import { StatusControllerService } from '@redaction/red-ui-http'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { AppStateService } from '@state/app-state.service'; import { UserService } from '@services/user.service'; import { Toaster } from '@iqser/common-ui'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; -import { FileStatusWrapper } from '@models/file/file-status.wrapper'; -import { DossierWrapper } from '@state/model/dossier.wrapper'; +import { File } from '@models/file/file'; +import { Dossier } from '@state/model/dossier'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { FilesService } from '../../services/files.service'; class DialogData { mode: 'approver' | 'reviewer'; - dossier?: DossierWrapper; - files?: FileStatusWrapper[]; + dossier?: Dossier; + files?: File[]; ignoreChanged?: boolean; } @@ -28,8 +28,8 @@ export class AssignReviewerApproverDialogComponent { readonly userService: UserService, private readonly _toaster: Toaster, private readonly _formBuilder: FormBuilder, - private readonly _statusControllerService: StatusControllerService, private readonly _appStateService: AppStateService, + private readonly _filesService: FilesService, private readonly _dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) readonly data: DialogData ) { @@ -69,16 +69,17 @@ export class AssignReviewerApproverDialogComponent { const selectedUser = this.selectedSingleUser; if (this.data.mode === 'reviewer') { - await this._statusControllerService - .setFileReviewerForList( + console.log('assign reviewer'); + await this._filesService + .setReviewerFor( this.data.files.map(f => f.fileId), this._appStateService.activeDossierId, selectedUser ) .toPromise(); } else { - await this._statusControllerService - .setStatusUnderApprovalForList( + await this._filesService + .setUnderApprovalFor( this.data.files.map(f => f.fileId), selectedUser, this._appStateService.activeDossierId 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 042440f41..39d6f0c31 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 @@ -1,9 +1,9 @@ import { Component, Inject, OnInit } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; -import { FileAttributeConfig, FileAttributesControllerService, FileStatus } from '@redaction/red-ui-http'; +import { FileAttributesControllerService, IFile, IFileAttributeConfig } from '@redaction/red-ui-http'; import { AppStateService } from '@state/app-state.service'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { DossierWrapper } from '@state/model/dossier.wrapper'; +import { Dossier } from '@state/model/dossier'; @Component({ templateUrl: './document-info-dialog.component.html', @@ -11,17 +11,17 @@ import { DossierWrapper } from '@state/model/dossier.wrapper'; }) export class DocumentInfoDialogComponent implements OnInit { documentInfoForm: FormGroup; - file: FileStatus; - attributes: FileAttributeConfig[]; + file: IFile; + attributes: IFileAttributeConfig[]; - private _dossier: DossierWrapper; + private _dossier: Dossier; constructor( private readonly _appStateService: AppStateService, private readonly _formBuilder: FormBuilder, private readonly _fileAttributesService: FileAttributesControllerService, public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: FileStatus + @Inject(MAT_DIALOG_DATA) public data: IFile ) { this.file = this.data; this._dossier = this._appStateService.getDossierById(this.file.dossierId); diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/attributes/edit-dossier-attributes.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/attributes/edit-dossier-attributes.component.ts index ef70e4e3b..df38cf707 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/attributes/edit-dossier-attributes.component.ts +++ b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/attributes/edit-dossier-attributes.component.ts @@ -1,7 +1,6 @@ import { Component, ElementRef, EventEmitter, Input, OnInit, Output, QueryList, ViewChildren } from '@angular/core'; import { EditDossierSectionInterface } from '../edit-dossier-section.interface'; -import { DossierWrapper } from '@state/model/dossier.wrapper'; -import { AppStateService } from '@state/app-state.service'; +import { Dossier } from '../../../../../state/model/dossier'; import { PermissionsService } from '@services/permissions.service'; import { CircleButtonTypes, IconButtonTypes, LoadingService } from '@iqser/common-ui'; import { FormBuilder, FormGroup } from '@angular/forms'; @@ -18,8 +17,8 @@ export class EditDossierAttributesComponent implements EditDossierSectionInterfa readonly iconButtonTypes = IconButtonTypes; readonly circleButtonTypes = CircleButtonTypes; - @Input() dossierWrapper: DossierWrapper; - @Output() updateDossier = new EventEmitter(); + @Input() dossier: Dossier; + @Output() readonly updateDossier = new EventEmitter(); customAttributes: DossierAttributeWithValue[] = []; imageAttributes: DossierAttributeWithValue[] = []; attributes: DossierAttributeWithValue[] = []; @@ -28,7 +27,6 @@ export class EditDossierAttributesComponent implements EditDossierSectionInterfa @ViewChildren('fileInput') private _fileInputs: QueryList; constructor( - private readonly _appStateService: AppStateService, private readonly _permissionsService: PermissionsService, private readonly _dossierAttributesService: DossierAttributesService, private readonly _loadingService: LoadingService, @@ -50,11 +48,11 @@ export class EditDossierAttributesComponent implements EditDossierSectionInterfa } get disabled() { - return !this._permissionsService.isOwner(this.dossierWrapper); + return !this._permissionsService.isOwner(this.dossier); } get canEdit(): boolean { - return this._permissionsService.isOwner(this.dossierWrapper); + return this._permissionsService.isOwner(this.dossier); } async ngOnInit() { @@ -70,7 +68,7 @@ export class EditDossierAttributesComponent implements EditDossierSectionInterfa dossierAttributeId: attr.id, value: this.currentAttrValue(attr) })); - await this._dossierAttributesService.setValues(this.dossierWrapper, dossierAttributeList); + await this._dossierAttributesService.setValues(this.dossier, dossierAttributeList); await this._loadAttributes(); this.updateDossier.emit(); this._loadingService.stop(); @@ -136,7 +134,7 @@ export class EditDossierAttributesComponent implements EditDossierSectionInterfa } private async _loadAttributes() { - this.attributes = await this._dossierAttributesService.getValues(this.dossierWrapper); + this.attributes = await this._dossierAttributesService.getValues(this.dossier); this.customAttributes = this.attributes.filter(attr => !this.isImage(attr)); this.imageAttributes = this.attributes.filter(attr => this.isImage(attr)); } diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/deleted-documents/edit-dossier-deleted-documents.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/deleted-documents/edit-dossier-deleted-documents.component.ts index 88e60bb07..920cff75e 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/deleted-documents/edit-dossier-deleted-documents.component.ts +++ b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/deleted-documents/edit-dossier-deleted-documents.component.ts @@ -1,16 +1,16 @@ import { Component, EventEmitter, forwardRef, Injector, Input, OnInit, Output, TemplateRef, ViewChild } from '@angular/core'; import { EditDossierSectionInterface } from '../edit-dossier-section.interface'; -import { DossierWrapper } from '@state/model/dossier.wrapper'; +import { Dossier } from '@state/model/dossier'; import { CircleButtonTypes, DefaultListingServices, - Listable, + IListable, ListingComponent, LoadingService, SortingOrders, TableColumnConfig } from '@iqser/common-ui'; -import { FileManagementControllerService, FileStatus, StatusControllerService } from '@redaction/red-ui-http'; +import { FileManagementControllerService, IFile } from '@redaction/red-ui-http'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import * as moment from 'moment'; import { ConfigService } from '@services/config.service'; @@ -20,8 +20,9 @@ import { distinctUntilChanged, map } from 'rxjs/operators'; import { ConfirmationDialogInput, TitleColors } from '@shared/dialogs/confirmation-dialog/confirmation-dialog.component'; import { DossiersDialogService } from '../../../services/dossiers-dialog.service'; import { AppStateService } from '@state/app-state.service'; +import { FilesService } from '../../../services/files.service'; -interface FileListItem extends FileStatus, Listable { +interface FileListItem extends IFile, IListable { readonly canRestore: boolean; readonly restoreDate: string; } @@ -36,8 +37,8 @@ interface FileListItem extends FileStatus, Listable { ] }) export class EditDossierDeletedDocumentsComponent extends ListingComponent implements EditDossierSectionInterface, OnInit { - @Input() dossierWrapper: DossierWrapper; - @Output() updateDossier = new EventEmitter(); + @Input() dossier: Dossier; + @Output() readonly updateDossier = new EventEmitter(); readonly changed = false; readonly canRestoreSelected$ = this._canRestoreSelected$; disabled: boolean; @@ -49,13 +50,12 @@ export class EditDossierDeletedDocumentsComponent extends ListingComponent; @ViewChild('deletedDateTemplate', { static: true }) deletedDateTemplate: TemplateRef; @ViewChild('restoreDateTemplate', { static: true }) restoreDateTemplate: TemplateRef; - protected readonly _primaryKey = 'fileId'; constructor( protected readonly _injector: Injector, - private readonly _statusController: StatusControllerService, private readonly _fileManagementController: FileManagementControllerService, private readonly _appStateService: AppStateService, + private readonly _filesService: FilesService, private readonly _loadingService: LoadingService, private readonly _configService: ConfigService, private readonly _dialogService: DossiersDialogService @@ -91,7 +91,7 @@ export class EditDossierDeletedDocumentsComponent extends ListingComponent { const fileIds = files.map(f => f.fileId); - await this._fileManagementController.restoreFiles(fileIds, this.dossierWrapper.dossierId).toPromise(); + await this._fileManagementController.restoreFiles(fileIds, this.dossier.id).toPromise(); this._removeFromList(fileIds); await this._appStateService.reloadActiveDossierFiles(); this.updateDossier.emit(); @@ -146,7 +146,7 @@ export class EditDossierDeletedDocumentsComponent extends ListingComponent f.fileId); - await this._fileManagementController.hardDeleteFile(this.dossierWrapper.dossierId, fileIds).toPromise(); + await this._fileManagementController.hardDeleteFile(this.dossier.id, fileIds).toPromise(); this._removeFromList(fileIds); this.updateDossier.emit(); } @@ -157,16 +157,17 @@ export class EditDossierDeletedDocumentsComponent extends ListingComponent this._toListItem(file)); } - private _toListItem(file: FileStatus): FileListItem { + private _toListItem(file: IFile): FileListItem { const restoreDate = this._getRestoreDate(file.softDeleted); return { id: file.fileId, ...file, restoreDate, + searchKey: file.filename, canRestore: this._canRestoreFile(restoreDate) }; } diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/dictionary/edit-dossier-dictionary.component.html b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/dictionary/edit-dossier-dictionary.component.html index 0f630ab4e..06dee2be4 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/dictionary/edit-dossier-dictionary.component.html +++ b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/dictionary/edit-dossier-dictionary.component.html @@ -1,10 +1,10 @@
-
{{ dossierWrapper.type?.label }}
+
{{ dossier.type?.label }}
- {{ 'edit-dossier-dialog.dictionary.entries' | translate: { length: (dossierWrapper.type?.entries || []).length } }} + {{ 'edit-dossier-dialog.dictionary.entries' | translate: { length: (dossier.type?.entries || []).length } }}
@@ -19,13 +19,13 @@ [placeholder]="'edit-dossier-dialog.dictionary.display-name.placeholder' | translate" [saveTooltip]="'edit-dossier-dialog.dictionary.display-name.save' | translate" [showPreview]="false" - [value]="dossierWrapper.type?.label" + [value]="dossier.type?.label" >
diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/dictionary/edit-dossier-dictionary.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/dictionary/edit-dossier-dictionary.component.ts index 51d4d08b2..39508e09a 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/dictionary/edit-dossier-dictionary.component.ts +++ b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/dictionary/edit-dossier-dictionary.component.ts @@ -1,13 +1,13 @@ import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; import { AppStateService } from '@state/app-state.service'; -import { DossierWrapper } from '@state/model/dossier.wrapper'; +import { Dossier } from '@state/model/dossier'; import { EditDossierSectionInterface } from '../edit-dossier-section.interface'; import { PermissionsService } from '@services/permissions.service'; import { DictionaryManagerComponent } from '@shared/components/dictionary-manager/dictionary-manager.component'; -import { DictionarySaveService } from '@shared/services/dictionary-save.service'; +import { DictionaryService } from '@shared/services/dictionary.service'; import { FormBuilder } from '@angular/forms'; import { CircleButtonTypes, LoadingService } from '@iqser/common-ui'; -import { Dictionary, DictionaryControllerService } from '@redaction/red-ui-http'; +import { IDictionary } from '@redaction/red-ui-http'; @Component({ selector: 'redaction-edit-dossier-dictionary', @@ -15,8 +15,8 @@ import { Dictionary, DictionaryControllerService } from '@redaction/red-ui-http' styleUrls: ['./edit-dossier-dictionary.component.scss'] }) export class EditDossierDictionaryComponent implements EditDossierSectionInterface, OnInit { - @Input() dossierWrapper: DossierWrapper; - @Output() updateDossier: EventEmitter = new EventEmitter(); + @Input() dossier: Dossier; + @Output() readonly updateDossier = new EventEmitter(); canEdit = false; readonly circleButtonTypes = CircleButtonTypes; @@ -24,13 +24,12 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa constructor( private readonly _appStateService: AppStateService, - private readonly _dictionarySaveService: DictionarySaveService, + private readonly _dictionaryService: DictionaryService, private readonly _permissionsService: PermissionsService, - private readonly _dictionaryControllerService: DictionaryControllerService, private readonly _loadingService: LoadingService, private readonly _formBuilder: FormBuilder ) { - this.canEdit = this._permissionsService.isDossierMember(this.dossierWrapper); + this.canEdit = this._permissionsService.isDossierMember(this.dossier); } get changed() { @@ -43,31 +42,31 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa async ngOnInit() { this._loadingService.start(); - await this._appStateService.updateDossierDictionary(this.dossierWrapper.dossierTemplateId, this.dossierWrapper.dossierId); + await this._appStateService.updateDossierDictionary(this.dossier.dossierTemplateId, this.dossier.id); this._loadingService.stop(); } async updateDisplayName(label: string) { - const typeValue: Dictionary = { ...this.dossierWrapper.type, label }; - await this._dictionaryControllerService - .updateType(typeValue, this.dossierWrapper.dossierTemplateId, 'dossier_redaction', this.dossierWrapper.dossierId) + const typeValue: IDictionary = { ...this.dossier.type, label }; + await this._dictionaryService + .updateType(typeValue, this.dossier.dossierTemplateId, 'dossier_redaction', this.dossier.id) .toPromise(); - await this._appStateService.updateDossierDictionary(this.dossierWrapper.dossierTemplateId, this.dossierWrapper.dossierId); + await this._appStateService.updateDossierDictionary(this.dossier.dossierTemplateId, this.dossier.id); this.updateDossier.emit(); } async save() { - await this._dictionarySaveService + await this._dictionaryService .saveEntries( this._dictionaryManager.currentEntries, this._dictionaryManager.initialEntries, - this.dossierWrapper.dossierTemplateId, + this.dossier.dossierTemplateId, 'dossier_redaction', - this.dossierWrapper.dossierId, + this.dossier.id, false ) .toPromise(); - await this._appStateService.updateDossierDictionary(this.dossierWrapper.dossierTemplateId, this.dossierWrapper.dossierId); + await this._appStateService.updateDossierDictionary(this.dossier.dossierTemplateId, this.dossier.id); this.updateDossier.emit(); } diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/download-package/edit-dossier-download-package.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/download-package/edit-dossier-download-package.component.ts index ccd3b6fe6..7e0f91e9f 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/download-package/edit-dossier-download-package.component.ts +++ b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/download-package/edit-dossier-download-package.component.ts @@ -1,8 +1,8 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { Dossier, DossierTemplateModel, ReportTemplate, ReportTemplateControllerService } from '@redaction/red-ui-http'; +import { DownloadFileType, ReportTemplate, ReportTemplateControllerService } from '@redaction/red-ui-http'; import { FormBuilder, FormGroup } from '@angular/forms'; import { AppStateService } from '@state/app-state.service'; -import { DossierWrapper } from '@state/model/dossier.wrapper'; +import { Dossier } from '@state/model/dossier'; import { EditDossierSectionInterface } from '../edit-dossier-section.interface'; import { downloadTypesTranslations } from '../../../../../translations/download-types-translations'; @@ -13,16 +13,14 @@ import { downloadTypesTranslations } from '../../../../../translations/download- }) export class EditDossierDownloadPackageComponent implements OnInit, EditDossierSectionInterface { dossierForm: FormGroup; - downloadTypesEnum: Dossier.DownloadFileTypesEnum[] = ['ORIGINAL', 'PREVIEW', 'REDACTED']; - downloadTypes: { key: Dossier.DownloadFileTypesEnum; label: string }[] = this.downloadTypesEnum.map(type => ({ + downloadTypes: { key: DownloadFileType; label: string }[] = ['ORIGINAL', 'PREVIEW', 'REDACTED'].map((type: DownloadFileType) => ({ key: type, label: downloadTypesTranslations[type] })); - dossierTemplates: DossierTemplateModel[]; availableReportTypes: ReportTemplate[] = []; - @Input() dossierWrapper: DossierWrapper; - @Output() updateDossier = new EventEmitter(); + @Input() dossier: Dossier; + @Output() readonly updateDossier = new EventEmitter(); constructor( private readonly _appStateService: AppStateService, @@ -41,11 +39,11 @@ export class EditDossierDownloadPackageComponent implements OnInit, EditDossierS get changed() { if (this.dossierForm) { for (const key of Object.keys(this.dossierForm.getRawValue())) { - if (this.dossierWrapper[key].length !== this.dossierForm.get(key).value.length) { + if (this.dossier[key].length !== this.dossierForm.get(key).value.length) { return true; } - const originalItems = [...this.dossierWrapper[key]].sort(); + const originalItems = [...this.dossier[key]].sort(); const newItems = [...this.dossierForm.get(key).value].sort(); for (let idx = 0; idx < originalItems.length; ++idx) { @@ -67,12 +65,12 @@ export class EditDossierDownloadPackageComponent implements OnInit, EditDossierS async ngOnInit() { this.availableReportTypes = - (await this._reportTemplateController.getAvailableReportTemplates(this.dossierWrapper.dossierTemplateId).toPromise()) || []; + (await this._reportTemplateController.getAvailableReportTemplates(this.dossier.dossierTemplateId).toPromise()) || []; this.dossierForm = this._formBuilder.group( { - reportTemplateIds: [this.dossierWrapper.reportTemplateIds], - downloadFileTypes: [this.dossierWrapper.downloadFileTypes] + reportTemplateIds: [this.dossier.reportTemplateIds], + downloadFileTypes: [this.dossier.downloadFileTypes] }, { validators: control => @@ -85,7 +83,7 @@ export class EditDossierDownloadPackageComponent implements OnInit, EditDossierS async save() { const dossier = { - ...this.dossierWrapper, + ...this.dossier, downloadFileTypes: this.dossierForm.get('downloadFileTypes').value, reportTemplateIds: this.dossierForm.get('reportTemplateIds').value }; @@ -95,8 +93,8 @@ export class EditDossierDownloadPackageComponent implements OnInit, EditDossierS revert() { this.dossierForm.reset({ - downloadFileTypes: this.dossierWrapper.downloadFileTypes, - reportTemplateIds: this.dossierWrapper.reportTemplateIds + downloadFileTypes: this.dossier.downloadFileTypes, + reportTemplateIds: this.dossier.reportTemplateIds }); } } diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/edit-dossier-dialog.component.html b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/edit-dossier-dialog.component.html index 5a70a20a8..48eb7f0b9 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/edit-dossier-dialog.component.html +++ b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/edit-dossier-dialog.component.html @@ -1,6 +1,6 @@
- {{ 'edit-dossier-dialog.header' | translate: { dossierName: dossierWrapper.dossierName } }} + {{ 'edit-dossier-dialog.header' | translate: { dossierName: dossier.dossierName } }}
@@ -22,37 +22,37 @@
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 f5de3fc9f..8090b67f0 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 @@ -1,6 +1,6 @@ import { ChangeDetectorRef, Component, Inject, ViewChild } from '@angular/core'; import { MAT_DIALOG_DATA } from '@angular/material/dialog'; -import { DossierWrapper } from '@state/model/dossier.wrapper'; +import { Dossier } from '@state/model/dossier'; import { EditDossierGeneralInfoComponent } from './general-info/edit-dossier-general-info.component'; import { EditDossierDownloadPackageComponent } from './download-package/edit-dossier-download-package.component'; import { EditDossierSectionInterface } from './edit-dossier-section.interface'; @@ -22,7 +22,7 @@ type Section = 'dossierInfo' | 'downloadPackage' | 'dossierDictionary' | 'member export class EditDossierDialogComponent { readonly navItems: { key: Section; title?: string; sideNavTitle?: string }[]; activeNav: Section; - dossierWrapper: DossierWrapper; + dossier: Dossier; @ViewChild(EditDossierGeneralInfoComponent) generalInfoComponent: EditDossierGeneralInfoComponent; @ViewChild(EditDossierDownloadPackageComponent) downloadPackageComponent: EditDossierDownloadPackageComponent; @@ -37,7 +37,7 @@ export class EditDossierDialogComponent { private readonly _changeRef: ChangeDetectorRef, @Inject(MAT_DIALOG_DATA) private readonly _data: { - dossierWrapper: DossierWrapper; + dossier: Dossier; afterSave: Function; section?: Section; } @@ -73,7 +73,7 @@ export class EditDossierDialogComponent { } ]; - this.dossierWrapper = _data.dossierWrapper; + this.dossier = _data.dossier; this.activeNav = _data.section || 'dossierInfo'; } @@ -105,8 +105,8 @@ export class EditDossierDialogComponent { } updatedDossier() { - this._toaster.success(_('edit-dossier-dialog.change-successful'), { params: { dossierName: this.dossierWrapper.dossierName } }); - this.dossierWrapper = this._appStateService.getDossierById(this.dossierWrapper.dossierId); + this._toaster.success(_('edit-dossier-dialog.change-successful'), { params: { dossierName: this.dossier.dossierName } }); + this.dossier = this._appStateService.getDossierById(this.dossier.id); this._changeRef.detectChanges(); this.afterSave(); } diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/general-info/edit-dossier-general-info.component.html b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/general-info/edit-dossier-general-info.component.html index bfbb5075a..15a7fb390 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/general-info/edit-dossier-general-info.component.html +++ b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/general-info/edit-dossier-general-info.component.html @@ -58,7 +58,7 @@
(); + @Input() dossier: Dossier; + @Output() readonly updateDossier = new EventEmitter(); constructor( readonly permissionsService: PermissionsService, @@ -43,13 +42,13 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti get changed() { for (const key of Object.keys(this.dossierForm.getRawValue())) { if (key === 'dueDate') { - if (this.hasDueDate !== !!this.dossierWrapper.dueDate) { + if (this.hasDueDate !== !!this.dossier.dueDate) { return true; } - if (this.hasDueDate && !moment(this.dossierWrapper.dueDate).isSame(moment(this.dossierForm.get(key).value))) { + if (this.hasDueDate && !moment(this.dossier.dueDate).isSame(moment(this.dossierForm.get(key).value))) { return true; } - } else if (this.dossierWrapper[key] !== this.dossierForm.get(key).value) { + } else if (this.dossier[key] !== this.dossierForm.get(key).value) { return true; } } @@ -68,34 +67,34 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti ngOnInit() { this._filterInvalidDossierTemplates(); this.dossierForm = this._formBuilder.group({ - dossierName: [this.dossierWrapper.dossierName, Validators.required], + dossierName: [this.dossier.dossierName, Validators.required], dossierTemplateId: [ { - value: this.dossierWrapper.dossierTemplateId, - disabled: this.dossierWrapper.hasFiles + value: this.dossier.dossierTemplateId, + disabled: this.dossier.hasFiles }, Validators.required ], - description: [this.dossierWrapper.description], - dueDate: [this.dossierWrapper.dueDate], - watermarkEnabled: [this.dossierWrapper.watermarkEnabled] + description: [this.dossier.description], + dueDate: [this.dossier.dueDate], + watermarkEnabled: [this.dossier.watermarkEnabled] }); - this.hasDueDate = !!this.dossierWrapper.dueDate; + this.hasDueDate = !!this.dossier.dueDate; } revert() { this.dossierForm.reset({ - dossierName: this.dossierWrapper.dossierName, - dossierTemplateId: this.dossierWrapper.dossierTemplateId, - description: this.dossierWrapper.description, - watermarkEnabled: this.dossierWrapper.watermarkEnabled, - dueDate: this.dossierWrapper.dueDate + dossierName: this.dossier.dossierName, + dossierTemplateId: this.dossier.dossierTemplateId, + description: this.dossier.description, + watermarkEnabled: this.dossier.watermarkEnabled, + dueDate: this.dossier.dueDate }); } async save() { const dossier = { - ...this.dossierWrapper, + ...this.dossier, dossierName: this.dossierForm.get('dossierName').value, description: this.dossierForm.get('description').value, watermarkEnabled: this.dossierForm.get('watermarkEnabled').value, @@ -116,12 +115,12 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti requireInput: true, denyText: _('confirmation-dialog.delete-dossier.deny-text'), translateParams: { - dossierName: this.dossierWrapper.dossierName, + dossierName: this.dossier.dossierName, dossiersCount: 1 } }); this._dialogService.openDialog('confirm', null, data, async () => { - await this._appStateService.deleteDossier(this.dossierWrapper); + await this._appStateService.deleteDossier(this.dossier); this._editDossierDialogRef.componentInstance.afterSave(); this._editDossierDialogRef.close(); this._router.navigate(['main', 'dossiers']).then(() => this._notifyDossierDeleted()); @@ -129,12 +128,12 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti } private _notifyDossierDeleted() { - this._toaster.success(_('edit-dossier-dialog.delete-successful'), { params: { dossierName: this.dossierWrapper.dossierName } }); + this._toaster.success(_('edit-dossier-dialog.delete-successful'), { params: { dossierName: this.dossier.dossierName } }); } private _filterInvalidDossierTemplates() { this.dossierTemplates = this._appStateService.dossierTemplates.filter(r => { - if (this.dossierWrapper?.dossierTemplateId === r.dossierTemplateId) { + if (this.dossier?.dossierTemplateId === r.dossierTemplateId) { return true; } const notYetValid = !!r.validFrom && moment(r.validFrom).isAfter(moment()); diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/team-members/edit-dossier-team-members.component.html b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/team-members/edit-dossier-team-members.component.html index 55f62235e..cb8de7e94 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/team-members/edit-dossier-team-members.component.html +++ b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/team-members/edit-dossier-team-members.component.html @@ -1 +1 @@ - + diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/team-members/edit-dossier-team-members.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/team-members/edit-dossier-team-members.component.ts index 785df2e9b..00bed1c3f 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/team-members/edit-dossier-team-members.component.ts +++ b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/team-members/edit-dossier-team-members.component.ts @@ -1,6 +1,5 @@ import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core'; -import { AppStateService } from '@state/app-state.service'; -import { DossierWrapper } from '@state/model/dossier.wrapper'; +import { Dossier } from '@state/model/dossier'; import { EditDossierSectionInterface } from '../edit-dossier-section.interface'; import { TeamMembersManagerComponent } from '../../../components/team-members-manager/team-members-manager.component'; import { UserService } from '@services/user.service'; @@ -13,12 +12,12 @@ import { UserService } from '@services/user.service'; export class EditDossierTeamMembersComponent implements EditDossierSectionInterface { readonly currentUser = this._userService.currentUser; - @Input() dossierWrapper: DossierWrapper; - @Output() updateDossier = new EventEmitter(); + @Input() dossier: Dossier; + @Output() readonly updateDossier = new EventEmitter(); @ViewChild(TeamMembersManagerComponent) managerComponent: TeamMembersManagerComponent; - constructor(private readonly _appStateService: AppStateService, private readonly _userService: UserService) {} + constructor(private readonly _userService: UserService) {} get changed() { return this.managerComponent.changed; diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.ts index 476092dcc..47ba5c066 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.ts +++ b/apps/red-ui/src/app/modules/dossier/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.ts @@ -10,7 +10,7 @@ import { ManualRedactionEntryWrapper } from '@models/file/manual-redaction-entry import { ManualAnnotationService } from '../../services/manual-annotation.service'; import { ManualAnnotationResponse } from '@models/file/manual-annotation-response'; import { PermissionsService } from '@services/permissions.service'; -import { TypeValueWrapper } from '@models/file/type-value.wrapper'; +import { TypeValue } from '@models/file/type-value'; export interface LegalBasisOption { label?: string; @@ -30,7 +30,7 @@ export class ManualAnnotationDialogComponent implements OnInit { isDictionaryRequest: boolean; isFalsePositiveRequest: boolean; - redactionDictionaries: TypeValueWrapper[] = []; + redactionDictionaries: TypeValue[] = []; legalOptions: LegalBasisOption[] = []; constructor( diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.html index 7dcf65568..a7d8f738f 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.html @@ -33,13 +33,13 @@
-
+
{{ dossier.dossierName }}
-
+
- {{ dossier.dossierTemplateName }} + {{ getDossierTemplateNameFor(dossier.dossierTemplateId) }}
@@ -53,7 +53,7 @@
- {{ dossier.memberCount }} + {{ dossier.memberIds.length }}
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.ts b/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.ts index 0b93ae005..8b4b7661f 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.ts @@ -1,11 +1,11 @@ import { AfterViewInit, Component, forwardRef, Injector, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core'; -import { Dossier } from '@redaction/red-ui-http'; +import { DossierStatuses } from '@redaction/red-ui-http'; import { AppStateService } from '@state/app-state.service'; import { UserService } from '@services/user.service'; import { DoughnutChartConfig } from '@shared/components/simple-doughnut-chart/simple-doughnut-chart.component'; import { groupBy } from '@utils/functions'; import { TranslateService } from '@ngx-translate/core'; -import { DossierWrapper } from '@state/model/dossier.wrapper'; +import { Dossier } from '@state/model/dossier'; import { timer } from 'rxjs'; import { tap } from 'rxjs/operators'; import { TranslateChartService } from '@services/translate-chart.service'; @@ -29,7 +29,7 @@ import { PermissionsService } from '@services/permissions.service'; providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => DossierListingScreenComponent) }] }) export class DossierListingScreenComponent - extends ListingComponent + extends ListingComponent implements OnInit, AfterViewInit, OnDestroy, OnAttach, OnDetach { readonly currentUser = this._userService.currentUser; @@ -43,21 +43,20 @@ export class DossierListingScreenComponent type: 'primary' } ]; - tableColumnConfigs: TableColumnConfig[]; + tableColumnConfigs: TableColumnConfig[]; dossiersChartData: DoughnutChartConfig[] = []; documentsChartData: DoughnutChartConfig[] = []; - @ViewChild('nameTemplate', { static: true }) nameTemplate: TemplateRef; - @ViewChild('needsWorkTemplate', { static: true }) needsWorkTemplate: TemplateRef; - @ViewChild('ownerTemplate', { static: true }) ownerTemplate: TemplateRef; - @ViewChild('statusTemplate', { static: true }) statusTemplate: TemplateRef; - protected readonly _primaryKey = 'dossierName'; + @ViewChild('nameTemplate', { static: true }) nameTemplate: TemplateRef; + @ViewChild('needsWorkTemplate', { static: true }) needsWorkTemplate: TemplateRef; + @ViewChild('ownerTemplate', { static: true }) ownerTemplate: TemplateRef; + @ViewChild('statusTemplate', { static: true }) statusTemplate: TemplateRef; private _lastScrolledIndex: number; @ViewChild('needsWorkFilterTemplate', { read: TemplateRef, static: true }) private readonly _needsWorkFilterTemplate: TemplateRef; - @ViewChild(TableComponent) private readonly _tableComponent: TableComponent; + @ViewChild(TableComponent) private readonly _tableComponent: TableComponent; constructor( private readonly _router: Router, @@ -76,14 +75,16 @@ export class DossierListingScreenComponent } private get _activeDossiersCount(): number { - return this.entitiesService.all.filter(p => p.status === Dossier.StatusEnum.ACTIVE).length; + return this.entitiesService.all.filter(p => p.status === DossierStatuses.ACTIVE).length; } private get _inactiveDossiersCount(): number { return this.entitiesService.all.length - this._activeDossiersCount; } - routerLinkFn = (dossier: DossierWrapper) => ['/main/dossiers/' + dossier.dossierId]; + getDossierTemplateNameFor(dossierTemplateId: string): string { + return this._appStateService.getDossierTemplateById(dossierTemplateId).name; + } ngOnInit(): void { this._configureTableColumns(); @@ -120,10 +121,10 @@ export class DossierListingScreenComponent openAddDossierDialog(): void { this._dialogService.openDialog('addDossier', null, null, async addResponse => { - await this._router.navigate([`/main/dossiers/${addResponse.dossier.dossierId}`]); + await this._router.navigate([`/main/dossiers/${addResponse.dossier.id}`]); if (addResponse.addMembers) { this._dialogService.openDialog('editDossier', null, { - dossierWrapper: addResponse.dossier, + dossier: addResponse.dossier, section: 'members' }); } @@ -140,12 +141,12 @@ export class DossierListingScreenComponent const groups = groupBy(this._appStateService.aggregatedFiles, 'status'); this.documentsChartData = []; - for (const key of Object.keys(groups)) { + for (const status of Object.keys(groups)) { this.documentsChartData.push({ - value: groups[key].length, - color: key, - label: fileStatusTranslations[key], - key: key + value: groups[status].length, + color: status, + label: fileStatusTranslations[status], + key: status }); } this.documentsChartData.sort(StatusSorter.byStatus); @@ -156,7 +157,7 @@ export class DossierListingScreenComponent this.tableColumnConfigs = [ { label: _('dossier-listing.table-col-names.name'), - sortByKey: 'dossierName', + sortByKey: 'searchKey', template: this.nameTemplate, width: '2fr' }, @@ -214,23 +215,29 @@ export class DossierListingScreenComponent allDistinctDossierTemplates.add(entry.dossierTemplateId); }); - const statusFilters = [...allDistinctFileStatus].map(status => ({ - key: status, - label: this._translateService.instant(fileStatusTranslations[status]) - })); + const statusFilters = [...allDistinctFileStatus].map( + status => + new NestedFilter({ + id: status, + label: this._translateService.instant(fileStatusTranslations[status]) + }) + ); this.filterService.addFilterGroup({ slug: 'statusFilters', label: this._translateService.instant('filters.status'), icon: 'red:status', - filters: statusFilters.sort(StatusSorter.byStatus), + filters: statusFilters.sort((a, b) => StatusSorter[a.id] - StatusSorter[b.id]), checker: dossierStatusChecker }); - const peopleFilters = [...allDistinctPeople].map(userId => ({ - key: userId, - label: this._userService.getNameForId(userId) - })); + const peopleFilters = [...allDistinctPeople].map( + userId => + new NestedFilter({ + id: userId, + label: this._userService.getNameForId(userId) + }) + ); this.filterService.addFilterGroup({ slug: 'peopleFilters', @@ -240,25 +247,31 @@ export class DossierListingScreenComponent checker: dossierMemberChecker }); - const needsWorkFilters = [...allDistinctNeedsWork].map(type => ({ - key: type, - label: workloadTranslations[type] - })); + const needsWorkFilters = [...allDistinctNeedsWork].map( + type => + new NestedFilter({ + id: type, + label: workloadTranslations[type] + }) + ); this.filterService.addFilterGroup({ slug: 'needsWorkFilters', label: this._translateService.instant('filters.needs-work'), icon: 'red:needs-work', filterTemplate: this._needsWorkFilterTemplate, - filters: needsWorkFilters.sort(RedactionFilterSorter.byKey), + filters: needsWorkFilters.sort((a, b) => RedactionFilterSorter[a.id] - RedactionFilterSorter[b.id]), checker: annotationFilterChecker, matchAll: true }); - const dossierTemplateFilters = [...allDistinctDossierTemplates].map(id => ({ - key: id, - label: this._appStateService.getDossierTemplateById(id).name - })); + const dossierTemplateFilters = [...allDistinctDossierTemplates].map( + id => + new NestedFilter({ + id: id, + label: this._appStateService.getDossierTemplateById(id).name + }) + ); this.filterService.addFilterGroup({ slug: 'dossierTemplateFilters', @@ -273,13 +286,16 @@ export class DossierListingScreenComponent this.filterService.addFilterGroup({ slug: 'quickFilters', filters: quickFilters, - checker: (dw: DossierWrapper) => quickFilters.reduce((acc, f) => acc || (f.checked && f.checker(dw)), false) + checker: (dw: Dossier) => quickFilters.reduce((acc, f) => acc || (f.checked && f.checker(dw)), false) }); - const dossierFilters = this.entitiesService.all.map(dossier => ({ - key: dossier.dossierName, - label: dossier.dossierName - })); + const dossierFilters = this.entitiesService.all.map( + dossier => + new NestedFilter({ + id: dossier.dossierName, + label: dossier.dossierName + }) + ); this.filterService.addFilterGroup({ slug: 'dossierNameFilter', label: this._translateService.instant('dossier-listing.filters.label'), @@ -290,30 +306,30 @@ export class DossierListingScreenComponent }); } - private _createQuickFilters() { + private _createQuickFilters(): NestedFilter[] { const myDossiersLabel = this._translateService.instant('dossier-listing.quick-filters.my-dossiers'); const filters: NestedFilter[] = [ { - key: 'my-dossiers', + id: 'my-dossiers', label: myDossiersLabel, - checker: (dw: DossierWrapper) => dw.ownerId === this.currentUser.id + checker: (dw: Dossier) => dw.ownerId === this.currentUser.id }, { - key: 'to-approve', + id: 'to-approve', label: this._translateService.instant('dossier-listing.quick-filters.to-approve'), - checker: (dw: DossierWrapper) => dw.approverIds.includes(this.currentUser.id) + checker: (dw: Dossier) => dw.approverIds.includes(this.currentUser.id) }, { - key: 'to-review', + id: 'to-review', label: this._translateService.instant('dossier-listing.quick-filters.to-review'), - checker: (dw: DossierWrapper) => dw.memberIds.includes(this.currentUser.id) + checker: (dw: Dossier) => dw.memberIds.includes(this.currentUser.id) }, { - key: 'other', + id: 'other', label: this._translateService.instant('dossier-listing.quick-filters.other'), - checker: (dw: DossierWrapper) => !dw.memberIds.includes(this.currentUser.id) + checker: (dw: Dossier) => !dw.memberIds.includes(this.currentUser.id) } - ]; + ].map(filter => new NestedFilter(filter)); return filters.filter(f => f.label === myDossiersLabel || this._userPreferenceService.areDevFeaturesEnabled); } 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 92ff81d9e..fb56c35c2 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 @@ -4,6 +4,7 @@ [actionConfigs]="actionConfigs" [fileAttributeConfigs]="fileAttributeConfigs" [showCloseButton]="true" + [viewModeSelection]="viewModeSelection" > + +
@@ -72,95 +91,80 @@ - +
-
-
- - {{ fileStatus.filename }} +
+
+ {{ file.filename }} +
+
+
+
+ + {{ file.primaryAttribute }}
-
-
- - {{ fileStatus.primaryAttribute }} - -
-
-
-
- - {{ fileStatus.numberOfPages }} -
-
- - {{ fileStatus.excludedPagesCount }} -
-
- - {{ fileStatus.lastOCRTime | date: 'mediumDate' }} -
-
+
- +
-
- {{ fileStatus.added | date: 'd MMM. yyyy, hh:mm a' }} +
+ {{ file.added | date: 'd MMM. yyyy, hh:mm a' }}
- +
- {{ fileStatus.fileAttributes.attributeIdToValue[config.id] }} + {{ file.fileAttributes.attributeIdToValue[config.id] }}
- + -
+
-
- +
+
- -
- + +
+
- -
+ +
- {{ fileStatus.numberOfPages }} + {{ file.numberOfPages }}
- -
-
-
+ +
+
+
+ + +
+
+ + + +
+
+ + +
+
+
+
+ {{ file.filename }} +
+ +
+
+ +
+
+ +
+
+ + +
+
+ + {{ file.numberOfPages }} +
+
+ + {{ file.excludedPagesCount }} +
+
+ + {{ file.lastOCRTime | date: 'mediumDate' }} +
+
+
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.scss b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.scss index a0301eeab..5359d5727 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.scss +++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.scss @@ -1,4 +1,5 @@ @use 'variables'; +@use 'common-mixins'; .file-upload-input { display: none; @@ -27,6 +28,7 @@ .primary-attribute { padding-top: 6px; + @include common-mixins.line-clamp(1); } &.extend-cols { @@ -63,3 +65,56 @@ background-color: inherit; } } + +.view-mode-selection { + border-right: 1px solid variables.$separator; + padding-right: 16px; + margin-right: 16px !important; + display: flex; + align-items: center; + + > iqser-circle-button:not(:last-child) { + margin-right: 2px; + } + + > div { + margin-right: 8px; + } +} + +.workflow-item { + padding: 10px; + + > div { + display: flex; + justify-content: space-between; + + .details { + max-width: calc(100% - 28px); + + .filename { + font-weight: 600; + line-height: 18px; + @include common-mixins.line-clamp(1); + } + } + + .user { + display: flex; + align-items: flex-end; + } + } + + redaction-file-actions { + margin-top: 10px; + display: none; + } + + &:hover redaction-file-actions { + display: block; + } +} + +.stats-subtitle { + margin-top: 4px; +} diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.ts b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.ts index 52f15a9ef..14e31d540 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.ts @@ -10,6 +10,7 @@ import { TemplateRef, ViewChild } from '@angular/core'; +import { FileStatus, FileStatuses, IFileAttributeConfig } from '@redaction/red-ui-http'; import { AppStateService } from '@state/app-state.service'; import { FileDropOverlayService } from '@upload-download/services/file-drop-overlay.service'; import { FileUploadModel } from '@upload-download/model/file-upload.model'; @@ -18,13 +19,13 @@ import { StatusOverlayService } from '@upload-download/services/status-overlay.s import { TranslateService } from '@ngx-translate/core'; import * as moment from 'moment'; import { DossierDetailsComponent } from '../../components/dossier-details/dossier-details.component'; -import { FileStatusWrapper } from '@models/file/file-status.wrapper'; +import { File } from '@models/file/file'; import { UserService } from '@services/user.service'; import { timer } from 'rxjs'; import { tap } from 'rxjs/operators'; import { RedactionFilterSorter } from '@utils/sorters/redaction-filter-sorter'; import { StatusSorter } from '@utils/sorters/status-sorter'; -import { convertFiles, handleFileDrop } from '@utils/file-drop-utils'; +import { convertFiles, Files, handleFileDrop } from '@utils/file-drop-utils'; import { DossiersDialogService } from '../../services/dossiers-dialog.service'; import { OnAttach, OnDetach } from '@utils/custom-route-reuse.strategy'; import { ConfigService } from '@services/config.service'; @@ -32,32 +33,36 @@ import { ActionConfig } from '@shared/components/page-header/models/action-confi import { CircleButtonTypes, DefaultListingServices, + INestedFilter, keyChecker, ListingComponent, + ListingModes, LoadingService, NestedFilter, TableColumnConfig, TableComponent, - Toaster + Toaster, + WorkflowConfig } from '@iqser/common-ui'; import { DossierAttributesService } from '@shared/services/controller-wrappers/dossier-attributes.service'; import { DossierAttributeWithValue } from '@models/dossier-attributes.model'; -import { UserPreferenceService } from '@services/user-preference.service'; import { workloadTranslations } from '../../translations/workload-translations'; import { fileStatusTranslations } from '../../translations/file-status-translations'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { annotationFilterChecker } from '@utils/filter-utils'; import { PermissionsService } from '@services/permissions.service'; import { RouterHistoryService } from '@services/router-history.service'; -import { FileAttributeConfig } from '@redaction/red-ui-http'; -import { DossierWrapper } from '@state/model/dossier.wrapper'; +import { Dossier } from '@state/model/dossier'; +import { Router } from '@angular/router'; +import { FileActionService } from '../../services/file-action.service'; @Component({ templateUrl: './dossier-overview-screen.component.html', styleUrls: ['./dossier-overview-screen.component.scss'], providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => DossierOverviewScreenComponent) }] }) -export class DossierOverviewScreenComponent extends ListingComponent implements OnInit, OnDestroy, OnDetach, OnAttach { +export class DossierOverviewScreenComponent extends ListingComponent implements OnInit, OnDestroy, OnDetach, OnAttach { + readonly listingModes = ListingModes; readonly circleButtonTypes = CircleButtonTypes; readonly currentUser = this._userService.currentUser; currentDossier = this._appStateService.activeDossier; @@ -70,29 +75,30 @@ export class DossierOverviewScreenComponent extends ListingComponent[] = []; + tableColumnConfigs: readonly TableColumnConfig[] = []; collapsedDetails = false; dossierAttributes: DossierAttributeWithValue[] = []; - fileAttributeConfigs: FileAttributeConfig[]; - @ViewChild('filenameTemplate', { static: true }) filenameTemplate: TemplateRef; - @ViewChild('addedOnTemplate', { static: true }) addedOnTemplate: TemplateRef; - @ViewChild('attributeTemplate', { static: true }) attributeTemplate: TemplateRef; - @ViewChild('needsWorkTemplate', { static: true }) needsWorkTemplate: TemplateRef; - @ViewChild('reviewerTemplate', { static: true }) reviewerTemplate: TemplateRef; - @ViewChild('pagesTemplate', { static: true }) pagesTemplate: TemplateRef; - @ViewChild('statusTemplate', { static: true }) statusTemplate: TemplateRef; - protected readonly _primaryKey = 'filename'; + fileAttributeConfigs: IFileAttributeConfig[]; + @ViewChild('filenameTemplate', { static: true }) filenameTemplate: TemplateRef; + @ViewChild('addedOnTemplate', { static: true }) addedOnTemplate: TemplateRef; + @ViewChild('attributeTemplate', { static: true }) attributeTemplate: TemplateRef; + @ViewChild('needsWorkTemplate', { static: true }) needsWorkTemplate: TemplateRef; + @ViewChild('reviewerTemplate', { static: true }) reviewerTemplate: TemplateRef; + @ViewChild('pagesTemplate', { static: true }) pagesTemplate: TemplateRef; + @ViewChild('statusTemplate', { static: true }) statusTemplate: TemplateRef; + readonly workflowConfig: WorkflowConfig; @ViewChild(DossierDetailsComponent, { static: false }) private readonly _dossierDetailsComponent: DossierDetailsComponent; private _lastScrolledIndex: number; @ViewChild('needsWorkFilterTemplate', { read: TemplateRef, static: true }) private readonly _needsWorkFilterTemplate: TemplateRef; @ViewChild('fileInput') private readonly _fileInput: ElementRef; - @ViewChild(TableComponent) private readonly _tableComponent: TableComponent; + @ViewChild(TableComponent) private readonly _tableComponent: TableComponent; constructor( private readonly _toaster: Toaster, protected readonly _injector: Injector, + private readonly _router: Router, private readonly _userService: UserService, readonly permissionsService: PermissionsService, private readonly _loadingService: LoadingService, @@ -104,15 +110,53 @@ export class DossierOverviewScreenComponent extends ListingComponent entity.status, + itemVersionFn: (entity: File) => `${entity.lastUpdated}-${entity.numberOfAnalyses}`, + columns: [ + { + label: fileStatusTranslations[FileStatuses.UNASSIGNED], + key: FileStatuses.UNASSIGNED, + enterFn: this.unassignFn, + enterPredicate: (entity: File) => false, + color: '#D3D5DA' + }, + { + label: fileStatusTranslations[FileStatuses.UNDER_REVIEW], + enterFn: this.underReviewFn, + enterPredicate: (file: File) => + this.permissionsService.canSetUnderReview(file) || + this.permissionsService.canAssignToSelf(file) || + this.permissionsService.canAssignUser(file), + key: FileStatuses.UNDER_REVIEW, + color: '#FDBD00' + }, + { + label: fileStatusTranslations[FileStatuses.UNDER_APPROVAL], + enterFn: this.underApprovalFn, + enterPredicate: (file: File) => + this.permissionsService.canSetUnderApproval(file) || this.permissionsService.canUndoApproval(file), + key: FileStatuses.UNDER_APPROVAL, + color: '#374C81' + }, + { + label: fileStatusTranslations[FileStatuses.APPROVED], + enterFn: this.approveFn, + enterPredicate: (file: File) => this.permissionsService.isReadyForApproval(file), + key: FileStatuses.APPROVED, + color: '#48C9F7' + } + ] + }; } get checkedRequiredFilters() { @@ -127,11 +171,44 @@ export class DossierOverviewScreenComponent extends ListingComponent config.displayedInFileList); } - routerLinkFn = (fileStatus: FileStatusWrapper) => - fileStatus.canBeOpened ? [`/main/dossiers/${this.currentDossier.dossierId}/file/${fileStatus.fileId}`] : []; + unassignFn = async (file: File) => { + // TODO + console.log('unassign', file); + }; - disabledFn = (fileStatus: FileStatusWrapper) => fileStatus.excluded; - lastOpenedFn = (fileStatus: FileStatusWrapper) => fileStatus.lastOpened; + underReviewFn = (file: File) => { + this._fileActionService.assignFile('reviewer', null, file, () => this._loadingService.loadWhile(this.reloadDossiers()), true); + }; + + underApprovalFn = async (file: File) => { + if (this._appStateService.activeDossier.approverIds.length > 1) { + this._fileActionService.assignFile('approver', null, file, () => this._loadingService.loadWhile(this.reloadDossiers()), true); + } else { + this._loadingService.start(); + await this._fileActionService.setFilesUnderApproval([file]).toPromise(); + await this.reloadDossiers(); + this._loadingService.stop(); + } + }; + + approveFn = async (file: File) => { + this._loadingService.start(); + await this._fileActionService.setFilesApproved([file]).toPromise(); + await this.reloadDossiers(); + this._loadingService.stop(); + }; + + actionPerformed(action?: string, file?: File) { + this.calculateData(); + + if (action === 'navigate') { + this._router.navigate([file.routerLink]); + } + } + + disabledFn = (fileStatus: File) => fileStatus.excluded; + + lastOpenedFn = (fileStatus: File) => fileStatus.lastOpened; async ngOnInit(): Promise { this._configureTableColumns(); @@ -160,8 +237,6 @@ export class DossierOverviewScreenComponent extends ListingComponent (this._lastScrolledIndex = index))) .subscribe(); - this.searchService.setSearchKey('filename'); - this.dossierAttributes = await this._dossierAttributesService.getValues(this.currentDossier); } catch (e) { } finally { @@ -213,39 +288,39 @@ export class DossierOverviewScreenComponent extends ListingComponent { await this._uploadFiles(convertFiles(files, this.currentDossier)); this._fileInput.nativeElement.value = null; } - async bulkActionPerformed() { + async bulkActionPerformed(): Promise { this.entitiesService.setSelected([]); await this.reloadDossiers(); } openEditDossierDialog($event: MouseEvent) { this._dialogService.openDialog('editDossier', $event, { - dossierWrapper: this.currentDossier + dossier: this.currentDossier }); } openAssignDossierMembersDialog(): void { - const data = { dossierWrapper: this.currentDossier, section: 'members' }; + const data = { dossier: this.currentDossier, section: 'members' }; this._dialogService.openDialog('editDossier', null, data, async () => await this.reloadDossiers()); } openDossierDictionaryDialog() { - const data = { dossierWrapper: this.currentDossier, section: 'dossierDictionary' }; + const data = { dossier: this.currentDossier, section: 'dossierDictionary' }; this._dialogService.openDialog('editDossier', null, data, async () => { await this.reloadDossiers(); }); @@ -255,11 +330,11 @@ export class DossierOverviewScreenComponent extends ListingComponent + recentlyModifiedChecker = (file: File) => moment(file.lastUpdated).add(this._configService.values.RECENT_PERIOD_IN_HOURS, 'hours').isAfter(moment()); private _configureTableColumns() { - const dynamicColumns: TableColumnConfig[] = []; + const dynamicColumns: TableColumnConfig[] = []; for (const config of this.displayedInFileListAttributes) { if (config.displayedInFileList) { dynamicColumns.push({ label: config.label, notTranslatable: true, template: this.attributeTemplate, extra: config }); @@ -268,7 +343,7 @@ export class DossierOverviewScreenComponent extends ListingComponent(); + const allDistinctFileStatuses = new Set(); const allDistinctPeople = new Set(); const allDistinctAddedDates = new Set(); const allDistinctNeedsWork = new Set(); @@ -332,7 +407,7 @@ export class DossierOverviewScreenComponent extends ListingComponent { allDistinctPeople.add(file.currentReviewer); - allDistinctFileStatusWrapper.add(file.status); + allDistinctFileStatuses.add(file.status); allDistinctAddedDates.add(moment(file.added).format('DD/MM/YYYY')); if (file.analysisRequired) { @@ -379,33 +454,40 @@ export class DossierOverviewScreenComponent extends ListingComponent(item => ({ - key: item, - label: this._translateService.instant(fileStatusTranslations[item]) - })); + const statusFilters = [...allDistinctFileStatuses].map( + status => + new NestedFilter({ + id: status, + label: this._translateService.instant(fileStatusTranslations[status]) + }) + ); this.filterService.addFilterGroup({ slug: 'statusFilters', label: this._translateService.instant('filters.status'), icon: 'red:status', - filters: statusFilters.sort(StatusSorter.byStatus), + filters: statusFilters.sort((a, b) => StatusSorter[a.id] - StatusSorter[b.id]), checker: keyChecker('status') }); - const peopleFilters = []; + const peopleFilters: NestedFilter[] = []; if (allDistinctPeople.has(undefined) || allDistinctPeople.has(null)) { allDistinctPeople.delete(undefined); allDistinctPeople.delete(null); - peopleFilters.push({ - key: null, - label: this._translateService.instant('initials-avatar.unassigned') - }); + peopleFilters.push( + new NestedFilter({ + id: null, + label: this._translateService.instant('initials-avatar.unassigned') + }) + ); } allDistinctPeople.forEach(userId => { - peopleFilters.push({ - key: userId, - label: this._userService.getNameForId(userId) - }); + peopleFilters.push( + new NestedFilter({ + id: userId, + label: this._userService.getNameForId(userId) + }) + ); }); this.filterService.addFilterGroup({ slug: 'peopleFilters', @@ -415,10 +497,13 @@ export class DossierOverviewScreenComponent extends ListingComponent(item => ({ - key: item, - label: workloadTranslations[item] - })); + const needsWorkFilters = [...allDistinctNeedsWork].map( + item => + new NestedFilter({ + id: item, + label: workloadTranslations[item] + }) + ); this.filterService.addFilterGroup({ slug: 'needsWorkFilters', @@ -437,27 +522,33 @@ export class DossierOverviewScreenComponent extends ListingComponent((value: string) => ({ - key: value, - label: value === '-' ? this._translateService.instant('filters.empty') : value - })), - checker: (input: FileStatusWrapper, filter: NestedFilter) => filter.key === input.fileAttributes.attributeIdToValue[id] + filters: [...filterValue].map( + (value: string) => + new NestedFilter({ + id: value, + label: value === '-' ? this._translateService.instant('filters.empty') : value + }) + ), + checker: (input: File, filter: INestedFilter) => filter.id === input.fileAttributes.attributeIdToValue[id] }); }); this.filterService.addFilterGroup({ slug: 'quickFilters', filters: this._createQuickFilters(), - checker: (file: FileStatusWrapper) => + checker: (file: File) => this.checkedRequiredFilters.reduce((acc, f) => acc && f.checker(file), true) && (this.checkedNotRequiredFilters.length === 0 || this.checkedNotRequiredFilters.reduce((acc, f) => acc || f.checker(file), false)) }); - const filesNamesFilters = this.entitiesService.all.map(file => ({ - key: file.filename, - label: file.filename - })); + const filesNamesFilters = this.entitiesService.all.map( + file => + new NestedFilter({ + id: file.filename, + label: file.filename + }) + ); this.filterService.addFilterGroup({ slug: 'filesNamesFilter', @@ -469,13 +560,13 @@ export class DossierOverviewScreenComponent extends ListingComponent 0) { const recentPeriod = this._configService.values.RECENT_PERIOD_IN_HOURS; quickFilters = [ { - key: 'recent', + id: 'recent', label: this._translateService.instant('dossier-overview.quick-filters.recent', { hours: recentPeriod }), @@ -488,20 +579,20 @@ export class DossierOverviewScreenComponent extends ListingComponent file.currentReviewer === this.currentUser.id + checker: (file: File) => file.currentReviewer === this.currentUser.id }, { - key: 'unassigned', + id: 'unassigned', label: this._translateService.instant('dossier-overview.quick-filters.unassigned'), - checker: (file: FileStatusWrapper) => !file.currentReviewer + checker: (file: File) => !file.currentReviewer }, { - key: 'assigned-to-others', + id: 'assigned-to-others', label: this._translateService.instant('dossier-overview.quick-filters.assigned-to-others'), - checker: (file: FileStatusWrapper) => !!file.currentReviewer && file.currentReviewer !== this.currentUser.id + checker: (file: File) => !!file.currentReviewer && file.currentReviewer !== this.currentUser.id } - ]; + ].map(filter => new NestedFilter(filter)); } } diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.html b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.html index e89ac5086..583a45ec0 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.html @@ -92,6 +92,7 @@ (actionPerformed)="fileActionPerformed($event)" [activeDocumentInfo]="viewDocumentInfo" [activeExcludePages]="excludePages" + type="file-preview" > @@ -141,7 +142,7 @@ [annotations]="annotations" [canPerformActions]="canPerformAnnotationActions" [fileData]="displayData" - [fileStatus]="appStateService.activeFile" + [file]="appStateService.activeFile" [multiSelectActive]="multiSelectActive" [shouldDeselectAnnotationsOnPageChange]="shouldDeselectAnnotationsOnPageChange" > @@ -158,7 +159,7 @@ ; - @ViewChild('fileActions') fileActions: FileActionsComponent; + private readonly _filterTemplate: TemplateRef; constructor( readonly appStateService: AppStateService, @@ -97,7 +94,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni private readonly _annotationDrawService: AnnotationDrawService, private readonly _fileActionService: FileActionService, private readonly _fileDownloadService: PdfViewerDataService, - private readonly _statusControllerService: StatusControllerService, + private readonly _filesService: FilesService, private readonly _ngZone: NgZone, private readonly _fileManagementControllerService: FileManagementControllerService, private readonly _loadingService: LoadingService, @@ -113,7 +110,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni }); } - get singleUsersSelectOptions(): string[] { + get singleUsersSelectOptions(): List { return this.appStateService.activeFile?.isUnderApproval ? this.appStateService.activeDossier.approverIds : this.appStateService.activeDossier.memberIds; @@ -146,11 +143,11 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni } get canSwitchToRedactedView(): boolean { - return this.fileData && !this.fileData.fileStatus.analysisRequired && !this.fileData.fileStatus.excluded; + return this.fileData && !this.fileData.file.analysisRequired && !this.fileData.file.excluded; } get canSwitchToDeltaView(): boolean { - return this.fileData?.redactionChangeLog?.redactionLogEntry?.length > 0 && !this.fileData.fileStatus.excluded; + return this.fileData?.redactionChangeLog?.redactionLogEntry?.length > 0 && !this.fileData.file.excluded; } get canAssign(): boolean { @@ -174,7 +171,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni } get lastReviewer(): string | undefined { - return this.appStateService.activeFile.fileStatus.lastReviewer; + return this.appStateService.activeFile.lastReviewer; } get assignOrChangeReviewerTooltip(): string { @@ -187,11 +184,11 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni return this.appStateService.activeFile.currentReviewer; } - get status(): FileStatus.StatusEnum { + get status(): FileStatus { return this.appStateService.activeFile.status; } - get statusBarConfig(): [{ length: number; color: FileStatus.StatusEnum }] { + get statusBarConfig(): [{ length: number; color: FileStatus }] { return [{ length: 1, color: this.status }]; } @@ -200,9 +197,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni } get canAssignReviewer(): boolean { - return ( - !this.currentReviewer && this.permissionsService.canAssignUser() && this.appStateService.activeDossier.hasMoreThanOneReviewer - ); + return !this.currentReviewer && this.permissionsService.canAssignUser() && this.appStateService.activeDossier.hasReviewers; } updateViewMode(): void { @@ -261,7 +256,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni this._updateCanPerformActions(); this._subscribeToFileUpdates(); - if (this.fileData?.fileStatus?.analysisRequired) { + if (this.fileData?.file?.analysisRequired) { this.fileActions.reanalyseFile(); } } @@ -355,7 +350,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni response.manualRedactionEntryWrapper.rectId ); this._instance.Core.annotationManager.deleteAnnotation(annotation); - this.fileData.fileStatus = await this.appStateService.reloadActiveFile(); + this.fileData.file = await this.appStateService.reloadActiveFile(); const distinctPages = entryWrapper.manualRedactionEntry.positions .map(p => p.page) .filter((item, pos, self) => self.indexOf(item) === pos); @@ -490,18 +485,18 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni } async assignToMe() { - await this._fileActionService.assignToMe(this.fileData.fileStatus, async () => { + await this._fileActionService.assignToMe([this.fileData.file], async () => { await this.appStateService.reloadActiveFile(); this._updateCanPerformActions(); }); } - async assignReviewer(user: UserWrapper | string) { + async assignReviewer(user: User | string) { const reviewerId = typeof user === 'string' ? user : user.id; const reviewerName = this.userService.getNameForId(reviewerId); - const { dossierId, fileId, filename } = this.fileData.fileStatus; - await this._statusControllerService.setFileReviewer(dossierId, fileId, reviewerId).toPromise(); + const { dossierId, fileId, filename } = this.fileData.file; + await this._filesService.setReviewerFor([fileId], dossierId, reviewerId).toPromise(); this._toaster.info(_('assignment.reviewer'), { params: { reviewerName, filename } }); await this.appStateService.reloadActiveFile(); @@ -523,9 +518,9 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni downloadOriginalFile() { this.addSubscription = this._fileManagementControllerService - .downloadOriginalFile(this.dossierId, this.fileId, true, this.fileData.fileStatus.cacheIdentifier, 'response') + .downloadOriginalFile(this.dossierId, this.fileId, true, this.fileData.file.cacheIdentifier, 'response') .subscribe(data => { - download(data, this.fileData.fileStatus.filename); + download(data, this.fileData.file.filename); }); } @@ -561,7 +556,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni if (excludedPages && excludedPages.length > 0) { const pdfNet = this._instance.Core.PDFNet; const document = await this._instance.Core.documentViewer.getDocument().getPDFDoc(); - await clearStamps(document, pdfNet, [...Array(this.fileData.fileStatus.numberOfPages).keys()]); + await clearStamps(document, pdfNet, [...Array(this.fileData.file.numberOfPages).keys()]); await stampPDFPage( document, pdfNet, @@ -577,7 +572,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni } private async _stampExcludedPages() { - await this._doStampExcludedPages(this.fileData.fileStatus.excludedPages); + await this._doStampExcludedPages(this.fileData.file.excludedPages); this._instance.Core.documentViewer.refreshAll(); this._instance.Core.documentViewer.updateView([this.activeViewerPage], this.activeViewerPage); this._changeDetectorRef.detectChanges(); @@ -585,8 +580,8 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni private _subscribeToFileUpdates(): void { this.addSubscription = timer(0, 5000).subscribe(async () => await this.appStateService.reloadActiveFile()); - this.addSubscription = this.appStateService.fileReanalysed$.subscribe(async (fileStatus: FileStatusWrapper) => { - if (fileStatus.fileId === this.fileId) { + this.addSubscription = this.appStateService.fileReanalysed$.subscribe(async (file: File) => { + if (file.fileId === this.fileId) { await this._loadFileData(!this._reloadFileOnReanalysis); this._reloadFileOnReanalysis = false; this._loadingService.stop(); @@ -606,11 +601,11 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni private async _loadFileData(performUpdate = false): Promise { const fileData = await this._fileDownloadService.loadActiveFileData().toPromise(); - if (!fileData.fileStatus?.isPending && !fileData.fileStatus?.isError) { + if (!fileData.file?.isPending && !fileData.file?.isError) { if (performUpdate) { this.fileData.redactionLog = fileData.redactionLog; this.fileData.redactionChangeLog = fileData.redactionChangeLog; - this.fileData.fileStatus = fileData.fileStatus; + this.fileData.file = fileData.file; this.rebuildFilters(true); } else { this.fileData = fileData; @@ -620,7 +615,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni return; } - if (fileData.fileStatus.isError) { + if (fileData.file.isError) { await this._router.navigate(['/main/dossiers/' + this.dossierId]); } } @@ -648,7 +643,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni private async _cleanupAndRedrawManualAnnotationsForEntirePage(page: number) { const currentPageAnnotations = this.annotations.filter(a => a.pageNumber === page); const currentPageAnnotationIds = currentPageAnnotations.map(a => a.id); - this.fileData.fileStatus = await this.appStateService.reloadActiveFile(); + this.fileData.file = await this.appStateService.reloadActiveFile(); this._fileDownloadService.loadActiveFileRedactionLog().subscribe(redactionLogPreview => { this.fileData.redactionLog = redactionLogPreview; 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 8c348f2cd..7ffcb6273 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 @@ -1,23 +1,29 @@ import { Component, forwardRef, Injector, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core'; -import { DefaultListingServices, keyChecker, Listable, ListingComponent, LoadingService, TableColumnConfig } from '@iqser/common-ui'; -import { MatchedDocument, SearchControllerService, SearchResult } from '@redaction/red-ui-http'; +import { + DefaultListingServices, + IListable, + keyChecker, + ListingComponent, + LoadingService, + NestedFilter, + TableColumnConfig +} from '@iqser/common-ui'; +import { List, MatchedDocument, SearchControllerService, SearchResult } from '@redaction/red-ui-http'; 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 { FileStatusWrapper } from '@models/file/file-status.wrapper'; 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 { DossierWrapper } from '@state/model/dossier.wrapper'; import { TranslateService } from '@ngx-translate/core'; import { RouterHistoryService } from '@services/router-history.service'; -interface ListItem extends Listable { +interface ListItem extends IListable { readonly dossierId: string; readonly filename: string; - readonly unmatched: readonly string[] | null; - readonly highlights: Record; + readonly unmatched: List | null; + readonly highlights: Record; readonly routerLink: string; readonly status: string; readonly dossierName: string; @@ -26,7 +32,7 @@ interface ListItem extends Listable { interface SearchInput { readonly query: string; - readonly dossierIds?: readonly string[]; + readonly dossierIds?: List; } @Component({ @@ -53,7 +59,6 @@ export class SearchScreenComponent extends ListingComponent implements tap(result => this.entitiesService.setEntities(result)), tap(() => this._loadingService.stop()) ); - protected readonly _primaryKey = 'filename'; constructor( private readonly _router: Router, @@ -72,11 +77,14 @@ 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(dossier => ({ - key: dossier.dossierId, - label: dossier.dossierName - })), - checker: keyChecker('dossierId') + filters: this._appStateService.allDossiers.map( + dossier => + new NestedFilter({ + id: dossier.id, + label: dossier.dossierName + }) + ), + checker: keyChecker('id') }); this.addSubscription = _activatedRoute.queryParamMap @@ -89,17 +97,11 @@ export class SearchScreenComponent extends ListingComponent implements this.addSubscription = this.searchService.valueChanges$.pipe(debounceTime(300)).subscribe(value => this.updateNavigation(value)); this.addSubscription = this.filterService.filterGroups$.pipe(skip(1)).subscribe(group => { - const dossierIds = group[0].filters.filter(v => v.checked).map(v => v.key); + const dossierIds = group[0].filters.filter(v => v.checked).map(v => v.id); this.search$.next({ query: this.searchService.searchValue, dossierIds: dossierIds }); }); } - routerLinkFn = (entity: ListItem) => [entity.routerLink]; - - setInitialConfig(): void { - return; - } - updateNavigation(query: string, mustContain?: string): void { const newQuery = query?.replace(mustContain, `"${mustContain}"`); const queryParams = newQuery && newQuery !== '' ? { query: newQuery } : {}; @@ -137,14 +139,6 @@ export class SearchScreenComponent extends ListingComponent implements this.search$.next({ query, dossierIds: dossierId ? [dossierId] : [] }); } - private _getFileWrapper(dossierId: string, fileId: string): FileStatusWrapper { - return this._appStateService.getFileById(dossierId, fileId); - } - - private _getDossierWrapper(dossierId: string): DossierWrapper { - return this._appStateService.getDossierById(dossierId); - } - private _toMatchedDocuments({ matchedDocuments }: SearchResult): MatchedDocument[] { return matchedDocuments.filter(doc => doc.score > 0 && doc.matchedTerms.length > 0); } @@ -154,8 +148,8 @@ export class SearchScreenComponent extends ListingComponent implements } private _toListItem({ dossierId, fileId, unmatchedTerms, highlights }: MatchedDocument): ListItem { - const fileWrapper = this._getFileWrapper(dossierId, fileId); - if (!fileWrapper) { + const file = this._appStateService.getFileById(dossierId, fileId); + if (!file) { return undefined; } @@ -164,10 +158,11 @@ export class SearchScreenComponent extends ListingComponent implements dossierId, unmatched: unmatchedTerms || null, highlights, - status: fileWrapper.status, - numberOfPages: fileWrapper.numberOfPages, - dossierName: this._getDossierWrapper(dossierId).dossierName, - filename: fileWrapper.filename, + status: file.status, + numberOfPages: file.numberOfPages, + dossierName: this._appStateService.getDossierById(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/annotation-processing.service.ts b/apps/red-ui/src/app/modules/dossier/services/annotation-processing.service.ts index e426b0bf7..66eb5f2c5 100644 --- a/apps/red-ui/src/app/modules/dossier/services/annotation-processing.service.ts +++ b/apps/red-ui/src/app/modules/dossier/services/annotation-processing.service.ts @@ -1,38 +1,36 @@ import { Injectable } from '@angular/core'; import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { SuperTypeSorter } from '@utils/sorters/super-type-sorter'; -import { handleCheckedValue, NestedFilter } from '@iqser/common-ui'; +import { Filter, handleCheckedValue, IFilter, INestedFilter, NestedFilter } from '@iqser/common-ui'; import { annotationTypesTranslations } from '../../../translations/annotation-types-translations'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; @Injectable() export class AnnotationProcessingService { - static get secondaryAnnotationFilters(): NestedFilter[] { + static get secondaryAnnotationFilters(): INestedFilter[] { return [ { - key: 'with-comments', + id: 'with-comments', icon: 'red:comment', label: _('filter-menu.with-comments'), checked: false, topLevelFilter: true, - children: [], checker: (annotation: AnnotationWrapper) => annotation?.comments?.length > 0 }, { - key: 'with-reason-changes', + id: 'with-reason-changes', icon: 'red:reason', label: _('filter-menu.with-reason-changes'), checked: false, topLevelFilter: true, - children: [], checker: (annotation: AnnotationWrapper) => annotation?.legalBasisChangeValue?.length > 0 } - ]; + ].map(item => new NestedFilter(item)); } - getAnnotationFilter(annotations: AnnotationWrapper[]): NestedFilter[] { - const filterMap = new Map(); - const filters: NestedFilter[] = []; + getAnnotationFilter(annotations: AnnotationWrapper[]): INestedFilter[] { + const filterMap = new Map(); + const filters: INestedFilter[] = []; annotations?.forEach(a => { const topLevelFilter = a.superType !== 'hint' && a.superType !== 'redaction' && a.superType !== 'recommendation'; @@ -49,21 +47,20 @@ export class AnnotationProcessingService { if (!parentFilter) { parentFilter = this._createParentFilter(a.superType, filterMap, filters); } - const childFilter = { - key: a.type, + const childFilter: IFilter = { + id: a.type, label: a.type, checked: false, - filters: [], matches: 1 }; filterMap.set(key, childFilter); - parentFilter.children.push(childFilter); + parentFilter.children.push(new Filter(childFilter)); } } }); for (const filter of filters) { - filter.children.sort((a, b) => a.key.localeCompare(b.key)); + filter.children.sort((a, b) => a.id.localeCompare(b.id)); handleCheckedValue(filter); if (filter.checked || filter.indeterminate) { filter.expanded = true; @@ -73,13 +70,13 @@ export class AnnotationProcessingService { } } - return filters.sort((a, b) => SuperTypeSorter[a.key] - SuperTypeSorter[b.key]); + return filters.sort((a, b) => SuperTypeSorter[a.id] - SuperTypeSorter[b.id]); } filterAndGroupAnnotations( annotations: AnnotationWrapper[], - primaryFilters: NestedFilter[], - secondaryFilters?: NestedFilter[] + primaryFilters: INestedFilter[], + secondaryFilters?: INestedFilter[] ): Map { const obj = new Map(); @@ -116,21 +113,20 @@ export class AnnotationProcessingService { return obj; } - private _createParentFilter(key: string, filterMap: Map, filters: NestedFilter[]) { - const filter: NestedFilter = { - key: key, + private _createParentFilter(key: string, filterMap: Map, filters: INestedFilter[]) { + const filter: INestedFilter = new NestedFilter({ + id: key, topLevelFilter: true, matches: 1, - label: annotationTypesTranslations[key], - children: [] - }; + label: annotationTypesTranslations[key] + }); filterMap.set(key, filter); filters.push(filter); return filter; } - private _getFlatFilters(filters: NestedFilter[], filterBy?: (f: NestedFilter) => boolean) { - const flatFilters: NestedFilter[] = []; + private _getFlatFilters(filters: INestedFilter[], filterBy?: (f: INestedFilter) => boolean) { + const flatFilters: INestedFilter[] = []; filters.forEach(filter => { flatFilters.push(filter); @@ -140,7 +136,7 @@ export class AnnotationProcessingService { return filterBy ? flatFilters.filter(f => filterBy(f)) : flatFilters; } - private _matchesOne = (filters: NestedFilter[], condition: (filter: NestedFilter) => boolean): boolean => { + private _matchesOne = (filters: INestedFilter[], condition: (filter: INestedFilter) => boolean): boolean => { if (filters.length === 0) { return true; } @@ -154,7 +150,7 @@ export class AnnotationProcessingService { return false; }; - private _matchesAll = (filters: NestedFilter[], condition: (filter: NestedFilter) => boolean): boolean => { + private _matchesAll = (filters: INestedFilter[], condition: (filter: INestedFilter) => boolean): boolean => { if (filters.length === 0) { return true; } @@ -168,11 +164,11 @@ export class AnnotationProcessingService { return true; }; - private _checkByFilterKey = (filter: NestedFilter, annotation: AnnotationWrapper) => { + private _checkByFilterKey = (filter: INestedFilter, annotation: AnnotationWrapper) => { const superType = annotation.superType; const isNotTopLevelFilter = superType === 'hint' || superType === 'redaction' || superType === 'recommendation'; - return filter.key === superType || (filter.key === annotation.type && isNotTopLevelFilter); + return filter.id === superType || (filter.id === annotation.type && isNotTopLevelFilter); }; private _sortAnnotations(annotations: AnnotationWrapper[]): AnnotationWrapper[] { 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 1379a4b02..46a87f29b 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,33 +1,90 @@ -import { Injectable } from '@angular/core'; -import { Dossier, DossierControllerService } from '@redaction/red-ui-http'; +import { Injectable, Injector } from '@angular/core'; +import { 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'; +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'; + +export interface IDossiersStats { + totalPeople: number; + totalAnalyzedPages: number; +} + +const getRelatedEvents = filter(event => event instanceof ActivationEnd && event.snapshot.component !== BaseScreenComponent); @Injectable({ providedIn: 'root' }) -export class DossiersService { - constructor(private readonly _dossierControllerService: DossierControllerService) {} +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); - createOrUpdate(dossier: Dossier): Promise { - return this._dossierControllerService.createOrUpdateDossier(dossier).toPromise(); + constructor(protected readonly _injector: Injector, private readonly _router: Router) { + super(TEMPORARY_INJECTOR(_injector), 'dossier'); + this.activeDossierId$ = this._activeDossierId$.asObservable(); + this.activeDossier$ = this.activeDossierId$.pipe(map(id => this.all.find(dossier => dossier.id === id))); + + _router.events.pipe(getRelatedEvents).subscribe((event: ActivationEnd) => { + const dossierId = event.snapshot.paramMap.get('dossierId'); + const sameIdAsCurrentActive = dossierId === this._activeDossierId$.getValue(); + + if (sameIdAsCurrentActive) { + return; + } + + if (dossierId === null || dossierId === undefined) { + return this._activeDossierId$.next(null); + } + + // const notFound = !this.all.some(dossier => dossier.id === dossierId); + // if (notFound) { + // return this._router.navigate(['/main/dossiers']).then(); + // } + + this._activeDossierId$.next(dossierId); + }); } - delete(dossierId: string): Promise { - return this._dossierControllerService.deleteDossier(dossierId).toPromise(); + get(): Observable; + get(dossierId: string): Observable; + get(dossierId?: string): Observable { + return dossierId ? super._getOne([dossierId]) : super.getAll(); } - getAll(): Promise { - return this._dossierControllerService.getDossiers().toPromise(); + createOrUpdate(dossier: IDossier): Promise { + return this._post(dossier).toPromise(); } - getDeleted(): Promise { - return this._dossierControllerService.getDeletedDossiers().toPromise(); + getDeleted(): Promise { + return this.getAll('deleted-dossiers').toPromise(); } - restore(dossierIds: Array): Promise { - return this._dossierControllerService.restoreDossiers(dossierIds).toPromise(); + restore(dossierIds: List): Promise { + return this._post(dossierIds, 'deleted-dossiers/restore').toPromise(); } - hardDelete(dossierIds: Array): Promise { - return this._dossierControllerService.hardDeleteDossiers(dossierIds).toPromise(); + hardDelete(dossierIds: List): Promise { + const body = dossierIds.map(id => ({ key: 'dossierId', value: id })); + return this.delete(body, 'deleted-dossiers/hard-delete', body).toPromise(); + } + + private _computeStats(entities: List): IDossiersStats { + let totalAnalyzedPages = 0; + const totalPeople = new Set(); + + entities.forEach(dossier => { + dossier.memberIds?.forEach(m => totalPeople.add(m)); + totalAnalyzedPages += dossier.totalNumberOfPages; + }); + + return { + totalPeople: totalPeople.size, + totalAnalyzedPages + }; } } diff --git a/apps/red-ui/src/app/modules/dossier/services/file-action.service.ts b/apps/red-ui/src/app/modules/dossier/services/file-action.service.ts index 0189094e3..c32aa4e20 100644 --- a/apps/red-ui/src/app/modules/dossier/services/file-action.service.ts +++ b/apps/red-ui/src/app/modules/dossier/services/file-action.service.ts @@ -1,13 +1,13 @@ import { Injectable } from '@angular/core'; import { AppStateService } from '@state/app-state.service'; import { UserService } from '@services/user.service'; -import { ReanalysisControllerService, StatusControllerService } from '@redaction/red-ui-http'; -import { FileStatusWrapper } from '@models/file/file-status.wrapper'; +import { ReanalysisControllerService } from '@redaction/red-ui-http'; +import { File } from '@models/file/file'; import { PermissionsService } from '@services/permissions.service'; -import { isArray } from 'rxjs/internal-compatibility'; import { DossiersDialogService } from './dossiers-dialog.service'; -import { ConfirmationDialogInput } from '../../shared/dialogs/confirmation-dialog/confirmation-dialog.component'; +import { ConfirmationDialogInput } from '@shared/dialogs/confirmation-dialog/confirmation-dialog.component'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { FilesService } from './files.service'; @Injectable() export class FileActionService { @@ -15,107 +15,81 @@ export class FileActionService { private readonly _dialogService: DossiersDialogService, private readonly _permissionsService: PermissionsService, private readonly _userService: UserService, - private readonly _statusControllerService: StatusControllerService, + private readonly _fileService: FilesService, private readonly _reanalysisControllerService: ReanalysisControllerService, private readonly _appStateService: AppStateService ) {} - reanalyseFile(fileStatusWrapper?: FileStatusWrapper) { - if (!fileStatusWrapper) { - fileStatusWrapper = this._appStateService.activeFile; - } - return this._reanalysisControllerService.reanalyzeFile( - this._appStateService.activeDossier.dossierId, - fileStatusWrapper.fileId, - true - ); + reanalyseFile(file = this._appStateService.activeFile) { + return this._reanalysisControllerService.reanalyzeFile(this._appStateService.activeDossier.id, file.fileId, true); } - toggleAnalysis(fileStatusWrapper?: FileStatusWrapper) { - if (!fileStatusWrapper) { - fileStatusWrapper = this._appStateService.activeFile; - } - return this._reanalysisControllerService.toggleAnalysis( - fileStatusWrapper.dossierId, - fileStatusWrapper.fileId, - !fileStatusWrapper.excluded - ); + toggleAnalysis(file = this._appStateService.activeFile) { + return this._reanalysisControllerService.toggleAnalysis(file.dossierId, file.fileId, !file.excluded); } - async assignToMe(fileStatus?: FileStatusWrapper | FileStatusWrapper[], callback?: Function) { + async assignToMe(files?: File[], callback?: Function) { return new Promise((resolve, reject) => { - if (!isArray(fileStatus)) { - fileStatus = [fileStatus]; - } - - const atLeastOneFileHasReviewer = fileStatus.reduce((acc, fs) => acc || !!fs.currentReviewer, false); + const atLeastOneFileHasReviewer = files.reduce((acc, fs) => acc || !!fs.currentReviewer, false); if (atLeastOneFileHasReviewer) { const data = new ConfirmationDialogInput({ title: _('confirmation-dialog.assign-file-to-me.title'), question: _('confirmation-dialog.assign-file-to-me.question') }); this._dialogService.openDialog('confirm', null, data, () => { - this._assignReviewerToCurrentUser(fileStatus, callback) + this._assignReviewerToCurrentUser(files, callback) .then(() => resolve()) .catch(() => reject()); }); } else { - this._assignReviewerToCurrentUser(fileStatus, callback) + this._assignReviewerToCurrentUser(files, callback) .then(() => resolve()) .catch(() => reject()); } }); } - setFileUnderApproval(fileStatus: FileStatusWrapper | FileStatusWrapper[], approverId?: string) { - if (!isArray(fileStatus)) { - fileStatus = [fileStatus]; - } - + setFilesUnderApproval(files: File[], approverId?: string) { if (!approverId) { approverId = this._appStateService.activeDossier.approverIds[0]; } - return this._statusControllerService.setStatusUnderApprovalForList( - fileStatus.map(f => f.fileId), + return this._fileService.setUnderApprovalFor( + files.map(f => f.fileId), approverId, this._appStateService.activeDossierId ); } - setFileApproved(fileStatus: FileStatusWrapper | FileStatusWrapper[]) { - if (!isArray(fileStatus)) { - fileStatus = [fileStatus]; - } - return this._statusControllerService.setStatusApprovedForList( - fileStatus.map(f => f.fileId), + setFilesApproved(files: File[]) { + return this._fileService.setApprovedFor( + files.map(f => f.fileId), this._appStateService.activeDossierId ); } - setFileUnderReview(fileStatus: FileStatusWrapper | FileStatusWrapper[]) { - if (!isArray(fileStatus)) { - fileStatus = [fileStatus]; - } - return this._statusControllerService.setStatusUnderReviewForList( - fileStatus.map(f => f.fileId), + setFilesUnderReview(files: File[]) { + return this._fileService.setUnderReviewFor( + files.map(f => f.fileId), this._appStateService.activeDossierId ); } - ocrFile(fileStatus: FileStatusWrapper | FileStatusWrapper[]) { - if (!isArray(fileStatus)) { - fileStatus = [fileStatus]; - } + ocrFiles(files: File[]) { return this._reanalysisControllerService.ocrFiles( - fileStatus.map(f => f.fileId), + files.map(f => f.fileId), this._appStateService.activeDossierId ); } - assignFile(mode: 'reviewer' | 'approver', $event: MouseEvent, file?: FileStatusWrapper, callback?: Function, ignoreChanged = false) { - const files = file ? [file] : [this._appStateService.activeFile]; - const data = { mode, files, ignoreChanged }; + assignFile( + mode: 'reviewer' | 'approver', + $event: MouseEvent, + file = this._appStateService.activeFile, + callback?: Function, + ignoreChanged = false + ) { + const data = { mode, files: [file], ignoreChanged }; this._dialogService.openDialog('assignFile', $event, data, async () => { if (callback) { callback(); @@ -123,13 +97,10 @@ export class FileActionService { }); } - private async _assignReviewerToCurrentUser(fileStatus: FileStatusWrapper | FileStatusWrapper[], callback?: Function) { - if (!isArray(fileStatus)) { - fileStatus = [fileStatus]; - } - await this._statusControllerService - .setFileReviewerForList( - fileStatus.map(f => f.fileId), + private async _assignReviewerToCurrentUser(files: File[], callback?: Function) { + await this._fileService + .setReviewerFor( + files.map(f => f.fileId), this._appStateService.activeDossierId, this._userService.currentUser.id ) diff --git a/apps/red-ui/src/app/modules/dossier/services/files.service.ts b/apps/red-ui/src/app/modules/dossier/services/files.service.ts new file mode 100644 index 000000000..5b1f481f5 --- /dev/null +++ b/apps/red-ui/src/app/modules/dossier/services/files.service.ts @@ -0,0 +1,79 @@ +import { Injectable, Injector } from '@angular/core'; +import { EntitiesService, List, RequiredParam, Validate } from '@iqser/common-ui'; +import { IFile } from '@redaction/red-ui-http'; +import { File } from '@models/file/file'; +import { TEMPORARY_INJECTOR } from './injector'; +import { Observable } from 'rxjs'; + +@Injectable({ + providedIn: 'root' +}) +export class FilesService extends EntitiesService { + constructor(protected readonly _injector: Injector) { + super(TEMPORARY_INJECTOR(_injector), 'status'); + } + + /** + * Gets the status for all files. + */ + get(): Observable; + /** + * Gets the status for a file from a dossier. + */ + get(dossierId: string, fileId: string): Observable; + get(dossierId?: string, fileId?: string) { + if (dossierId && fileId) { + return super._getOne([dossierId, fileId]); + } + + return super.getAll(); + } + + getFor(dossierId: string): Observable; + getFor(dossierIds: List): Observable>; + getFor(args: string | List) { + if (typeof args === 'string') { + return super.getAll(`${this._defaultModelPath}/${args}`); + } + + return this._post>(args); + } + + @Validate() + setUnderApprovalFor(@RequiredParam() body: List, @RequiredParam() approverId: string, @RequiredParam() dossierId: string) { + const url = `${this._defaultModelPath}/underapproval/${dossierId}/bulk`; + return this._post(body, url, [{ key: 'approverId', value: approverId }]); + } + + /** + * Assigns a reviewer for a list of files. + */ + @Validate() + setReviewerFor(@RequiredParam() filesIds: List, @RequiredParam() dossierId: string, @RequiredParam() reviewerId: string) { + return this._post(filesIds, `${this._defaultModelPath}/${dossierId}/bulk/${reviewerId}`); + } + + /** + * Sets the status APPROVED for a list of files. + */ + @Validate() + setApprovedFor(@RequiredParam() filesIds: List, @RequiredParam() dossierId: string) { + return this._post(filesIds, `${this._defaultModelPath}/approved/${dossierId}/bulk`); + } + + /** + * Sets the status UNDER_REVIEW for a list of files. + */ + @Validate() + setUnderReviewFor(@RequiredParam() filesIds: List, @RequiredParam() dossierId: string) { + return this._post(filesIds, `${this._defaultModelPath}/underreview/${dossierId}/bulk`); + } + + /** + * Gets the deleted files for a dossier. + */ + @Validate() + getDeletedFilesFor(@RequiredParam() dossierId: string): Observable { + return this.getAll(`${this._defaultModelPath}/softdeleted/${dossierId}`); + } +} diff --git a/apps/red-ui/src/app/modules/dossier/services/injector.ts b/apps/red-ui/src/app/modules/dossier/services/injector.ts new file mode 100644 index 000000000..3100fb6e4 --- /dev/null +++ b/apps/red-ui/src/app/modules/dossier/services/injector.ts @@ -0,0 +1,16 @@ +import { Injector } from "@angular/core"; +import { FilterService, SearchService } from "@iqser/common-ui"; + +/** + * This should be removed when refactoring is done + * @param injector + * @constructor + */ +export const TEMPORARY_INJECTOR = injector => + Injector.create({ + providers: [ + { provide: FilterService, useClass: FilterService }, + { provide: SearchService, useClass: SearchService } + ], + parent: injector + }); diff --git a/apps/red-ui/src/app/modules/dossier/services/manual-annotation.service.ts b/apps/red-ui/src/app/modules/dossier/services/manual-annotation.service.ts index db88b7afa..f38d0bdc5 100644 --- a/apps/red-ui/src/app/modules/dossier/services/manual-annotation.service.ts +++ b/apps/red-ui/src/app/modules/dossier/services/manual-annotation.service.ts @@ -1,11 +1,6 @@ import { Injectable } from '@angular/core'; import { AppStateService } from '@state/app-state.service'; -import { - AddRedactionRequest, - DictionaryControllerService, - ForceRedactionRequest, - ManualRedactionControllerService -} from '@redaction/red-ui-http'; +import { AddRedactionRequest, ForceRedactionRequest, ManualRedactionControllerService } from '@redaction/red-ui-http'; import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { Toaster } from '@iqser/common-ui'; import { TranslateService } from '@ngx-translate/core'; @@ -28,7 +23,6 @@ export class ManualAnnotationService { private readonly _translateService: TranslateService, private readonly _toaster: Toaster, private readonly _manualRedactionControllerService: ManualRedactionControllerService, - private readonly _dictionaryControllerService: DictionaryControllerService, private readonly _permissionsService: PermissionsService ) { this.CONFIG = { diff --git a/apps/red-ui/src/app/modules/dossier/services/pdf-viewer-data.service.ts b/apps/red-ui/src/app/modules/dossier/services/pdf-viewer-data.service.ts index b27639250..d5f0ebaaf 100644 --- a/apps/red-ui/src/app/modules/dossier/services/pdf-viewer-data.service.ts +++ b/apps/red-ui/src/app/modules/dossier/services/pdf-viewer-data.service.ts @@ -10,7 +10,7 @@ import { import { FileDataModel } from '@models/file/file-data.model'; import { AppStateService } from '@state/app-state.service'; import { PermissionsService } from '@services/permissions.service'; -import { FileStatusWrapper } from '@models/file/file-status.wrapper'; +import { File } from '@models/file/file'; @Injectable() export class PdfViewerDataService { @@ -59,13 +59,7 @@ export class PdfViewerDataService { return of({ pages: [] }); } - downloadOriginalFile(fileStatus: FileStatusWrapper): Observable { - return this._fileManagementControllerService.downloadOriginalFile( - fileStatus.dossierId, - fileStatus.fileId, - true, - fileStatus.cacheIdentifier, - 'body' - ); + downloadOriginalFile(file: File): Observable { + return this._fileManagementControllerService.downloadOriginalFile(file.dossierId, file.fileId, true, file.cacheIdentifier, 'body'); } } diff --git a/apps/red-ui/src/app/modules/dossier/translations/file-status-translations.ts b/apps/red-ui/src/app/modules/dossier/translations/file-status-translations.ts index a72e50900..26432c048 100644 --- a/apps/red-ui/src/app/modules/dossier/translations/file-status-translations.ts +++ b/apps/red-ui/src/app/modules/dossier/translations/file-status-translations.ts @@ -1,7 +1,7 @@ import { FileStatus } from '@redaction/red-ui-http'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -export const fileStatusTranslations: { [key in FileStatus.StatusEnum]: string } = { +export const fileStatusTranslations: { [key in FileStatus]: string } = { APPROVED: _('file-status.approved'), DELETED: _('file-status.deleted'), ERROR: _('file-status.error'), diff --git a/apps/red-ui/src/app/modules/dossier/utils/compare-mode.utils.ts b/apps/red-ui/src/app/modules/dossier/utils/compare-mode.utils.ts index 18309a8df..899d386a8 100644 --- a/apps/red-ui/src/app/modules/dossier/utils/compare-mode.utils.ts +++ b/apps/red-ui/src/app/modules/dossier/utils/compare-mode.utils.ts @@ -22,7 +22,7 @@ export const loadCompareDocumentWrapper = async ( compareDocument, mergedDocument, instance, - fileStatus, + file, setCompareViewMode: () => void, navigateToPage: () => void, pdfNet: any @@ -44,7 +44,7 @@ export const loadCompareDocumentWrapper = async ( setCompareViewMode(); instance.loadDocument(mergedDocumentBuffer, { - filename: fileStatus ? fileStatus.filename : 'document.pdf' + filename: file?.filename ?? 'document.pdf' }); instance.disableElements(['compareButton']); instance.enableElements(['closeCompareButton']); diff --git a/apps/red-ui/src/app/modules/shared/components/annotation-icon/annotation-icon.component.ts b/apps/red-ui/src/app/modules/shared/components/annotation-icon/annotation-icon.component.ts index f35c4566e..398a87988 100644 --- a/apps/red-ui/src/app/modules/shared/components/annotation-icon/annotation-icon.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/annotation-icon/annotation-icon.component.ts @@ -1,5 +1,5 @@ import { Component, ElementRef, Input, OnChanges, ViewChild } from '@angular/core'; -import { TypeValueWrapper } from '@models/file/type-value.wrapper'; +import { TypeValue } from '@models/file/type-value'; @Component({ selector: 'redaction-annotation-icon', @@ -10,7 +10,7 @@ export class AnnotationIconComponent implements OnChanges { @Input() color: string; @Input() type: 'square' | 'rhombus' | 'circle' | 'hexagon' | 'none'; @Input() label: string; - @Input() dictType: TypeValueWrapper; + @Input() dictType: TypeValue; @ViewChild('icon', { static: true }) icon: ElementRef; diff --git a/apps/red-ui/src/app/modules/shared/components/assign-user-dropdown/assign-user-dropdown.component.ts b/apps/red-ui/src/app/modules/shared/components/assign-user-dropdown/assign-user-dropdown.component.ts index c804f9f2b..fd20f27b9 100644 --- a/apps/red-ui/src/app/modules/shared/components/assign-user-dropdown/assign-user-dropdown.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/assign-user-dropdown/assign-user-dropdown.component.ts @@ -1,5 +1,7 @@ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; -import { UserService, UserWrapper } from '@services/user.service'; +import { UserService } from '@services/user.service'; +import { List } from '@redaction/red-ui-http'; +import { User } from '@models/user'; @Component({ selector: 'redaction-assign-user-dropdown', @@ -8,27 +10,27 @@ import { UserService, UserWrapper } from '@services/user.service'; changeDetection: ChangeDetectionStrategy.OnPush }) export class AssignUserDropdownComponent { - oldUser: UserWrapper | string; - @Input() options: (UserWrapper | string)[]; - @Output() save = new EventEmitter(); - @Output() cancel = new EventEmitter(); - private _currentUser: UserWrapper | string; + oldUser: User | string; + @Input() options: List; + @Output() readonly save = new EventEmitter(); + @Output() readonly cancel = new EventEmitter(); + private _currentUser: User | string; constructor(private readonly _userService: UserService) {} - get value(): UserWrapper | string { + get value(): User | string { return this._currentUser; } @Input() - set value(value: UserWrapper | string) { + set value(value: User | string) { if (this.oldUser === undefined) { this.oldUser = value; } this._currentUser = value; } - getContext(user: UserWrapper | string) { + getContext(user: User | string) { return { userId: typeof user === 'string' ? user : user?.id }; } } diff --git a/apps/red-ui/src/app/modules/shared/components/buttons/file-download-btn/file-download-btn.component.ts b/apps/red-ui/src/app/modules/shared/components/buttons/file-download-btn/file-download-btn.component.ts index 7cf584f88..1d41ba93f 100644 --- a/apps/red-ui/src/app/modules/shared/components/buttons/file-download-btn/file-download-btn.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/buttons/file-download-btn/file-download-btn.component.ts @@ -1,7 +1,7 @@ import { ChangeDetectionStrategy, Component, Input, OnDestroy } from '@angular/core'; import { PermissionsService } from '@services/permissions.service'; -import { DossierWrapper } from '@state/model/dossier.wrapper'; -import { FileStatusWrapper } from '@models/file/file-status.wrapper'; +import { Dossier } from '../../../../../state/model/dossier'; +import { File } from '@models/file/file'; import { FileDownloadService } from '@upload-download/services/file-download.service'; import { Toaster } from '@iqser/common-ui'; import { AutoUnsubscribe, CircleButtonType, CircleButtonTypes } from '@iqser/common-ui'; @@ -17,8 +17,8 @@ export type MenuState = 'OPEN' | 'CLOSED'; changeDetection: ChangeDetectionStrategy.OnPush }) export class FileDownloadBtnComponent extends AutoUnsubscribe implements OnDestroy { - @Input() dossier: DossierWrapper; - @Input() file: FileStatusWrapper | FileStatusWrapper[]; + @Input() dossier: Dossier; + @Input() file: File | File[]; @Input() tooltipPosition: 'above' | 'below' | 'before' | 'after' = 'above'; @Input() type: CircleButtonType = CircleButtonTypes.default; @Input() tooltipClass: string; diff --git a/apps/red-ui/src/app/modules/shared/components/dictionary-annotation-icon/dictionary-annotation-icon.component.ts b/apps/red-ui/src/app/modules/shared/components/dictionary-annotation-icon/dictionary-annotation-icon.component.ts index 3fc06e497..5892b774f 100644 --- a/apps/red-ui/src/app/modules/shared/components/dictionary-annotation-icon/dictionary-annotation-icon.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/dictionary-annotation-icon/dictionary-annotation-icon.component.ts @@ -1,6 +1,6 @@ import { Component, Input, OnChanges } from '@angular/core'; import { AppStateService } from '@state/app-state.service'; -import { TypeValueWrapper } from '@models/file/type-value.wrapper'; +import { TypeValue } from '@models/file/type-value'; @Component({ selector: 'redaction-dictionary-annotation-icon', @@ -19,7 +19,7 @@ export class DictionaryAnnotationIconComponent implements OnChanges { ngOnChanges(): void { if (this.dictionaryKey) { - const typeValue: TypeValueWrapper = this._appStateService.getDictionaryTypeValue(this.dictionaryKey, this.dossierTemplateId); + const typeValue: TypeValue = this._appStateService.getDictionaryTypeValue(this.dictionaryKey, this.dossierTemplateId); this.color = this._appStateService.getDictionaryColor(this.dictionaryKey, this.dossierTemplateId); this.type = typeValue.hint ? 'circle' : 'square'; this.label = this.dictionaryKey[0].toUpperCase(); 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 dceeade0d..33bfc20ed 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 { DictionaryControllerService } from '@redaction/red-ui-http'; import { AppStateService } from '@state/app-state.service'; -import { Debounce, IconButtonTypes } from '@iqser/common-ui'; +import { Debounce, IconButtonTypes, List } from '@iqser/common-ui'; import { Observable } from 'rxjs'; import { map, take } from 'rxjs/operators'; -import { DossierWrapper } from '@state/model/dossier.wrapper'; +import { Dossier } from '@state/model/dossier'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { DictionaryService } from '@shared/services/dictionary.service'; import ICodeEditor = monaco.editor.ICodeEditor; import IDiffEditor = monaco.editor.IDiffEditor; import IModelDeltaDecoration = monaco.editor.IModelDeltaDecoration; @@ -23,14 +23,10 @@ const SMOOTH_SCROLL = 0; export class DictionaryManagerComponent implements OnChanges, OnInit { readonly iconButtonTypes = IconButtonTypes; - @Input() - withFloatingActions = true; - @Input() - initialEntries: string[]; - @Input() - canEdit = false; - @Output() - saveDictionary = new EventEmitter(); + @Input() withFloatingActions = true; + @Input() initialEntries: List; + @Input() canEdit = false; + @Output() readonly saveDictionary = new EventEmitter(); currentMatch = 0; findMatches: FindMatch[] = []; @@ -48,20 +44,15 @@ export class DictionaryManagerComponent implements OnChanges, OnInit { private _decorations: string[] = []; private _searchDecorations: string[] = []; - constructor( - private readonly _dictionaryControllerService: DictionaryControllerService, - private readonly _appStateService: AppStateService - ) { - this.currentEntries = this.initialEntries; - } + constructor(private readonly _dictionaryService: DictionaryService, private readonly _appStateService: AppStateService) {} - private _dossier: DossierWrapper = this.selectDossier as DossierWrapper; + private _dossier: Dossier = this.selectDossier as Dossier; get dossier() { return this._dossier; } - set dossier(dossier: DossierWrapper) { + set dossier(dossier: Dossier) { this._dossier = dossier; if (dossier === this.selectDossier) { @@ -99,6 +90,8 @@ export class DictionaryManagerComponent implements OnChanges, OnInit { } ngOnInit(): void { + this.currentEntries = [...this.initialEntries]; + this.editorOptions = { theme: 'vs', language: 'text/plain', @@ -125,7 +118,7 @@ export class DictionaryManagerComponent implements OnChanges, OnInit { } revert() { - this.currentEntries = this.initialEntries; + this.currentEntries = [...this.initialEntries]; this.searchChanged(''); } @@ -204,10 +197,10 @@ export class DictionaryManagerComponent implements OnChanges, OnInit { this._codeEditor.revealLineInCenter(range.startLineNumber, SMOOTH_SCROLL); } - private _onDossierChanged({ dossierId, dossierTemplateId }: DossierWrapper): Observable { - const dictionary$ = this._dictionaryControllerService.getDictionaryForType(dossierTemplateId, 'dossier_redaction', dossierId); + private _onDossierChanged({ id, dossierTemplateId }: Dossier): Observable { + const dictionary$ = this._dictionaryService.getFor(dossierTemplateId, 'dossier_redaction', id); - return dictionary$.pipe(map(data => this._toString(data.entries))); + return dictionary$.pipe(map(data => this._toString([...data.entries]))); } private _toString(entries: string[]) { diff --git a/apps/red-ui/src/app/modules/shared/components/initials-avatar/initials-avatar.component.ts b/apps/red-ui/src/app/modules/shared/components/initials-avatar/initials-avatar.component.ts index cd85fa28f..288f70a62 100644 --- a/apps/red-ui/src/app/modules/shared/components/initials-avatar/initials-avatar.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/initials-avatar/initials-avatar.component.ts @@ -1,7 +1,8 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy } from '@angular/core'; -import { UserService, UserWrapper } from '@services/user.service'; +import { UserService } from '@services/user.service'; import { TranslateService } from '@ngx-translate/core'; import { AutoUnsubscribe } from '@iqser/common-ui'; +import { User } from '@models/user'; @Component({ selector: 'redaction-initials-avatar', @@ -20,7 +21,7 @@ export class InitialsAvatarComponent extends AutoUnsubscribe implements OnChange displayName: string; initials: string; colorClass: string; - user: UserWrapper; + user: User; constructor( private readonly _userService: UserService, diff --git a/apps/red-ui/src/app/modules/shared/components/page-header/page-header.component.html b/apps/red-ui/src/app/modules/shared/components/page-header/page-header.component.html index cb2a0faa6..829a4b248 100644 --- a/apps/red-ui/src/app/modules/shared/components/page-header/page-header.component.html +++ b/apps/red-ui/src/app/modules/shared/components/page-header/page-header.component.html @@ -15,7 +15,9 @@
-
+
+ + diff --git a/apps/red-ui/src/app/modules/shared/components/page-header/page-header.component.scss b/apps/red-ui/src/app/modules/shared/components/page-header/page-header.component.scss index acbdfdf11..ffe60a1b5 100644 --- a/apps/red-ui/src/app/modules/shared/components/page-header/page-header.component.scss +++ b/apps/red-ui/src/app/modules/shared/components/page-header/page-header.component.scss @@ -1,3 +1,5 @@ +@import '../../../../../assets/styles/variables'; + .ml-6 { margin-left: 6px; } diff --git a/apps/red-ui/src/app/modules/shared/components/page-header/page-header.component.ts b/apps/red-ui/src/app/modules/shared/components/page-header/page-header.component.ts index fb1bc8eda..2465429d6 100644 --- a/apps/red-ui/src/app/modules/shared/components/page-header/page-header.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/page-header/page-header.component.ts @@ -1,25 +1,27 @@ -import { Component, EventEmitter, Input, Optional, Output } from '@angular/core'; +import { Component, EventEmitter, Input, Optional, Output, TemplateRef } from '@angular/core'; import { ActionConfig } from '@shared/components/page-header/models/action-config.model'; import { ButtonConfig } from '@shared/components/page-header/models/button-config.model'; -import { FilterService, SearchService } from '@iqser/common-ui'; +import { FilterService, IconButtonTypes, IListable, SearchService } from '@iqser/common-ui'; import { distinctUntilChanged, map } from 'rxjs/operators'; import { combineLatest, Observable, of } from 'rxjs'; import { SearchPosition, SearchPositions } from '@shared/components/page-header/models/search-positions.type'; -import { FileAttributeConfig } from '@redaction/red-ui-http'; +import { IFileAttributeConfig } from '@redaction/red-ui-http'; @Component({ selector: 'redaction-page-header', templateUrl: './page-header.component.html', styleUrls: ['./page-header.component.scss'] }) -export class PageHeaderComponent { +export class PageHeaderComponent { readonly searchPositions = SearchPositions; + readonly iconButtonTypes = IconButtonTypes; @Input() pageLabel: string; @Input() showCloseButton: boolean; @Input() actionConfigs: readonly ActionConfig[]; @Input() buttonConfigs: readonly ButtonConfig[]; - @Input() fileAttributeConfigs: readonly FileAttributeConfig[]; + @Input() fileAttributeConfigs: readonly IFileAttributeConfig[]; + @Input() viewModeSelection: TemplateRef; @Input() searchPlaceholder: string; @Input() searchWidth: number | 'full'; @Input() searchPosition: SearchPosition = SearchPositions.afterFilters; diff --git a/apps/red-ui/src/app/modules/shared/components/simple-doughnut-chart/simple-doughnut-chart.component.ts b/apps/red-ui/src/app/modules/shared/components/simple-doughnut-chart/simple-doughnut-chart.component.ts index 07271d371..f5f8cf4af 100644 --- a/apps/red-ui/src/app/modules/shared/components/simple-doughnut-chart/simple-doughnut-chart.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/simple-doughnut-chart/simple-doughnut-chart.component.ts @@ -56,7 +56,7 @@ export class SimpleDoughnutChartComponent implements OnChanges { } filterChecked$(key: string): Observable { - return this.statusFilters$.pipe(map(all => all?.find(e => e.key === key)?.checked)); + return this.statusFilters$.pipe(map(all => all?.find(e => e.id === key)?.checked)); } calculateChartData() { diff --git a/apps/red-ui/src/app/modules/shared/pipes/name.pipe.ts b/apps/red-ui/src/app/modules/shared/pipes/name.pipe.ts index b95d4e83c..d0618c670 100644 --- a/apps/red-ui/src/app/modules/shared/pipes/name.pipe.ts +++ b/apps/red-ui/src/app/modules/shared/pipes/name.pipe.ts @@ -1,6 +1,7 @@ import { Pipe, PipeTransform } from '@angular/core'; -import { UserService, UserWrapper } from '@services/user.service'; +import { UserService } from '@services/user.service'; import { TranslateService } from '@ngx-translate/core'; +import { User } from '@models/user'; @Pipe({ name: 'name' @@ -8,7 +9,7 @@ import { TranslateService } from '@ngx-translate/core'; export class NamePipe implements PipeTransform { constructor(private readonly _userService: UserService, private readonly _translateService: TranslateService) {} - transform(value: UserWrapper | string): string { + transform(value: User | string): string { if (typeof value === 'string') { return this._userService.getNameForId(value) || this._translateService.instant('unknown'); } diff --git a/apps/red-ui/src/app/modules/shared/services/controller-wrappers/dossier-attributes.service.ts b/apps/red-ui/src/app/modules/shared/services/controller-wrappers/dossier-attributes.service.ts index 21cac798a..1b11fb087 100644 --- a/apps/red-ui/src/app/modules/shared/services/controller-wrappers/dossier-attributes.service.ts +++ b/apps/red-ui/src/app/modules/shared/services/controller-wrappers/dossier-attributes.service.ts @@ -1,14 +1,15 @@ import { Injectable } from '@angular/core'; import { - DossierAttributeConfig, DossierAttributeReq, DossierAttributesControllerService, - DossierAttributesRes + DossierAttributesRes, + IDossierAttributeConfig } from '@redaction/red-ui-http'; -import { DossierWrapper } from '@state/model/dossier.wrapper'; +import { Dossier } from '@state/model/dossier'; import { DossierAttributeWithValue } from '@models/dossier-attributes.model'; import { AppStateService } from '@state/app-state.service'; import { Observable } from 'rxjs'; +import { DossierAttributeConfig } from '@state/model/dossier-attribute-config'; @Injectable({ providedIn: 'root' @@ -19,10 +20,10 @@ export class DossierAttributesService { private readonly _appStateService: AppStateService ) {} - async getValues(dossierWrapper: DossierWrapper): Promise { - const attributes = await this._dossierAttributesControllerService.getDossierAttributes(dossierWrapper.dossierId).toPromise(); + async getValues(dossier: Dossier): Promise { + const attributes = await this._dossierAttributesControllerService.getDossierAttributes(dossier.id).toPromise(); const attributesConfig = await this._dossierAttributesControllerService - .getDossierAttributesConfig(dossierWrapper.dossierTemplateId) + .getDossierAttributesConfig(dossier.dossierTemplateId) .toPromise(); return attributesConfig.dossierAttributeConfigs.map(config => ({ @@ -31,10 +32,8 @@ export class DossierAttributesService { })); } - setValues(dossierWrapper: DossierWrapper, dossierAttributeList: DossierAttributeReq[]): Promise { - return this._dossierAttributesControllerService - .setDossierAttributes({ dossierAttributeList }, dossierWrapper.dossierId) - .toPromise(); + setValues(dossier: Dossier, dossierAttributeList: DossierAttributeReq[]): Promise { + return this._dossierAttributesControllerService.setDossierAttributes({ dossierAttributeList }, dossier.id).toPromise(); } deleteConfigs(ids: string[], dossierTemplateId = this._appStateService.activeDossierTemplateId): Promise { @@ -42,16 +41,15 @@ export class DossierAttributesService { } async getConfig(dossierTemplateId = this._appStateService.activeDossierTemplateId): Promise { - return ( - (await this._dossierAttributesControllerService.getDossierAttributesConfig(dossierTemplateId).toPromise()) - ?.dossierAttributeConfigs || [] - ); + const config$ = this._dossierAttributesControllerService.getDossierAttributesConfig(dossierTemplateId); + const result = (await config$.toPromise())?.dossierAttributeConfigs || []; + return result.map(item => new DossierAttributeConfig(item)); } addOrUpdateConfig( - attribute: DossierAttributeConfig, + attribute: IDossierAttributeConfig, dossierTemplateId = this._appStateService.activeDossierTemplateId - ): Observable { + ): Observable { return this._dossierAttributesControllerService.addOrUpdateDossierAttributesConfig(attribute, dossierTemplateId); } } diff --git a/apps/red-ui/src/app/modules/shared/services/dictionary-save.service.ts b/apps/red-ui/src/app/modules/shared/services/dictionary-save.service.ts deleted file mode 100644 index dd4382b47..000000000 --- a/apps/red-ui/src/app/modules/shared/services/dictionary-save.service.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable, throwError } from 'rxjs'; -import { Toaster } from '@iqser/common-ui'; -import { DictionaryControllerService } from '@redaction/red-ui-http'; -import { tap } from 'rxjs/operators'; -import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; - -const MIN_WORD_LENGTH = 2; - -@Injectable({ - providedIn: 'root' -}) -export class DictionarySaveService { - constructor(private readonly _toaster: Toaster, private readonly _dictionaryControllerService: DictionaryControllerService) {} - - saveEntries( - entries: string[], - initialEntries: string[], - dossierTemplateId: string, - type: string, - dossierId: string, - showToast = true - ): Observable { - let entriesToAdd = []; - entries.forEach(currentEntry => { - entriesToAdd.push(currentEntry); - }); - // remove empty lines - entriesToAdd = entriesToAdd.filter(e => e && e.trim().length > 0).map(e => e.trim()); - const invalidRowsExist = entriesToAdd.filter(e => e.length < MIN_WORD_LENGTH); - if (invalidRowsExist.length === 0) { - // can add at least 1 - block UI - let obs: Observable; - if (entriesToAdd.length > 0) { - obs = this._dictionaryControllerService.addEntry(entriesToAdd, dossierTemplateId, type, dossierId, true); - } else { - obs = this._dictionaryControllerService.deleteEntries(initialEntries, dossierTemplateId, type, dossierId); - } - - return obs.pipe( - tap( - () => { - if (showToast) { - this._toaster.success(_('dictionary-overview.success.generic')); - } - }, - () => this._toaster.error(_('dictionary-overview.error.generic')) - ) - ); - } else { - this._toaster.error(_('dictionary-overview.error.entries-too-short')); - - return throwError('Entries too short'); - } - } -} diff --git a/apps/red-ui/src/app/modules/shared/services/dictionary.service.ts b/apps/red-ui/src/app/modules/shared/services/dictionary.service.ts new file mode 100644 index 000000000..6ed66324f --- /dev/null +++ b/apps/red-ui/src/app/modules/shared/services/dictionary.service.ts @@ -0,0 +1,162 @@ +import { Injectable, Injector } from '@angular/core'; +import { Observable, throwError } from 'rxjs'; +import { EntitiesService, List, QueryParam, RequiredParam, Toaster, Validate } from '@iqser/common-ui'; +import { Colors, IDictionary, ITypeValue, UpdateTypeValue } from '@redaction/red-ui-http'; +import { tap } from 'rxjs/operators'; +import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { TEMPORARY_INJECTOR } from '../../dossier/services/injector'; +import { Dictionary } from '@models/dictionary'; + +const MIN_WORD_LENGTH = 2; + +@Injectable({ + providedIn: 'root' +}) +export class DictionaryService extends EntitiesService { + constructor(private readonly _toaster: Toaster, protected readonly _injector: Injector) { + super(TEMPORARY_INJECTOR(_injector), 'dictionary'); + } + + /** + * Retrieves all dictionary entries of an entry type + */ + @Validate() + getFor(@RequiredParam() dossierTemplateId: string, @RequiredParam() type: string, dossierId?: string) { + const queryParams = dossierId ? [{ key: 'dossierId', value: dossierId }] : undefined; + return this._getOne([type, dossierTemplateId], this._defaultModelPath, queryParams); + } + + /** + * Deletes entry types + */ + @Validate() + deleteTypes(@RequiredParam() body: List, @RequiredParam() dossierTemplateId: string, dossierId?: string) { + const queryParams = dossierId ? [{ key: 'dossierId', value: dossierId }] : undefined; + const url = `${this._defaultModelPath}/type/${dossierTemplateId}/delete`; + return this._post(body, url, queryParams); + } + + /** + * Retrieve all entry types + */ + @Validate() + getAllTypes(@RequiredParam() dossierTemplateId: string, dossierId?: string) { + const queryParams = dossierId ? [{ key: 'dossierId', value: dossierId }] : undefined; + return this._getOne<{ types: ITypeValue[] }>(['type', dossierTemplateId], this._defaultModelPath, queryParams); + } + + /** + * Retrieves system colors for redaction. + */ + @Validate() + getColors(@RequiredParam() dossierTemplateId: string) { + return this._getOne([dossierTemplateId], 'color'); + } + + /** + * Updates colors, hint and caseInsensitive of an entry type. + */ + @Validate() + updateType( + @RequiredParam() body: UpdateTypeValue, + @RequiredParam() dossierTemplateId: string, + @RequiredParam() type: string, + dossierId?: string + ) { + const url = `${this._defaultModelPath}/type/${type}/${dossierTemplateId}`; + const queryParams = dossierId ? [{ key: 'dossierId', value: dossierId }] : undefined; + return this._post(body, url, queryParams); + } + + /** + * Set system colors for redaction + */ + @Validate() + setColors(@RequiredParam() body: Colors, @RequiredParam() dossierTemplateId: string) { + return this._post(body, `color/${dossierTemplateId}`); + } + + /** + * Creates entry type with colors, hint and caseInsensitive + */ + @Validate() + addType(@RequiredParam() body: ITypeValue, @RequiredParam() dossierId?: string) { + const queryParams = dossierId ? [{ key: 'dossierId', value: dossierId }] : undefined; + return this._post(body, `${this._defaultModelPath}/type`, queryParams); + } + + /** + * Add dictionary entries with entry type. + */ + @Validate() + addEntry( + @RequiredParam() body: List, + @RequiredParam() dossierTemplateId: string, + @RequiredParam() type: string, + dossierId?: string, + removeCurrent?: boolean + ) { + const queryParams: List = [ + { key: 'dossierId', value: dossierId }, + { key: 'removeCurrent', value: removeCurrent } + ]; + const url = `${this._defaultModelPath}/${type}/${dossierTemplateId}`; + return this._post(body, url, queryParams); + } + + /** + * Delete dictionary entries with entry type. + */ + @Validate() + deleteEntries( + @RequiredParam() body: List, + @RequiredParam() dossierTemplateId: string, + @RequiredParam() type: string, + @RequiredParam() dossierId?: string + ) { + const queryParams = dossierId ? [{ key: 'dossierId', value: dossierId }] : undefined; + const url = `${this._defaultModelPath}/delete/${type}/${dossierTemplateId}`; + return this._post(body, url, queryParams); + } + + saveEntries( + entries: List, + initialEntries: List, + dossierTemplateId: string, + type: string, + dossierId: string, + showToast = true + ): Observable { + let entriesToAdd = []; + entries.forEach(currentEntry => { + entriesToAdd.push(currentEntry); + }); + // remove empty lines + entriesToAdd = entriesToAdd.filter(e => e && e.trim().length > 0).map(e => e.trim()); + const invalidRowsExist = entriesToAdd.filter(e => e.length < MIN_WORD_LENGTH); + if (invalidRowsExist.length === 0) { + // can add at least 1 - block UI + let obs: Observable; + if (entriesToAdd.length > 0) { + obs = this.addEntry(entriesToAdd, dossierTemplateId, type, dossierId, true); + } else { + obs = this.deleteEntries(initialEntries, dossierTemplateId, type, dossierId); + } + + return obs.pipe( + tap( + () => { + if (showToast) { + this._toaster.success(_('dictionary-overview.success.generic')); + } + }, + () => this._toaster.error(_('dictionary-overview.error.generic')) + ) + ); + } else { + this._toaster.error(_('dictionary-overview.error.entries-too-short')); + + return throwError('Entries too short'); + } + } +} diff --git a/apps/red-ui/src/app/modules/shared/shared.module.ts b/apps/red-ui/src/app/modules/shared/shared.module.ts index 06178f8be..92d75e3b7 100644 --- a/apps/red-ui/src/app/modules/shared/shared.module.ts +++ b/apps/red-ui/src/app/modules/shared/shared.module.ts @@ -69,5 +69,4 @@ const modules = [MatConfigModule, ScrollingModule, IconsModule, FormsModule, Rea } ] }) -export class SharedModule { -} +export class SharedModule {} diff --git a/apps/red-ui/src/app/modules/upload-download/model/download-status.wrapper.ts b/apps/red-ui/src/app/modules/upload-download/model/download-status.wrapper.ts index 8c3c0f914..156e1ebc7 100644 --- a/apps/red-ui/src/app/modules/upload-download/model/download-status.wrapper.ts +++ b/apps/red-ui/src/app/modules/upload-download/model/download-status.wrapper.ts @@ -1,13 +1,17 @@ import { DownloadDetails, DownloadStatus } from '@redaction/red-ui-http'; -import { Listable } from '@iqser/common-ui'; +import { IListable } from '@iqser/common-ui'; -export class DownloadStatusWrapper implements Listable { +export class DownloadStatusWrapper implements IListable { inProgress: boolean; constructor(private _downloadStatus: DownloadStatus) {} get id() { - return this._downloadStatus.storageId; + return this.storageId; + } + + get searchKey(): string { + return this.storageId; } get size() { 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 597119a99..74230877b 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 @@ -3,8 +3,8 @@ import { DownloadControllerService, FileManagementControllerService } from '@red import { interval, Observable } from 'rxjs'; import { ConfigService } from '@services/config.service'; import { TranslateService } from '@ngx-translate/core'; -import { DossierWrapper } from '@state/model/dossier.wrapper'; -import { FileStatusWrapper } from '@models/file/file-status.wrapper'; +import { Dossier } from '@state/model/dossier'; +import { File } from '@models/file/file'; import { mergeMap, tap } from 'rxjs/operators'; import { DownloadStatusWrapper } from '../model/download-status.wrapper'; import { AppStateService } from '@state/app-state.service'; @@ -34,11 +34,11 @@ export class FileDownloadService { }); } - downloadFiles(fileStatusWrappers: FileStatusWrapper[], dossier: DossierWrapper): Observable { + downloadFiles(files: File[], dossier: Dossier): Observable { return this._downloadControllerService .prepareDownload({ - fileIds: fileStatusWrappers.map(f => f.fileId), - dossierId: dossier.dossierId + fileIds: files.map(f => f.fileId), + dossierId: dossier.id }) .pipe(mergeMap(() => this.getDownloadStatus())); } diff --git a/apps/red-ui/src/app/services/permissions.service.ts b/apps/red-ui/src/app/services/permissions.service.ts index 1a87cc9d9..02a6d9658 100644 --- a/apps/red-ui/src/app/services/permissions.service.ts +++ b/apps/red-ui/src/app/services/permissions.service.ts @@ -1,9 +1,9 @@ import { Injectable } from '@angular/core'; import { AppStateService } from '@state/app-state.service'; import { UserService } from './user.service'; -import { FileStatusWrapper } from '@models/file/file-status.wrapper'; +import { File } from '@models/file/file'; import { Comment } from '@redaction/red-ui-http'; -import { DossierWrapper } from '@state/model/dossier.wrapper'; +import { Dossier } from '@state/model/dossier'; @Injectable({ providedIn: 'root' @@ -11,50 +11,47 @@ import { DossierWrapper } from '@state/model/dossier.wrapper'; export class PermissionsService { constructor(private readonly _appStateService: AppStateService, private readonly _userService: UserService) {} - private get _activeFile(): FileStatusWrapper | undefined { + private get _activeFile(): File | undefined { return this._appStateService.activeFile; } - private get _activeDossier(): DossierWrapper | undefined { + private get _activeDossier(): Dossier | undefined { return this._appStateService.activeDossier; } - isReviewerOrApprover(fileStatus?: FileStatusWrapper): boolean { - return this.isFileReviewer(fileStatus) || this.isApprover(); + isReviewerOrApprover(file?: File): boolean { + return this.isFileReviewer(file) || this.isApprover(); } displayReanalyseBtn(dossier = this._activeDossier): boolean { return this.isApprover(dossier) && dossier.files.filter(file => file.analysisRequired).length > 0; } - canToggleAnalysis(fileStatus: FileStatusWrapper): boolean { - return this.isReviewerOrApprover(fileStatus) && ['UNASSIGNED', 'UNDER_REVIEW', 'UNDER_APPROVAL'].includes(fileStatus.status); + canToggleAnalysis(file: File): boolean { + return this.isReviewerOrApprover(file) && ['UNASSIGNED', 'UNDER_REVIEW', 'UNDER_APPROVAL'].includes(file.status); } - canReanalyseFile(fileStatus = this._activeFile): boolean { - return ( - (fileStatus.analysisRequired && (this.isReviewerOrApprover(fileStatus) || fileStatus.isUnassigned)) || - (fileStatus.isError && fileStatus.isUnassigned) - ); + canReanalyseFile(file = this._activeFile): boolean { + return (file.analysisRequired && (this.isReviewerOrApprover(file) || file.isUnassigned)) || (file.isError && file.isUnassigned); } - isFileReviewer(fileStatus = this._activeFile): boolean { - return fileStatus.currentReviewer === this._userService.currentUser.id; + isFileReviewer(file = this._activeFile): boolean { + return file.currentReviewer === this._userService.currentUser.id; } - canDeleteFile(fileStatus = this._activeFile, dossier?: DossierWrapper): boolean { - return (this.isOwner(dossier) && !fileStatus.isApproved) || fileStatus.isUnassigned; + canDeleteFile(file = this._activeFile, dossier?: Dossier): boolean { + return (this.isOwner(dossier) && !file.isApproved) || file.isUnassigned; } - canAssignToSelf(fileStatus = this._activeFile): boolean { - const precondition = this.isDossierMember() && !fileStatus.isProcessing && !fileStatus.isError && !fileStatus.isApproved; + canAssignToSelf(file = this._activeFile): boolean { + const precondition = this.isDossierMember() && !file.isProcessing && !file.isError && !file.isApproved; - const isTheOnlyReviewer = !this._appStateService.activeDossier?.hasMoreThanOneReviewer; + const isTheOnlyReviewer = !this._appStateService.activeDossier?.hasReviewers; if (precondition) { if ( - (fileStatus.isUnassigned || (fileStatus.isUnderReview && !this.isFileReviewer(fileStatus))) && - (this.isApprover() || isTheOnlyReviewer || (this.isDossierReviewer() && fileStatus.isUnassigned)) + (file.isUnassigned || (file.isUnderReview && !this.isFileReviewer(file))) && + (this.isApprover() || isTheOnlyReviewer || (this.isDossierReviewer() && file.isUnassigned)) ) { return true; } @@ -62,30 +59,30 @@ export class PermissionsService { return false; } - canAssignUser(fileStatus = this._activeFile): boolean { - const precondition = !fileStatus.isProcessing && !fileStatus.isError && !fileStatus.isApproved && this.isApprover(); + canAssignUser(file = this._activeFile): boolean { + const precondition = !file.isProcessing && !file.isError && !file.isApproved && this.isApprover(); if (precondition) { - if ((fileStatus.isUnassigned || fileStatus.isUnderReview) && this._activeDossier.hasMoreThanOneReviewer) { + if ((file.isUnassigned || file.isUnderReview) && this._activeDossier.hasReviewers) { return true; } - if (fileStatus.isUnderApproval && this._activeDossier.hasMoreThanOneApprover) { + if (file.isUnderApproval && this._activeDossier.approverIds.length > 1) { return true; } } return false; } - canSetUnderReview(fileStatus = this._activeFile): boolean { - return fileStatus?.isUnderApproval && this.isApprover(); + canSetUnderReview(file = this._activeFile): boolean { + return file?.isUnderApproval && this.isApprover(); } - isReadyForApproval(fileStatus = this._activeFile): boolean { - return this.canSetUnderReview(fileStatus); + isReadyForApproval(file = this._activeFile): boolean { + return this.canSetUnderReview(file); } - canSetUnderApproval(fileStatus = this._activeFile): boolean { - return fileStatus?.isUnderReview && this.isReviewerOrApprover(fileStatus); + canSetUnderApproval(file = this._activeFile): boolean { + return file?.isUnderReview && this.isReviewerOrApprover(file); } isOwner(dossier = this._activeDossier, user = this._userService.currentUser): boolean { @@ -104,25 +101,25 @@ export class PermissionsService { return dossier?.memberIds.includes(user.id); } - canPerformAnnotationActions(fileStatus = this._activeFile): boolean { - return ['UNDER_REVIEW', 'UNDER_APPROVAL'].includes(fileStatus?.status) && this.isFileReviewer(fileStatus); + canPerformAnnotationActions(file = this._activeFile): boolean { + return ['UNDER_REVIEW', 'UNDER_APPROVAL'].includes(file?.status) && this.isFileReviewer(file); } - canUndoApproval(fileStatus = this._activeFile): boolean { - return fileStatus?.isApproved && this.isApprover(); + canUndoApproval(file = this._activeFile): boolean { + return file?.isApproved && this.isApprover(); } - canMarkPagesAsViewed(fileStatus = this._activeFile): boolean { - return ['UNDER_REVIEW', 'UNDER_APPROVAL'].includes(fileStatus?.status) && this.isFileReviewer(fileStatus); + canMarkPagesAsViewed(file = this._activeFile): boolean { + return ['UNDER_REVIEW', 'UNDER_APPROVAL'].includes(file?.status) && this.isFileReviewer(file); } - canDownloadFiles(fileStatus = this._activeFile): boolean { - const dossier = this._appStateService.getDossierById(fileStatus?.dossierId); + canDownloadFiles(file = this._activeFile): boolean { + const dossier = this._appStateService.getDossierById(file?.dossierId); if (!dossier) { return false; } - return fileStatus.isApproved && this.isApprover(dossier); + return file.isApproved && this.isApprover(dossier); } canDeleteDossier(dossier = this._activeDossier): boolean { @@ -133,15 +130,15 @@ export class PermissionsService { return user.isAdmin; } - canAddComment(fileStatus = this._activeFile): boolean { - return (this.isFileReviewer(fileStatus) || this.isApprover()) && !fileStatus.isApproved; + canAddComment(file = this._activeFile): boolean { + return (this.isFileReviewer(file) || this.isApprover()) && !file.isApproved; } - canExcludePages(fileStatus = this._activeFile): boolean { - return ['UNDER_REVIEW', 'UNDER_APPROVAL'].includes(fileStatus.status) && (this.isFileReviewer(fileStatus) || this.isApprover()); + canExcludePages(file = this._activeFile): boolean { + return ['UNDER_REVIEW', 'UNDER_APPROVAL'].includes(file.status) && (this.isFileReviewer(file) || this.isApprover()); } - canDeleteComment(comment: Comment, fileStatus = this._activeFile) { - return (comment.user === this._userService.currentUser.id || this.isApprover()) && !fileStatus.isApproved; + canDeleteComment(comment: Comment, file = this._activeFile) { + return (comment.user === this._userService.currentUser.id || this.isApprover()) && !file.isApproved; } } diff --git a/apps/red-ui/src/app/services/user.service.ts b/apps/red-ui/src/app/services/user.service.ts index a7b86c994..5d159d8ed 100644 --- a/apps/red-ui/src/app/services/user.service.ts +++ b/apps/red-ui/src/app/services/user.service.ts @@ -1,12 +1,11 @@ import { Inject, Injectable } from '@angular/core'; import { KeycloakService } from 'keycloak-angular'; -import { KeycloakProfile } from 'keycloak-js'; import jwt_decode from 'jwt-decode'; -import { User, UserControllerService } from '@redaction/red-ui-http'; +import { IUser, UserControllerService } from '@redaction/red-ui-http'; import { wipeCaches } from '@redaction/red-cache'; import { BASE_HREF } from '../tokens'; import { Subject } from 'rxjs'; -import { Listable } from '@iqser/common-ui'; +import { User } from '@models/user'; export interface ProfileModel { username?: string; @@ -16,31 +15,13 @@ export interface ProfileModel { language: string; } -export class UserWrapper implements Listable { - constructor(private readonly _user: KeycloakProfile | User, public roles: string[], public id: string) {} - - email = this._user.email; - username = this._user.username || this.email; - firstName = this._user.firstName; - lastName = this._user.lastName; - name = this.firstName && this.lastName ? `${this.firstName} ${this.lastName}` : this.username; - searchKey = this.name + this.username + this.email; - - isActive = this.roles.length > 0; - isManager = this.roles.indexOf('RED_MANAGER') >= 0; - isUserAdmin = this.roles.indexOf('RED_USER_ADMIN') >= 0; - isUser = this.roles.indexOf('RED_USER') >= 0; - isAdmin = this.roles.indexOf('RED_ADMIN') >= 0; - hasAnyREDRoles = this.isUser || this.isManager || this.isAdmin || this.isUserAdmin; -} - @Injectable({ providedIn: 'root' }) export class UserService { usersReloaded$ = new Subject(); - private _currentUser: UserWrapper; - private _allUsers: UserWrapper[]; + private _currentUser: User; + private _allUsers: User[]; constructor( @Inject(BASE_HREF) private readonly _baseHref: string, @@ -48,17 +29,17 @@ export class UserService { private readonly _userControllerService: UserControllerService ) {} - private _allRedUsers: UserWrapper[]; + private _allRedUsers: User[]; - get managerUsers(): UserWrapper[] { + get managerUsers(): User[] { return this._allRedUsers.filter(user => user.isManager); } - get eligibleUsers(): UserWrapper[] { + get eligibleUsers(): User[] { return this._allRedUsers.filter(user => user.isUser || user.isManager); } - get currentUser(): UserWrapper { + get currentUser(): User { return this._currentUser; } @@ -74,13 +55,13 @@ export class UserService { } async loadAllUsers() { - let allUsers: User[]; + let allUsers: IUser[]; if (this._currentUser.isUserAdmin) { allUsers = await this._userControllerService.getAllUsers().toPromise(); } else { allUsers = await this._userControllerService.getUsers().toPromise(); } - this._allUsers = allUsers.map(user => new UserWrapper(user, user.roles, user.userId)); + this._allUsers = allUsers.map(user => new User(user, user.roles, user.userId)); this._allRedUsers = this._allUsers.filter(user => user.hasAnyREDRoles); this.usersReloaded$.next(); return this._allUsers; @@ -90,11 +71,7 @@ export class UserService { const token = await this._keycloakService.getToken(); const decoded = jwt_decode(token) as any; const userId = decoded.sub; - this._currentUser = new UserWrapper( - await this._keycloakService.loadUserProfile(true), - this._keycloakService.getUserRoles(true), - userId - ); + this._currentUser = new User(await this._keycloakService.loadUserProfile(true), this._keycloakService.getUserRoles(true), userId); } getRedUserById(id: string) { @@ -109,11 +86,7 @@ export class UserService { return this.getUserById(userId)?.name; } - isManager(user: UserWrapper = this._currentUser): boolean { - return user.roles.indexOf('RED_MANAGER') >= 0; - } - - hasAnyRole(requiredRoles: string[], user: UserWrapper = this._currentUser) { + hasAnyRole(requiredRoles: string[], user = this._currentUser): boolean { if (requiredRoles?.length > 0) { for (const role of requiredRoles) { if (user.roles.indexOf(role) >= 0) { 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 f28d7bebe..c32e29691 100644 --- a/apps/red-ui/src/app/state/app-state.service.ts +++ b/apps/red-ui/src/app/state/app-state.service.ts @@ -1,13 +1,11 @@ import { Injectable } from '@angular/core'; import { - DictionaryControllerService, - Dossier, DossierTemplateControllerService, FileAttributesConfig, FileAttributesControllerService, - FileStatus, - ReanalysisControllerService, - StatusControllerService + IDossier, + IFile, + ReanalysisControllerService } from '@redaction/red-ui-http'; import { Toaster } from '@iqser/common-ui'; import { TranslateService } from '@ngx-translate/core'; @@ -16,23 +14,24 @@ import { UserService } from '@services/user.service'; import { forkJoin, Observable, of, Subject } from 'rxjs'; import { catchError, map, tap } from 'rxjs/operators'; import { FALLBACK_COLOR, hexToRgb } from '@utils/functions'; -import { FileStatusWrapper } from '@models/file/file-status.wrapper'; -import { DossierWrapper } from './model/dossier.wrapper'; -import { TypeValueWrapper } from '@models/file/type-value.wrapper'; -import { DossierTemplateModelWrapper } from '@models/file/dossier-template-model.wrapper'; +import { File } from '@models/file/file'; +import { Dossier } from './model/dossier'; +import { TypeValue } from '@models/file/type-value'; +import { DossierTemplate } from '@models/file/dossier-template'; import { DossiersService } from '../modules/dossier/services/dossiers.service'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { UserPreferenceService } from '@services/user-preference.service'; +import { FilesService } from '../modules/dossier/services/files.service'; +import { DictionaryService } from '@shared/services/dictionary.service'; export interface AppState { - dossiers: DossierWrapper[]; - dossierTemplates: DossierTemplateModelWrapper[]; + dossiers: Dossier[]; + dossierTemplates: DossierTemplate[]; activeDossierId: string; activeFileId: string; activeDossierTemplateId: string; activeDictionaryType: string; totalAnalysedPages?: number; - totalDocuments?: number; totalPeople?: number; } @@ -40,10 +39,10 @@ export interface AppState { providedIn: 'root' }) export class AppStateService { - readonly fileChanged$ = new Subject(); - readonly fileReanalysed$ = new Subject(); - readonly dossierChanged$ = new Subject(); - readonly dossierTemplateChanged$ = new Subject(); + readonly fileChanged$ = new Subject(); + readonly fileReanalysed$ = new Subject(); + readonly dossierChanged$ = new Subject(); + readonly dossierTemplateChanged$ = new Subject(); private _appState: AppState; @@ -51,12 +50,12 @@ export class AppStateService { private readonly _router: Router, private readonly _userService: UserService, private readonly _dossiersService: DossiersService, + private readonly _filesService: FilesService, private readonly _toaster: Toaster, private readonly _reanalysisControllerService: ReanalysisControllerService, private readonly _translateService: TranslateService, - private readonly _dictionaryControllerService: DictionaryControllerService, + private readonly _dictionaryService: DictionaryService, private readonly _dossierTemplateControllerService: DossierTemplateControllerService, - private readonly _statusControllerService: StatusControllerService, private readonly _fileAttributesService: FileAttributesControllerService, private readonly _userPreferenceService: UserPreferenceService ) { @@ -85,13 +84,13 @@ export class AppStateService { }); } - private _dictionaryData: { [key: string]: { [key: string]: TypeValueWrapper } } = null; + private _dictionaryData: { [key: string]: { [key: string]: TypeValue } } = null; - get dictionaryData(): { [key: string]: { [key: string]: TypeValueWrapper } } { + get dictionaryData(): { [key: string]: { [key: string]: TypeValue } } { return this._dictionaryData; } - get aggregatedFiles(): FileStatusWrapper[] { + get aggregatedFiles(): File[] { return this.allDossiers.reduce((acc, { files }) => [...acc, ...files], []); } @@ -99,11 +98,11 @@ export class AppStateService { return this._appState.activeDossierTemplateId; } - get activeDossierTemplate(): DossierTemplateModelWrapper { + get activeDossierTemplate(): DossierTemplate { return this.getDossierTemplateById(this.activeDossierTemplateId); } - get dossierTemplates(): DossierTemplateModelWrapper[] { + get dossierTemplates(): DossierTemplate[] { return this._appState.dossierTemplates; } @@ -111,7 +110,7 @@ export class AppStateService { return this._appState.activeDictionaryType; } - get activeDictionary(): TypeValueWrapper { + get activeDictionary(): TypeValue { return this.activeDossierTemplateId && this.dictionaryData[this.activeDossierTemplateId] ? this.dictionaryData[this.activeDossierTemplateId][this.activeDictionaryType] : null; @@ -121,11 +120,11 @@ export class AppStateService { return this._appState.activeDossierId; } - get activeDossier(): DossierWrapper | undefined { - return this.allDossiers.find(p => p.dossierId === this.activeDossierId); + get activeDossier(): Dossier | undefined { + return this.allDossiers.find(p => p.id === this.activeDossierId); } - get allDossiers(): DossierWrapper[] { + get allDossiers(): Dossier[] { return this._appState.dossiers; } @@ -133,7 +132,7 @@ export class AppStateService { return this.allDossiers?.length > 0; } - get activeFile(): FileStatusWrapper | undefined { + get activeFile(): File | undefined { return this.activeDossier?.files.find(f => f.fileId === this.activeFileId); } @@ -187,11 +186,11 @@ export class AppStateService { return color ?? this._dictionaryData[dossierTemplateId]['default'].hexColor; } - getDossierTemplateById(id: string): DossierTemplateModelWrapper { + getDossierTemplateById(id: string): DossierTemplate { return this.dossierTemplates.find(rs => rs.dossierTemplateId === id); } - getDictionaryTypeValue(key: string, dossierTemplateId?: string): TypeValueWrapper { + getDictionaryTypeValue(key: string, dossierTemplateId?: string): TypeValue { if (!dossierTemplateId && this.activeDossier) { dossierTemplateId = this.activeDossier.dossierTemplateId; } @@ -208,7 +207,7 @@ export class AppStateService { } getDossierById(id: string) { - return this.allDossiers.find(dossier => dossier.dossierId === id); + return this.allDossiers.find(dossier => dossier.id === id); } getFileById(dossierId: string, fileId: string) { @@ -216,18 +215,16 @@ export class AppStateService { } async loadAllDossiers(emitEvents: boolean = true) { - const dossiers = await this._dossiersService.getAll(); + const dossiers = await this._dossiersService.get().toPromise(); if (!dossiers) { return; } - const mappedDossiers = dossiers.map( - p => new DossierWrapper(p, this.getDossierTemplateById(p.dossierTemplateId).name, this._getExistingFiles(p.dossierId)) - ); - const fileData = await this._statusControllerService.getFileStatusForDossiers(mappedDossiers.map(p => p.dossierId)).toPromise(); + const mappedDossiers = dossiers.map(p => new Dossier(p, this._getExistingFiles(p.dossierId))); + const fileData = await this._filesService.getFor(mappedDossiers.map(p => p.id)).toPromise(); for (const dossierId of Object.keys(fileData)) { - const dossier = mappedDossiers.find(p => p.dossierId === dossierId); + const dossier = mappedDossiers.find(p => p.id === dossierId); this._processFiles(dossier, fileData[dossierId], emitEvents); } @@ -241,34 +238,32 @@ export class AppStateService { } const oldProcessedDate = this.activeFile.lastProcessed; const dossierTemplateId = this.activeFile.dossierTemplateId; - const activeFile = await this._statusControllerService.getFileStatus(this.activeDossierId, this.activeFileId).toPromise(); - activeFile.dossierTemplateId = dossierTemplateId; + const iFile = await this._filesService.get(this.activeDossierId, this.activeFileId).toPromise(); + iFile.dossierTemplateId = dossierTemplateId; - const activeFileWrapper = new FileStatusWrapper( - activeFile, - this._userService.getNameForId(activeFile.currentReviewer), - this.getFileAttributeConfig(activeFile.dossierTemplateId) - ); - this.activeDossier.files = this.activeDossier?.files.map(file => - file.fileId === activeFileWrapper.fileId ? activeFileWrapper : file + const activeFile = new File( + iFile, + this._userService.getNameForId(iFile.currentReviewer), + this.getFileAttributeConfig(iFile.dossierTemplateId) ); + this.activeDossier.files = this.activeDossier?.files.map(file => (file.fileId === activeFile.fileId ? activeFile : file)); this._computeStats(); - if (activeFileWrapper.lastProcessed !== oldProcessedDate) { - this.fileReanalysed$.next(activeFileWrapper); + if (activeFile.lastProcessed !== oldProcessedDate) { + this.fileReanalysed$.next(activeFile); } - this.fileChanged$.next(activeFileWrapper); - return activeFileWrapper; + this.fileChanged$.next(activeFile); + return activeFile; } - async getFiles(dossier: DossierWrapper = this.activeDossier, emitEvents = true) { - const files = await this._statusControllerService.getDossierStatus(dossier.dossierId).toPromise(); + async getFiles(dossier: Dossier = this.activeDossier, emitEvents = true) { + const files = await this._filesService.getFor(dossier.id).toPromise(); return this._processFiles(dossier, files, emitEvents); } - async reanalyzeDossier({ dossierId }: DossierWrapper = this.activeDossier) { - await this._reanalysisControllerService.reanalyzeDossier(dossierId, true).toPromise(); + async reanalyzeDossier({ id }: Dossier = this.activeDossier) { + await this._reanalysisControllerService.reanalyzeDossier(id, true).toPromise(); } async activateDossier(dossierId: string) { @@ -287,9 +282,7 @@ export class AppStateService { // dossier exists, load its dictionary const dossier = this.getDossierById(dossierId); try { - dossier.type = await this._dictionaryControllerService - .getDictionaryForType(dossierTemplateId, 'dossier_redaction', dossierId) - .toPromise(); + dossier.type = await this._dictionaryService.getFor(dossierTemplateId, 'dossier_redaction', dossierId).toPromise(); } catch (e) { dossier.type = null; } @@ -337,29 +330,28 @@ export class AppStateService { this._appState.activeDictionaryType = null; } - deleteDossier(dossier: DossierWrapper) { - return this._dossiersService.delete(dossier.dossierId).then( - () => { - const index = this.allDossiers.findIndex(p => p.dossierId === dossier.dossierId); - this._appState.dossiers.splice(index, 1); - }, - () => this._toaster.error(_('dossier-listing.delete.delete-failed'), { params: dossier }) - ); + deleteDossier(dossier: Dossier) { + return this._dossiersService + .delete(dossier.id) + .toPromise() + .then( + () => { + const index = this.allDossiers.findIndex(p => p.id === dossier.id); + this._appState.dossiers.splice(index, 1); + }, + () => this._toaster.error(_('dossier-listing.delete.delete-failed'), { params: dossier }) + ); } - async createOrUpdateDossier(dossier: Dossier) { + async createOrUpdateDossier(dossier: IDossier) { try { const updatedDossier = await this._dossiersService.createOrUpdate(dossier); - let foundDossier = this.allDossiers.find(p => p.dossierId === updatedDossier.dossierId); + let foundDossier = this.allDossiers.find(p => p.id === updatedDossier.dossierId); if (foundDossier) { this._appState.dossiers.splice(this._appState.dossiers.indexOf(foundDossier), 1); - foundDossier = new DossierWrapper( - updatedDossier, - this.getDossierTemplateById(updatedDossier.dossierTemplateId).name, - foundDossier.files - ); + foundDossier = new Dossier(updatedDossier, foundDossier.files); } else { - foundDossier = new DossierWrapper(updatedDossier, this.getDossierTemplateById(updatedDossier.dossierTemplateId).name, []); + foundDossier = new Dossier(updatedDossier, []); } this._appState.dossiers.push(foundDossier); @@ -380,7 +372,7 @@ export class AppStateService { async loadAllDossierTemplates() { const dossierTemplates = await this._dossierTemplateControllerService.getAllDossierTemplates().toPromise(); - this._appState.dossierTemplates = dossierTemplates.map(dossierTemplate => new DossierTemplateModelWrapper(dossierTemplate, null)); + this._appState.dossierTemplates = dossierTemplates.map(dossierTemplate => new DossierTemplate(dossierTemplate, null)); for (const dossierTemplate of this._appState.dossierTemplates) { dossierTemplate.fileAttributesConfig = await this._fileAttributesService .getFileAttributesConfiguration(dossierTemplate.dossierTemplateId) @@ -399,7 +391,7 @@ export class AppStateService { Object.assign( this._appState.dossierTemplates.find(d => d.dossierTemplateId === dossierTemplateId), - new DossierTemplateModelWrapper(dossierTemplate, fileAttributesConfigs) + new DossierTemplate(dossierTemplate, fileAttributesConfigs) ); await this.refreshDossierTemplateDictionaryData(dossierTemplateId); @@ -449,15 +441,15 @@ export class AppStateService { private _getDictionaryDataForDossierTemplateObservables(dossierTemplateId: string): Observable<{ [key: string]: any }> { const dictionaryData: { [key: string]: any } = {}; - const typeObs = this._dictionaryControllerService.getAllTypes(dossierTemplateId).pipe( + const typeObs = this._dictionaryService.getAllTypes(dossierTemplateId).pipe( tap(typesResponse => { for (const type of typesResponse.types) { - dictionaryData[type.type] = new TypeValueWrapper(type); + dictionaryData[type.type] = new TypeValue(type); } }) ); - const colorsObs = this._dictionaryControllerService.getColors(dossierTemplateId).pipe( + const colorsObs = this._dictionaryService.getColors(dossierTemplateId).pipe( tap(colors => { for (const key of Object.keys(colors)) { const color = colors[key]; @@ -471,207 +463,184 @@ export class AppStateService { } } - // declined - dictionaryData['declined-suggestion'] = new TypeValueWrapper( + dictionaryData['declined-suggestion'] = new TypeValue( { hexColor: colors.notRedacted, type: 'declined-suggestion' }, - null, true ); - // manual - dictionaryData['manual'] = new TypeValueWrapper( + + dictionaryData['manual'] = new TypeValue( { hexColor: colors.manualRedactionColor, type: 'manual' }, - null, true ); - // manual - dictionaryData['manual-redaction'] = new TypeValueWrapper( + + dictionaryData['manual-redaction'] = new TypeValue( { hexColor: colors.manualRedactionColor, type: 'manual-redaction' }, - null, true ); // dictionary actions - dictionaryData['recommendation'] = new TypeValueWrapper( + dictionaryData['recommendation'] = new TypeValue( { hexColor: '#c5d3eb', type: 'recommendation' }, - null, true ); // dictionary actions - dictionaryData['add-dictionary'] = new TypeValueWrapper( + dictionaryData['add-dictionary'] = new TypeValue( { hexColor: colors.analysisColor, type: 'add-dictionary' }, - null, true ); - dictionaryData['remove-dictionary'] = new TypeValueWrapper( + dictionaryData['remove-dictionary'] = new TypeValue( { hexColor: colors.analysisColor, type: 'remove-dictionary' }, - null, true ); - dictionaryData['remove-only-here'] = new TypeValueWrapper( + dictionaryData['remove-only-here'] = new TypeValue( { hexColor: colors.analysisColor, type: 'remove-only-here' }, - null, true ); // generic suggestions - dictionaryData['suggestion'] = new TypeValueWrapper( + dictionaryData['suggestion'] = new TypeValue( { hexColor: colors.requestAdd, type: 'suggestion' }, - null, true ); - // add suggestions - dictionaryData['suggestion-add'] = new TypeValueWrapper( + + dictionaryData['suggestion-add'] = new TypeValue( { hexColor: colors.requestAdd, type: 'suggestion-add' }, - null, true ); // add suggestions - dictionaryData['suggestion-change-legal-basis'] = new TypeValueWrapper( + dictionaryData['suggestion-change-legal-basis'] = new TypeValue( { hexColor: colors.requestAdd, type: 'suggestion-change-legal-basis' }, - null, true ); - dictionaryData['suggestion-recategorize-image'] = new TypeValueWrapper( + dictionaryData['suggestion-recategorize-image'] = new TypeValue( { hexColor: colors.requestAdd, type: 'suggestion-recategorize-image' }, - null, true ); - dictionaryData['suggestion-add-dictionary'] = new TypeValueWrapper( + dictionaryData['suggestion-add-dictionary'] = new TypeValue( { hexColor: colors.dictionaryRequestColor, type: 'suggestion-add' }, - null, true ); - // suggestion remove - dictionaryData['suggestion-remove'] = new TypeValueWrapper( + + dictionaryData['suggestion-remove'] = new TypeValue( { hexColor: colors.requestRemove, type: 'suggestion-add' }, - null, true ); - dictionaryData['suggestion-remove-dictionary'] = new TypeValueWrapper( + dictionaryData['suggestion-remove-dictionary'] = new TypeValue( { hexColor: colors.dictionaryRequestColor, type: 'suggestion-add' }, - null, true ); - dictionaryData['skipped'] = new TypeValueWrapper( + dictionaryData['skipped'] = new TypeValue( { hexColor: colors.notRedacted, type: 'skipped' }, - null, true ); - dictionaryData['default'] = new TypeValueWrapper( + dictionaryData['default'] = new TypeValue( { hexColor: colors.defaultColor, type: 'default' }, - null, true ); - dictionaryData['add'] = new TypeValueWrapper( + dictionaryData['add'] = new TypeValue( { hexColor: colors.requestAdd, type: 'add' }, - null, true ); - dictionaryData['analysis'] = new TypeValueWrapper( + + dictionaryData['analysis'] = new TypeValue( { hexColor: colors.analysisColor, type: 'analysis' }, - null, true ); - dictionaryData['pending-analysis'] = new TypeValueWrapper( + dictionaryData['pending-analysis'] = new TypeValue( { hexColor: colors.analysisColor, type: 'analysis' }, - null, true ); - dictionaryData['change-legal-basis'] = new TypeValueWrapper( + dictionaryData['change-legal-basis'] = new TypeValue( { hexColor: colors.analysisColor, type: 'analysis' }, - null, true ); - dictionaryData['hint'] = new TypeValueWrapper( + dictionaryData['hint'] = new TypeValue( { hexColor: '#fa98f7', type: 'hint', hint: true }, - null, true ); - dictionaryData['redaction'] = new TypeValueWrapper( + dictionaryData['redaction'] = new TypeValue( { hexColor: colors.previewColor, type: 'redaction' }, - null, true ); - dictionaryData['updated'] = new TypeValueWrapper( + dictionaryData['updated'] = new TypeValue( { hexColor: colors.updatedColor, type: 'updated' }, - null, true ); }) @@ -688,36 +657,35 @@ export class AppStateService { await this._userPreferenceService.saveLastOpenedFileForDossier(dossierId, fileId); } - private _getExistingFiles(dossierId: string): FileStatusWrapper[] { - const dossier = this.allDossiers.find(p => p.dossierId === dossierId); + private _getExistingFiles(dossierId: string): File[] { + const dossier = this.allDossiers.find(p => p.id === dossierId); return dossier?.files ?? []; } - private _processFiles(dossier: DossierWrapper, files: FileStatus[], emitEvents: boolean = true) { + private _processFiles(dossier: Dossier, iFiles: IFile[], emitEvents = true) { const oldFiles = [...dossier.files]; - const fileStatusChangedEvent = []; - const fileReanalysedEvent = []; + const fileChangedEvent: File[] = []; + const fileReanalysedEvent: File[] = []; - for (const file of files) { + for (const iFile of iFiles) { let found = false; - file.dossierTemplateId = dossier.dossierTemplateId; + iFile.dossierTemplateId = dossier.dossierTemplateId; for (const oldFile of oldFiles) { - if (oldFile.fileId === file.fileId) { + if (oldFile.fileId === iFile.fileId) { // emit when analysis count changed - const fileStatusWrapper = new FileStatusWrapper( - file, - this._userService.getNameForId(file.currentReviewer), - this.getFileAttributeConfig(file.dossierTemplateId) + const file = new File( + iFile, + this._userService.getNameForId(iFile.currentReviewer), + this.getFileAttributeConfig(iFile.dossierTemplateId) ); - fileStatusWrapper.lastOpened = - fileStatusWrapper.fileId === this._userPreferenceService.getLastOpenedFileForDossier(dossier.dossierId); - if (JSON.stringify(oldFile) !== JSON.stringify(fileStatusWrapper)) { - fileStatusChangedEvent.push(fileStatusWrapper); + file.lastOpened = file.fileId === this._userPreferenceService.getLastOpenedFileForDossier(dossier.id); + if (JSON.stringify(oldFile) !== JSON.stringify(file)) { + fileChangedEvent.push(file); } - if (oldFile.lastProcessed !== file.lastProcessed) { - fileReanalysedEvent.push(fileStatusWrapper); + if (oldFile.lastProcessed !== iFile.lastProcessed) { + fileReanalysedEvent.push(file); } found = true; break; @@ -725,51 +693,43 @@ export class AppStateService { } // emit for new file if (!found) { - const fsw = new FileStatusWrapper( - file, - this._userService.getNameForId(file.currentReviewer), - this.getFileAttributeConfig(file.dossierTemplateId) + const file = new File( + iFile, + this._userService.getNameForId(iFile.currentReviewer), + this.getFileAttributeConfig(iFile.dossierTemplateId) ); - fileStatusChangedEvent.push(fsw); + fileChangedEvent.push(file); } } - dossier.files = files.map( - file => - new FileStatusWrapper( - file, - this._userService.getNameForId(file.currentReviewer), - this.getFileAttributeConfig(file.dossierTemplateId) - ) + dossier.files = iFiles.map( + iFile => + new File(iFile, this._userService.getNameForId(iFile.currentReviewer), this.getFileAttributeConfig(iFile.dossierTemplateId)) ); this._computeStats(); if (emitEvents) { fileReanalysedEvent.forEach(file => this.fileReanalysed$.next(file)); - fileStatusChangedEvent.forEach(file => this.fileChanged$.next(file)); + fileChangedEvent.forEach(file => this.fileChanged$.next(file)); } - const lastOpenedFileId = this._userPreferenceService.getLastOpenedFileForDossier(dossier.dossierId); + const lastOpenedFileId = this._userPreferenceService.getLastOpenedFileForDossier(dossier.id); dossier.files.forEach(file => (file.lastOpened = file.fileId === lastOpenedFileId)); - return files; + return iFiles; } private _computeStats() { let totalAnalysedPages = 0; - let totalDocuments = 0; const totalPeople = new Set(); this.allDossiers.forEach(d => { - totalDocuments += d.files.length; d.memberIds?.forEach(m => totalPeople.add(m)); - d.totalNumberOfPages = d.files.reduce((acc, file) => acc + file.numberOfPages, 0); totalAnalysedPages += d.totalNumberOfPages; }); this._appState.totalPeople = totalPeople.size; this._appState.totalAnalysedPages = totalAnalysedPages; - this._appState.totalDocuments = totalDocuments; } } 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 new file mode 100644 index 000000000..28da877ca --- /dev/null +++ b/apps/red-ui/src/app/state/model/dossier-attribute-config.ts @@ -0,0 +1,22 @@ +import { DossierAttributeConfigType, IDossierAttributeConfig } from '@redaction/red-ui-http'; +import { IListable } from '@iqser/common-ui'; + +export class DossierAttributeConfig implements IDossierAttributeConfig, IListable { + readonly id: string; + readonly editable: boolean; + readonly label?: string; + readonly placeholder?: string; + readonly type?: DossierAttributeConfigType; + + constructor(dossierAttributeConfig: IDossierAttributeConfig) { + this.id = dossierAttributeConfig.id; + this.editable = !!dossierAttributeConfig.editable; + this.label = dossierAttributeConfig.label; + this.placeholder = dossierAttributeConfig.placeholder; + this.type = dossierAttributeConfig.type; + } + + get searchKey(): string { + return this.label; + } +} diff --git a/apps/red-ui/src/app/state/model/dossier.ts b/apps/red-ui/src/app/state/model/dossier.ts new file mode 100644 index 000000000..6e2ec7389 --- /dev/null +++ b/apps/red-ui/src/app/state/model/dossier.ts @@ -0,0 +1,110 @@ +import { File } from '@models/file/file'; +import { DossierStatus, DownloadFileType, IDictionary, IDossier, List } from '@redaction/red-ui-http'; +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 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 watermarkEnabled: boolean; + readonly hasReviewers: boolean; + + reanalysisRequired = this._files.some(file => file.analysisRequired); + hasFiles = this._files.length > 0; + filesLength = this._files.length; + + totalNumberOfPages?: number; + hintsOnly?: boolean; + hasRedactions?: boolean; + hasSuggestions?: boolean; + hasNone?: boolean; + hasPendingOrProcessing?: boolean; + + allFilesApproved?: boolean; + type?: IDictionary; + + constructor(dossier: IDossier, private _files: File[] = []) { + this.dossierId = dossier.dossierId; + this.approverIds = dossier.approverIds; + this.date = dossier.date; + this.description = dossier.description; + this.dossierName = dossier.dossierName; + this.dossierTemplateId = dossier.dossierTemplateId; + this.downloadFileTypes = dossier.downloadFileTypes; + this.dueDate = dossier.dueDate; + this.hardDeletedTime = dossier.hardDeletedTime; + this.memberIds = dossier.memberIds; + this.ownerId = dossier.ownerId; + this.reportTemplateIds = dossier.reportTemplateIds; + this.reportTypes = dossier.reportTypes; + this.softDeletedTime = dossier.softDeletedTime; + this.status = dossier.status; + this.watermarkEnabled = dossier.watermarkEnabled; + this.hasReviewers = this.memberIds.length > 1; + + this._recomputeFileStatus(); + } + + get id(): string { + return this.dossierId; + } + + get routerLink(): string { + return `/main/dossiers/${this.dossierId}`; + } + + get searchKey(): string { + 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); + } + + hasMember(memberId: string): boolean { + return 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; + 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/state/model/dossier.wrapper.ts b/apps/red-ui/src/app/state/model/dossier.wrapper.ts deleted file mode 100644 index b7cf48f4d..000000000 --- a/apps/red-ui/src/app/state/model/dossier.wrapper.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { FileStatusWrapper } from '@models/file/file-status.wrapper'; -import * as moment from 'moment'; -import { Dictionary, Dossier } from '@redaction/red-ui-http'; -import { Listable } from '@iqser/common-ui'; - -export class DossierWrapper implements Dossier, Listable { - readonly approverIds = this._dossier.approverIds; - readonly date = this._dossier.date; - readonly description = this._dossier.description; - readonly dossierId = this._dossier.dossierId; - readonly dossierName = this._dossier.dossierName; - readonly dossierTemplateId = this._dossier.dossierTemplateId; - readonly downloadFileTypes = this._dossier.downloadFileTypes; - readonly dueDate = this._dossier.dueDate; - readonly hardDeletedTime = this._dossier.hardDeletedTime; - readonly memberIds = this._dossier.memberIds; - readonly ownerId = this._dossier.ownerId; - readonly reportTemplateIds = this._dossier.reportTemplateIds; - readonly reportTypes = this._dossier.reportTypes; - readonly softDeletedTime = this._dossier.softDeletedTime; - readonly status = this._dossier.status; - readonly watermarkEnabled = this._dossier.watermarkEnabled; - - readonly hasMoreThanOneApprover = this.approverIds.length > 1; - readonly hasMoreThanOneReviewer = this.memberIds.length > 1; - readonly memberCount = this.memberIds.length; - - reanalysisRequired = this._files.some(file => file.analysisRequired); - hasFiles = this._files.length > 0; - filesLength = this._files.length; - - totalNumberOfPages?: number; - hintsOnly?: boolean; - hasRedactions?: boolean; - hasSuggestions?: boolean; - hasNone?: boolean; - hasPendingOrProcessing?: boolean; - - allFilesApproved?: boolean; - type?: Dictionary; - - constructor(private readonly _dossier: Dossier, readonly dossierTemplateName, private _files: FileStatusWrapper[] = []) { - this._recomputeFileStatus(); - } - - get id() { - return this.dossierId; - } - - get files() { - return this._files; - } - - set files(files: FileStatusWrapper[]) { - this._files = files ? files : []; - this._recomputeFileStatus(); - } - - hasStatus(status: string): boolean { - return !!this._files.find(f => f.status === status); - } - - hasMember(memberId: string) { - return this._dossier.memberIds.indexOf(memberId) >= 0; - } - - addedDateMatches(key: string) { - return moment(this.date).format('DD/MM/YYYY') === key; - } - - 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; - 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/translations/download-types-translations.ts b/apps/red-ui/src/app/translations/download-types-translations.ts index ba6bdf18d..043e96878 100644 --- a/apps/red-ui/src/app/translations/download-types-translations.ts +++ b/apps/red-ui/src/app/translations/download-types-translations.ts @@ -1,7 +1,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -import { Dossier } from '@redaction/red-ui-http'; +import { DownloadFileType } from '@redaction/red-ui-http'; -export const downloadTypesTranslations: { [key in Dossier.DownloadFileTypesEnum]: string } = { +export const downloadTypesTranslations: { [key in DownloadFileType]: string } = { ORIGINAL: _('download-type.original'), PREVIEW: _('download-type.preview'), REDACTED: _('download-type.redacted'), diff --git a/apps/red-ui/src/app/utils/file-drop-utils.ts b/apps/red-ui/src/app/utils/file-drop-utils.ts index a2a02e397..fb0d1efa1 100644 --- a/apps/red-ui/src/app/utils/file-drop-utils.ts +++ b/apps/red-ui/src/app/utils/file-drop-utils.ts @@ -1,7 +1,7 @@ import { FileUploadModel } from '@upload-download/model/file-upload.model'; -import { DossierWrapper } from '@state/model/dossier.wrapper'; +import { Dossier } from '@state/model/dossier'; -export function handleFileDrop(event: DragEvent, dossier: DossierWrapper, uploadFiles: (files: FileUploadModel[]) => void) { +export function handleFileDrop(event: DragEvent, dossier: Dossier, uploadFiles: (files: FileUploadModel[]) => void) { event.preventDefault(); event.stopPropagation(); const { dataTransfer } = event; @@ -30,7 +30,9 @@ export function isCsv(file: FileUploadModel): boolean { return file.file.type?.toLowerCase() === 'text/csv' || file.file.name.toLowerCase().endsWith('.csv'); } -export function convertFiles(files: FileList | File[], dossier: DossierWrapper): FileUploadModel[] { +export type Files = FileList | File[]; + +export function convertFiles(files: FileList | File[], dossier: Dossier): FileUploadModel[] { let uploadFiles: FileUploadModel[] = []; for (let i = 0; i < files.length; i++) { const file = files[i]; @@ -39,7 +41,7 @@ export function convertFiles(files: FileList | File[], dossier: DossierWrapper): progress: 0, completed: false, error: null, - dossierId: dossier.dossierId, + dossierId: dossier.id, dossierName: dossier.dossierName, sizeError: false, retryCount: 0, diff --git a/apps/red-ui/src/app/utils/filter-utils.ts b/apps/red-ui/src/app/utils/filter-utils.ts index e45b90362..2763afba0 100644 --- a/apps/red-ui/src/app/utils/filter-utils.ts +++ b/apps/red-ui/src/app/utils/filter-utils.ts @@ -1,38 +1,38 @@ -import { FileStatusWrapper } from '@models/file/file-status.wrapper'; -import { DossierWrapper } from '@state/model/dossier.wrapper'; -import { handleCheckedValue, NestedFilter } from '@iqser/common-ui'; +import { File } from '@models/file/file'; +import { Dossier } from '../state/model/dossier'; +import { handleCheckedValue, INestedFilter } from '@iqser/common-ui'; -export function handleFilterDelta(oldFilters: NestedFilter[], newFilters: NestedFilter[], allFilters: NestedFilter[]) { +export function handleFilterDelta(oldFilters: INestedFilter[], newFilters: INestedFilter[], allFilters: INestedFilter[]) { const newFiltersDelta = {}; for (const newFilter of newFilters) { - const oldFilter = oldFilters.find(f => f.key === newFilter.key); + const oldFilter = oldFilters.find(f => f.id === newFilter.id); if (!oldFilter || oldFilter.matches !== newFilter.matches) { - newFiltersDelta[newFilter.key] = {}; - newFilter.children.forEach(filter => (newFiltersDelta[newFilter.key][filter.key] = {})); + newFiltersDelta[newFilter.id] = {}; + newFilter.children.forEach(filter => (newFiltersDelta[newFilter.id][filter.id] = {})); } if (!oldFilter) { for (const childFilter of newFilter.children) { - const oldFilterChild = oldFilter?.children.find(f => f.key === childFilter.key); + const oldFilterChild = oldFilter?.children.find(f => f.id === childFilter.id); if (!oldFilterChild || oldFilterChild.matches !== childFilter.matches) { - if (!newFiltersDelta[newFilter.key]) { - newFiltersDelta[newFilter.key] = {}; + if (!newFiltersDelta[newFilter.id]) { + newFiltersDelta[newFilter.id] = {}; } - newFiltersDelta[newFilter.key][childFilter.key] = {}; + newFiltersDelta[newFilter.id][childFilter.id] = {}; } } } } for (const key of Object.keys(newFiltersDelta)) { - const foundFilter = allFilters.find(f => f.key === key); + const foundFilter = allFilters.find(f => f.id === key); if (foundFilter) { // if has children if (!foundFilter.children?.length) { foundFilter.checked = true; } else { for (const subKey of Object.keys(newFiltersDelta[key])) { - const childFilter = foundFilter.children.find(f => f.key === subKey); + const childFilter = foundFilter.children.find(f => f.id === subKey); if (childFilter) { childFilter.checked = true; } @@ -45,10 +45,10 @@ export function handleFilterDelta(oldFilters: NestedFilter[], newFilters: Nested }); } -export const annotationFilterChecker = (input: FileStatusWrapper | DossierWrapper, filter: NestedFilter) => { - switch (filter.key) { +export const annotationFilterChecker = (input: File | Dossier, filter: INestedFilter) => { + switch (filter.id) { case 'analysis': { - if (input instanceof DossierWrapper) { + if (input instanceof Dossier) { return input.reanalysisRequired; } else { return input.analysisRequired; @@ -67,21 +67,21 @@ export const annotationFilterChecker = (input: FileStatusWrapper | DossierWrappe return input.hasNone; } case 'updated': { - return input instanceof FileStatusWrapper && input.hasUpdates; + return input instanceof File && input.hasUpdates; } case 'image': { - return input instanceof FileStatusWrapper && input.hasImages; + return input instanceof File && input.hasImages; } case 'comment': { - return input instanceof FileStatusWrapper && input.hasAnnotationComments; + return input instanceof File && input.hasAnnotationComments; } } }; -export const dossierStatusChecker = (dw: DossierWrapper, filter: NestedFilter) => dw.hasStatus(filter.key); +export const dossierStatusChecker = (dw: Dossier, filter: INestedFilter) => dw.hasStatus(filter.id); -export const dossierMemberChecker = (dw: DossierWrapper, filter: NestedFilter) => dw.hasMember(filter.key); +export const dossierMemberChecker = (dw: Dossier, filter: INestedFilter) => dw.hasMember(filter.id); -export const dossierTemplateChecker = (dw: DossierWrapper, filter: NestedFilter) => dw.dossierTemplateId === filter.key; +export const dossierTemplateChecker = (dw: Dossier, filter: INestedFilter) => dw.dossierTemplateId === filter.id; -export const dossierApproverChecker = (dw: DossierWrapper, filter: NestedFilter) => dw.approverIds.includes(filter.key); +export const dossierApproverChecker = (dw: Dossier, filter: INestedFilter) => dw.approverIds.includes(filter.id); diff --git a/apps/red-ui/src/app/utils/sorters/redaction-filter-sorter.ts b/apps/red-ui/src/app/utils/sorters/redaction-filter-sorter.ts index 82e055c3b..90d07be73 100644 --- a/apps/red-ui/src/app/utils/sorters/redaction-filter-sorter.ts +++ b/apps/red-ui/src/app/utils/sorters/redaction-filter-sorter.ts @@ -6,5 +6,5 @@ export const RedactionFilterSorter = { hint: 4, suggestion: 5, none: 6, - byKey: (a: { key: string }, b: { key: string }) => RedactionFilterSorter[a.key] - RedactionFilterSorter[b.key] + byKey: (a: { id: string }, b: { id: string }) => RedactionFilterSorter[a.id] - RedactionFilterSorter[b.id] }; diff --git a/apps/red-ui/src/app/utils/types.d.ts b/apps/red-ui/src/app/utils/types.d.ts index 5b10a4181..acc52b81e 100644 --- a/apps/red-ui/src/app/utils/types.d.ts +++ b/apps/red-ui/src/app/utils/types.d.ts @@ -1,3 +1,3 @@ import { FileStatus } from '@redaction/red-ui-http'; -export type Color = FileStatus.StatusEnum | DossierStatus.StatusEnum; +export type Color = FileStatus | DossierStatus.StatusEnum; diff --git a/apps/red-ui/src/assets/config/config.json b/apps/red-ui/src/assets/config/config.json index 22b208d48..d1e68990c 100644 --- a/apps/red-ui/src/assets/config/config.json +++ b/apps/red-ui/src/assets/config/config.json @@ -1,7 +1,7 @@ { "ADMIN_CONTACT_NAME": null, "ADMIN_CONTACT_URL": null, - "API_URL": "https://demo.redactmanager.com/redaction-gateway-v1", + "API_URL": "https://red-staging.iqser.cloud/redaction-gateway-v1", "APP_NAME": "RedactManager", "AUTO_READ_TIME": 1.5, "BACKEND_APP_VERSION": "4.4.40", @@ -17,7 +17,7 @@ "MAX_RETRIES_ON_SERVER_ERROR": 3, "OAUTH_CLIENT_ID": "redaction", "OAUTH_IDP_HINT": null, - "OAUTH_URL": "https://demo.redactmanager.com/auth/realms/redaction", + "OAUTH_URL": "https://red-staging.iqser.cloud/auth/realms/redaction", "RECENT_PERIOD_IN_HOURS": 24, "SELECTION_MODE": "structural" } diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index 7c0e555b4..5da5171d4 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -694,6 +694,7 @@ }, "ocr-file": "OCR Document", "ocr-performed": "OCR was performed for this file.", + "open-document": "Open Document", "quick-filters": { "assigned-to-me": "Assigned to me", "assigned-to-others": "Assigned to others", @@ -1510,6 +1511,11 @@ "expand": "Show Details", "title": "Users" }, + "view-mode": { + "list": "List", + "view-as": "View as:", + "workflow": "Workflow" + }, "watermark": "Watermark", "watermark-screen": { "action": { diff --git a/apps/red-ui/src/assets/styles/_variables.scss b/apps/red-ui/src/assets/styles/_variables.scss index 9aeb20b26..be6a0f8ce 100644 --- a/apps/red-ui/src/assets/styles/_variables.scss +++ b/apps/red-ui/src/assets/styles/_variables.scss @@ -36,7 +36,6 @@ $dark: $black; $btn-bg-hover: $grey-4; $btn-bg: $grey-6; -$filter-bg: $grey-2; $quick-filter-border: $grey-5; $separator: rgba(226, 228, 233, 0.9); diff --git a/apps/red-ui/src/assets/styles/red-components.scss b/apps/red-ui/src/assets/styles/red-components.scss index b8f850889..df392fb85 100644 --- a/apps/red-ui/src/assets/styles/red-components.scss +++ b/apps/red-ui/src/assets/styles/red-components.scss @@ -81,6 +81,8 @@ mat-icon { width: 10px; + height: 10px; + line-height: 13px; margin-right: 6px; } diff --git a/apps/red-ui/src/assets/styles/red-page-layout.scss b/apps/red-ui/src/assets/styles/red-page-layout.scss index acf3e9d8e..d16387f6a 100644 --- a/apps/red-ui/src/assets/styles/red-page-layout.scss +++ b/apps/red-ui/src/assets/styles/red-page-layout.scss @@ -242,10 +242,18 @@ section.settings { margin-top: 32px; } +.mb-6 { + margin-bottom: 6px; +} + .mb-8 { margin-bottom: 8px !important; } +.mb-12 { + margin-bottom: 12px !important; +} + .ml-8 { margin-left: 8px; } diff --git a/apps/red-ui/src/styles.scss b/apps/red-ui/src/styles.scss index 1f8bbdd7e..17cb7360b 100644 --- a/apps/red-ui/src/styles.scss +++ b/apps/red-ui/src/styles.scss @@ -18,7 +18,11 @@ $iqser-white: vars.$white, $iqser-separator: vars.$separator, $iqser-quick-filter-border: vars.$quick-filter-border, - $iqser-filter-bg: vars.$filter-bg, + $iqser-grey-2: vars.$grey-2, + $iqser-grey-3: vars.$grey-3, + $iqser-grey-4: vars.$grey-4, + $iqser-grey-5: vars.$grey-5, + $iqser-grey-6: vars.$grey-6, $iqser-helpmode-primary: vars.$green-2 ); diff --git a/libs/common-ui b/libs/common-ui index ea82e4351..2835c812a 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit ea82e4351f217045e064ff10ee73ebbd190f330d +Subproject commit 2835c812a1141dd6dde67a70ec2736a9603a0bcd diff --git a/libs/red-ui-http/src/lib/api.module.ts b/libs/red-ui-http/src/lib/api.module.ts index 8962f8f4a..93f794458 100644 --- a/libs/red-ui-http/src/lib/api.module.ts +++ b/libs/red-ui-http/src/lib/api.module.ts @@ -3,10 +3,8 @@ import { Configuration } from './configuration'; import { HttpClient } from '@angular/common/http'; import { AuditControllerService } from './api/auditController.service'; -import { DictionaryControllerService } from './api/dictionaryController.service'; import { DigitalSignatureControllerService } from './api/digitalSignatureController.service'; import { DossierAttributesControllerService } from './api/dossierAttributesController.service'; -import { DossierControllerService } from './api/dossierController.service'; import { DossierTemplateControllerService } from './api/dossierTemplateController.service'; import { DownloadControllerService } from './api/downloadController.service'; import { FileAttributesControllerService } from './api/fileAttributesController.service'; @@ -21,7 +19,6 @@ import { RedactionLogControllerService } from './api/redactionLogController.serv import { ReportTemplateControllerService } from './api/reportTemplateController.service'; import { RulesControllerService } from './api/rulesController.service'; import { SmtpConfigurationControllerService } from './api/smtpConfigurationController.service'; -import { StatusControllerService } from './api/statusController.service'; import { UploadControllerService } from './api/uploadController.service'; import { UserControllerService } from './api/userController.service'; import { UserPreferenceControllerService } from './api/userPreferenceController.service'; @@ -37,10 +34,8 @@ import { NotificationControllerService } from './api/notificationController.serv exports: [], providers: [ AuditControllerService, - DictionaryControllerService, DigitalSignatureControllerService, DossierAttributesControllerService, - DossierControllerService, DossierTemplateControllerService, DownloadControllerService, FileAttributesControllerService, @@ -55,7 +50,6 @@ import { NotificationControllerService } from './api/notificationController.serv ReportTemplateControllerService, RulesControllerService, SmtpConfigurationControllerService, - StatusControllerService, UploadControllerService, UserControllerService, UserPreferenceControllerService, diff --git a/libs/red-ui-http/src/lib/api/api.ts b/libs/red-ui-http/src/lib/api/api.ts index 976be4cb9..3c6557617 100644 --- a/libs/red-ui-http/src/lib/api/api.ts +++ b/libs/red-ui-http/src/lib/api/api.ts @@ -1,17 +1,14 @@ import { AuditControllerService } from './auditController.service'; import { DebugControllerService } from './debugController.service'; -import { DictionaryControllerService } from './dictionaryController.service'; import { FileManagementControllerService } from './fileManagementController.service'; import { InfoControllerService } from './infoController.service'; import { LegalBasisMappingControllerService } from './legalBasisMappingController.service'; import { LicenseReportControllerService } from './licenseReportController.service'; import { ManualRedactionControllerService } from './manualRedactionController.service'; -import { DossierControllerService } from './dossierController.service'; import { ReanalysisControllerService } from './reanalysisController.service'; import { RedactionLogControllerService } from './redactionLogController.service'; import { DossierTemplateControllerService } from './dossierTemplateController.service'; import { RulesControllerService } from './rulesController.service'; -import { StatusControllerService } from './statusController.service'; import { UserControllerService } from './userController.service'; import { UserPreferenceControllerService } from './userPreferenceController.service'; import { VersionsControllerService } from './versionsController.service'; @@ -89,18 +86,15 @@ export * from './notificationController.service'; export const APIS = [ AuditControllerService, DebugControllerService, - DictionaryControllerService, FileManagementControllerService, InfoControllerService, LegalBasisMappingControllerService, LicenseReportControllerService, ManualRedactionControllerService, - DossierControllerService, ReanalysisControllerService, RedactionLogControllerService, DossierTemplateControllerService, RulesControllerService, - StatusControllerService, UserControllerService, UserPreferenceControllerService, VersionsControllerService, diff --git a/libs/red-ui-http/src/lib/api/dictionaryController.service.ts b/libs/red-ui-http/src/lib/api/dictionaryController.service.ts index ce77d7944..8c50fab00 100644 --- a/libs/red-ui-http/src/lib/api/dictionaryController.service.ts +++ b/libs/red-ui-http/src/lib/api/dictionaryController.service.ts @@ -10,20 +10,20 @@ * Do not edit the class manually. */ /* tslint:disable:no-unused-variable member-ordering */ -import { Inject, Injectable, Optional } from '@angular/core'; -import { HttpClient, HttpEvent, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http'; -import { CustomHttpUrlEncodingCodec } from '../encoder'; +import { Inject, Injectable, Optional } from "@angular/core"; +import { HttpClient, HttpEvent, HttpHeaders, HttpParams, HttpResponse } from "@angular/common/http"; +import { CustomHttpUrlEncodingCodec } from "../encoder"; -import { Observable } from 'rxjs'; +import { Observable } from "rxjs"; -import { Colors } from '../model/colors'; -import { Dictionary } from '../model/dictionary'; -import { TypeResponse } from '../model/typeResponse'; -import { TypeValue } from '../model/typeValue'; -import { UpdateTypeValue } from '../model/updateTypeValue'; +import { Colors } from "../model/colors"; +import { IDictionary } from "../model/dictionary"; +import { TypeResponse } from "../model/typeResponse"; +import { ITypeValue } from "../model/typeValue"; +import { UpdateTypeValue } from "../model/updateTypeValue"; -import { BASE_PATH } from '../variables'; -import { Configuration } from '../configuration'; +import { BASE_PATH } from "../variables"; +import { Configuration } from "../configuration"; @Injectable() export class DictionaryControllerService { @@ -160,13 +160,13 @@ export class DictionaryControllerService { * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param reportProgress flag to report request and response progress. */ - public addType(body: TypeValue, dossierId?: string, observe?: 'body', reportProgress?: boolean): Observable; + public addType(body: ITypeValue, dossierId?: string, observe?: 'body', reportProgress?: boolean): Observable; - public addType(body: TypeValue, dossierId?: string, observe?: 'response', reportProgress?: boolean): Observable>; + public addType(body: ITypeValue, dossierId?: string, observe?: 'response', reportProgress?: boolean): Observable>; - public addType(body: TypeValue, dossierId?: string, observe?: 'events', reportProgress?: boolean): Observable>; + public addType(body: ITypeValue, dossierId?: string, observe?: 'events', reportProgress?: boolean): Observable>; - public addType(body: TypeValue, dossierId?: string, observe: any = 'body', reportProgress: boolean = false): Observable { + public addType(body: ITypeValue, dossierId?: string, observe: any = 'body', reportProgress: boolean = false): Observable { if (body === null || body === undefined) { throw new Error('Required parameter body was null or undefined when calling addType.'); } @@ -780,7 +780,7 @@ export class DictionaryControllerService { dossierId?: string, observe?: 'body', reportProgress?: boolean - ): Observable; + ): Observable; public getDictionaryForType( dossierTemplateId: string, @@ -788,7 +788,7 @@ export class DictionaryControllerService { dossierId?: string, observe?: 'response', reportProgress?: boolean - ): Observable>; + ): Observable>; public getDictionaryForType( dossierTemplateId: string, @@ -796,7 +796,7 @@ export class DictionaryControllerService { dossierId?: string, observe?: 'events', reportProgress?: boolean - ): Observable>; + ): Observable>; public getDictionaryForType( dossierTemplateId: string, @@ -834,7 +834,7 @@ export class DictionaryControllerService { headers = headers.set('Accept', httpHeaderAcceptSelected); } - return this.httpClient.request( + return this.httpClient.request( 'get', `${this.basePath}/dictionary/${encodeURIComponent(String(type))}/${encodeURIComponent(String(dossierTemplateId))}`, { diff --git a/libs/red-ui-http/src/lib/api/dossierAttributesController.service.ts b/libs/red-ui-http/src/lib/api/dossierAttributesController.service.ts index cfa08f4b4..9e809d6c6 100644 --- a/libs/red-ui-http/src/lib/api/dossierAttributesController.service.ts +++ b/libs/red-ui-http/src/lib/api/dossierAttributesController.service.ts @@ -10,20 +10,20 @@ * Do not edit the class manually. */ /* tslint:disable:no-unused-variable member-ordering */ -import { Inject, Injectable, Optional } from '@angular/core'; -import { HttpClient, HttpEvent, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http'; +import { Inject, Injectable, Optional } from "@angular/core"; +import { HttpClient, HttpEvent, HttpHeaders, HttpParams, HttpResponse } from "@angular/common/http"; -import { Observable } from 'rxjs'; +import { Observable } from "rxjs"; -import { DossierAttributeConfig } from '../model/dossierAttributeConfig'; -import { DossierAttributeReq } from '../model/dossierAttributeReq'; -import { DossierAttributesConfig } from '../model/dossierAttributesConfig'; -import { DossierAttributesReq } from '../model/dossierAttributesReq'; -import { DossierAttributesRes } from '../model/dossierAttributesRes'; +import { IDossierAttributeConfig } from "../model/dossierAttributeConfig"; +import { DossierAttributeReq } from "../model/dossierAttributeReq"; +import { DossierAttributesConfig } from "../model/dossierAttributesConfig"; +import { DossierAttributesReq } from "../model/dossierAttributesReq"; +import { DossierAttributesRes } from "../model/dossierAttributesRes"; -import { BASE_PATH } from '../variables'; -import { Configuration } from '../configuration'; -import { CustomHttpUrlEncodingCodec } from '../encoder'; +import { BASE_PATH } from "../variables"; +import { Configuration } from "../configuration"; +import { CustomHttpUrlEncodingCodec } from "../encoder"; @Injectable() export class DossierAttributesControllerService { @@ -133,28 +133,28 @@ export class DossierAttributesControllerService { * @param reportProgress flag to report request and response progress. */ public addOrUpdateDossierAttributesConfig( - body: DossierAttributeConfig, + body: IDossierAttributeConfig, dossierTemplateId: string, observe?: 'body', reportProgress?: boolean - ): Observable; + ): Observable; public addOrUpdateDossierAttributesConfig( - body: DossierAttributeConfig, + body: IDossierAttributeConfig, dossierTemplateId: string, observe?: 'response', reportProgress?: boolean - ): Observable>; + ): Observable>; public addOrUpdateDossierAttributesConfig( - body: DossierAttributeConfig, + body: IDossierAttributeConfig, dossierTemplateId: string, observe?: 'events', reportProgress?: boolean - ): Observable>; + ): Observable>; public addOrUpdateDossierAttributesConfig( - body: DossierAttributeConfig, + body: IDossierAttributeConfig, dossierTemplateId: string, observe: any = 'body', reportProgress: boolean = false @@ -190,7 +190,7 @@ export class DossierAttributesControllerService { headers = headers.set('Content-Type', httpContentTypeSelected); } - return this.httpClient.request( + return this.httpClient.request( 'post', `${this.basePath}/dossier-attributes/config/${encodeURIComponent(String(dossierTemplateId))}`, { diff --git a/libs/red-ui-http/src/lib/api/dossierController.service.ts b/libs/red-ui-http/src/lib/api/dossierController.service.ts index 8995f46de..858653fd6 100644 --- a/libs/red-ui-http/src/lib/api/dossierController.service.ts +++ b/libs/red-ui-http/src/lib/api/dossierController.service.ts @@ -16,7 +16,7 @@ import { CustomHttpUrlEncodingCodec } from '../encoder'; import { Observable } from 'rxjs'; -import { Dossier } from '../model/dossier'; +import { IDossier } from '../model/dossier'; import { DossierRequest } from '../model/dossierRequest'; import { BASE_PATH } from '../variables'; @@ -49,11 +49,11 @@ export class DossierControllerService { * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param reportProgress flag to report request and response progress. */ - public createOrUpdateDossier(body: DossierRequest, observe?: 'body', reportProgress?: boolean): Observable; + public createOrUpdateDossier(body: DossierRequest, observe?: 'body', reportProgress?: boolean): Observable; - public createOrUpdateDossier(body: DossierRequest, observe?: 'response', reportProgress?: boolean): Observable>; + public createOrUpdateDossier(body: DossierRequest, observe?: 'response', reportProgress?: boolean): Observable>; - public createOrUpdateDossier(body: DossierRequest, observe?: 'events', reportProgress?: boolean): Observable>; + public createOrUpdateDossier(body: DossierRequest, observe?: 'events', reportProgress?: boolean): Observable>; public createOrUpdateDossier(body: DossierRequest, observe: any = 'body', reportProgress: boolean = false): Observable { if (body === null || body === undefined) { @@ -83,7 +83,7 @@ export class DossierControllerService { headers = headers.set('Content-Type', httpContentTypeSelected); } - return this.httpClient.request('post', `${this.basePath}/dossier`, { + return this.httpClient.request('post', `${this.basePath}/dossier`, { body: body, withCredentials: this.configuration.withCredentials, headers: headers, @@ -140,11 +140,11 @@ export class DossierControllerService { * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param reportProgress flag to report request and response progress. */ - public getDeletedDossiers(observe?: 'body', reportProgress?: boolean): Observable>; + public getDeletedDossiers(observe?: 'body', reportProgress?: boolean): Observable>; - public getDeletedDossiers(observe?: 'response', reportProgress?: boolean): Observable>>; + public getDeletedDossiers(observe?: 'response', reportProgress?: boolean): Observable>>; - public getDeletedDossiers(observe?: 'events', reportProgress?: boolean): Observable>>; + public getDeletedDossiers(observe?: 'events', reportProgress?: boolean): Observable>>; public getDeletedDossiers(observe: any = 'body', reportProgress: boolean = false): Observable { let headers = this.defaultHeaders; @@ -163,7 +163,7 @@ export class DossierControllerService { headers = headers.set('Accept', httpHeaderAcceptSelected); } - return this.httpClient.request>('get', `${this.basePath}/deleted-dossiers`, { + return this.httpClient.request>('get', `${this.basePath}/deleted-dossiers`, { withCredentials: this.configuration.withCredentials, headers: headers, observe: observe, @@ -178,11 +178,11 @@ export class DossierControllerService { * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param reportProgress flag to report request and response progress. */ - public getDossier(dossierId: string, observe?: 'body', reportProgress?: boolean): Observable; + public getDossier(dossierId: string, observe?: 'body', reportProgress?: boolean): Observable; - public getDossier(dossierId: string, observe?: 'response', reportProgress?: boolean): Observable>; + public getDossier(dossierId: string, observe?: 'response', reportProgress?: boolean): Observable>; - public getDossier(dossierId: string, observe?: 'events', reportProgress?: boolean): Observable>; + public getDossier(dossierId: string, observe?: 'events', reportProgress?: boolean): Observable>; public getDossier(dossierId: string, observe: any = 'body', reportProgress: boolean = false): Observable { if (dossierId === null || dossierId === undefined) { @@ -205,7 +205,7 @@ export class DossierControllerService { headers = headers.set('Accept', httpHeaderAcceptSelected); } - return this.httpClient.request('get', `${this.basePath}/dossier/${encodeURIComponent(String(dossierId))}`, { + return this.httpClient.request('get', `${this.basePath}/dossier/${encodeURIComponent(String(dossierId))}`, { withCredentials: this.configuration.withCredentials, headers: headers, observe: observe, @@ -219,11 +219,11 @@ export class DossierControllerService { * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param reportProgress flag to report request and response progress. */ - public getDossiers(observe?: 'body', reportProgress?: boolean): Observable>; + public getDossiers(observe?: 'body', reportProgress?: boolean): Observable>; - public getDossiers(observe?: 'response', reportProgress?: boolean): Observable>>; + public getDossiers(observe?: 'response', reportProgress?: boolean): Observable>>; - public getDossiers(observe?: 'events', reportProgress?: boolean): Observable>>; + public getDossiers(observe?: 'events', reportProgress?: boolean): Observable>>; public getDossiers(observe: any = 'body', reportProgress: boolean = false): Observable { let headers = this.defaultHeaders; @@ -242,7 +242,7 @@ export class DossierControllerService { headers = headers.set('Accept', httpHeaderAcceptSelected); } - return this.httpClient.request>('get', `${this.basePath}/dossier`, { + return this.httpClient.request>('get', `${this.basePath}/dossier`, { withCredentials: this.configuration.withCredentials, headers: headers, observe: observe, diff --git a/libs/red-ui-http/src/lib/api/dossierTemplateController.service.ts b/libs/red-ui-http/src/lib/api/dossierTemplateController.service.ts index 6276e3e9f..6a8f20a86 100644 --- a/libs/red-ui-http/src/lib/api/dossierTemplateController.service.ts +++ b/libs/red-ui-http/src/lib/api/dossierTemplateController.service.ts @@ -10,15 +10,15 @@ * Do not edit the class manually. */ /* tslint:disable:no-unused-variable member-ordering */ -import { Inject, Injectable, Optional } from '@angular/core'; -import { HttpClient, HttpEvent, HttpHeaders, HttpResponse } from '@angular/common/http'; +import { Inject, Injectable, Optional } from "@angular/core"; +import { HttpClient, HttpEvent, HttpHeaders, HttpResponse } from "@angular/common/http"; -import { Observable } from 'rxjs'; +import { Observable } from "rxjs"; -import { DossierTemplateModel } from '../model/dossierTemplateModel'; +import { IDossierTemplate } from "../model/dossierTemplate"; -import { BASE_PATH } from '../variables'; -import { Configuration } from '../configuration'; +import { BASE_PATH } from "../variables"; +import { Configuration } from "../configuration"; @Injectable() export class DossierTemplateControllerService { @@ -47,29 +47,21 @@ export class DossierTemplateControllerService { * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param reportProgress flag to report request and response progress. */ - public createOrUpdateDossierTemplate( - body: DossierTemplateModel, - observe?: 'body', - reportProgress?: boolean - ): Observable; + public createOrUpdateDossierTemplate(body: IDossierTemplate, observe?: 'body', reportProgress?: boolean): Observable; public createOrUpdateDossierTemplate( - body: DossierTemplateModel, + body: IDossierTemplate, observe?: 'response', reportProgress?: boolean - ): Observable>; + ): Observable>; public createOrUpdateDossierTemplate( - body: DossierTemplateModel, + body: IDossierTemplate, observe?: 'events', reportProgress?: boolean - ): Observable>; + ): Observable>; - public createOrUpdateDossierTemplate( - body: DossierTemplateModel, - observe: any = 'body', - reportProgress: boolean = false - ): Observable { + public createOrUpdateDossierTemplate(body: IDossierTemplate, observe: any = 'body', reportProgress: boolean = false): Observable { if (body === null || body === undefined) { throw new Error('Required parameter body was null or undefined when calling createOrUpdateDossierTemplate.'); } @@ -97,7 +89,7 @@ export class DossierTemplateControllerService { headers = headers.set('Content-Type', httpContentTypeSelected); } - return this.httpClient.request('post', `${this.basePath}/dossier-template`, { + return this.httpClient.request('post', `${this.basePath}/dossier-template`, { body: body, withCredentials: this.configuration.withCredentials, headers: headers, @@ -205,11 +197,11 @@ export class DossierTemplateControllerService { * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param reportProgress flag to report request and response progress. */ - public getAllDossierTemplates(observe?: 'body', reportProgress?: boolean): Observable>; + public getAllDossierTemplates(observe?: 'body', reportProgress?: boolean): Observable>; - public getAllDossierTemplates(observe?: 'response', reportProgress?: boolean): Observable>>; + public getAllDossierTemplates(observe?: 'response', reportProgress?: boolean): Observable>>; - public getAllDossierTemplates(observe?: 'events', reportProgress?: boolean): Observable>>; + public getAllDossierTemplates(observe?: 'events', reportProgress?: boolean): Observable>>; public getAllDossierTemplates(observe: any = 'body', reportProgress: boolean = false): Observable { let headers = this.defaultHeaders; @@ -228,7 +220,7 @@ export class DossierTemplateControllerService { headers = headers.set('Accept', httpHeaderAcceptSelected); } - return this.httpClient.request>('get', `${this.basePath}/dossier-template`, { + return this.httpClient.request>('get', `${this.basePath}/dossier-template`, { withCredentials: this.configuration.withCredentials, headers: headers, observe: observe, @@ -243,19 +235,19 @@ export class DossierTemplateControllerService { * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param reportProgress flag to report request and response progress. */ - public getDossierTemplate(dossierTemplateId: string, observe?: 'body', reportProgress?: boolean): Observable; + public getDossierTemplate(dossierTemplateId: string, observe?: 'body', reportProgress?: boolean): Observable; public getDossierTemplate( dossierTemplateId: string, observe?: 'response', reportProgress?: boolean - ): Observable>; + ): Observable>; public getDossierTemplate( dossierTemplateId: string, observe?: 'events', reportProgress?: boolean - ): Observable>; + ): Observable>; public getDossierTemplate(dossierTemplateId: string, observe: any = 'body', reportProgress: boolean = false): Observable { if (dossierTemplateId === null || dossierTemplateId === undefined) { @@ -278,7 +270,7 @@ export class DossierTemplateControllerService { headers = headers.set('Accept', httpHeaderAcceptSelected); } - return this.httpClient.request( + return this.httpClient.request( 'get', `${this.basePath}/dossier-template/${encodeURIComponent(String(dossierTemplateId))}`, { diff --git a/libs/red-ui-http/src/lib/api/fileAttributesController.service.ts b/libs/red-ui-http/src/lib/api/fileAttributesController.service.ts index 689b985f9..a7b368f18 100644 --- a/libs/red-ui-http/src/lib/api/fileAttributesController.service.ts +++ b/libs/red-ui-http/src/lib/api/fileAttributesController.service.ts @@ -10,17 +10,17 @@ * Do not edit the class manually. */ /* tslint:disable:no-unused-variable member-ordering */ -import { Inject, Injectable, Optional } from '@angular/core'; -import { HttpClient, HttpEvent, HttpHeaders, HttpResponse } from '@angular/common/http'; +import { Inject, Injectable, Optional } from "@angular/core"; +import { HttpClient, HttpEvent, HttpHeaders, HttpResponse } from "@angular/common/http"; -import { Observable } from 'rxjs'; +import { Observable } from "rxjs"; -import { FileAttributeConfig } from '../model/fileAttributeConfig'; -import { FileAttributes } from '../model/fileAttributes'; -import { FileAttributesConfig } from '../model/fileAttributesConfig'; +import { IFileAttributeConfig } from "../model/fileAttributeConfig"; +import { FileAttributes } from "../model/fileAttributes"; +import { FileAttributesConfig } from "../model/fileAttributesConfig"; -import { BASE_PATH } from '../variables'; -import { Configuration } from '../configuration'; +import { BASE_PATH } from "../variables"; +import { Configuration } from "../configuration"; @Injectable() export class FileAttributesControllerService { @@ -432,28 +432,28 @@ export class FileAttributesControllerService { * @param reportProgress flag to report request and response progress. */ public setFileAttributesConfiguration( - body: FileAttributeConfig, + body: IFileAttributeConfig, dossierTemplateId: string, observe?: 'body', reportProgress?: boolean - ): Observable; + ): Observable; public setFileAttributesConfiguration( - body: FileAttributeConfig, + body: IFileAttributeConfig, dossierTemplateId: string, observe?: 'response', reportProgress?: boolean - ): Observable>; + ): Observable>; public setFileAttributesConfiguration( - body: FileAttributeConfig, + body: IFileAttributeConfig, dossierTemplateId: string, observe?: 'events', reportProgress?: boolean - ): Observable>; + ): Observable>; public setFileAttributesConfiguration( - body: FileAttributeConfig, + body: IFileAttributeConfig, dossierTemplateId: string, observe: any = 'body', reportProgress: boolean = false @@ -489,7 +489,7 @@ export class FileAttributesControllerService { headers = headers.set('Content-Type', httpContentTypeSelected); } - return this.httpClient.request( + return this.httpClient.request( 'post', `${this.basePath}/fileAttributes/config/fileAttribute/${encodeURIComponent(String(dossierTemplateId))}`, { diff --git a/libs/red-ui-http/src/lib/api/statusController.service.ts b/libs/red-ui-http/src/lib/api/statusController.service.ts index 8597d3038..d7afabc56 100644 --- a/libs/red-ui-http/src/lib/api/statusController.service.ts +++ b/libs/red-ui-http/src/lib/api/statusController.service.ts @@ -10,16 +10,16 @@ * Do not edit the class manually. */ /* tslint:disable:no-unused-variable member-ordering */ -import { Inject, Injectable, Optional } from '@angular/core'; -import { HttpClient, HttpEvent, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http'; -import { CustomHttpUrlEncodingCodec } from '../encoder'; +import { Inject, Injectable, Optional } from "@angular/core"; +import { HttpClient, HttpEvent, HttpHeaders, HttpParams, HttpResponse } from "@angular/common/http"; +import { CustomHttpUrlEncodingCodec } from "../encoder"; -import { Observable } from 'rxjs'; +import { Observable } from "rxjs"; -import { FileStatus } from '../model/fileStatus'; +import { IFile } from "../model/file"; -import { BASE_PATH } from '../variables'; -import { Configuration } from '../configuration'; +import { BASE_PATH } from "../variables"; +import { Configuration } from "../configuration"; @Injectable() export class StatusControllerService { @@ -48,13 +48,9 @@ export class StatusControllerService { * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param reportProgress flag to report request and response progress. */ - public getDeletedFileStatus(dossierId: string, observe?: 'body', reportProgress?: boolean): Observable>; - public getDeletedFileStatus( - dossierId: string, - observe?: 'response', - reportProgress?: boolean - ): Observable>>; - public getDeletedFileStatus(dossierId: string, observe?: 'events', reportProgress?: boolean): Observable>>; + public getDeletedFileStatus(dossierId: string, observe?: 'body', reportProgress?: boolean): Observable>; + public getDeletedFileStatus(dossierId: string, observe?: 'response', reportProgress?: boolean): Observable>>; + public getDeletedFileStatus(dossierId: string, observe?: 'events', reportProgress?: boolean): Observable>>; public getDeletedFileStatus(dossierId: string, observe: any = 'body', reportProgress: boolean = false): Observable { if (dossierId === null || dossierId === undefined) { throw new Error('Required parameter dossierId was null or undefined when calling getDeletedFileStatus.'); @@ -76,7 +72,7 @@ export class StatusControllerService { headers = headers.set('Accept', httpHeaderAcceptSelected); } - return this.httpClient.request>( + return this.httpClient.request>( 'get', `${this.basePath}/status/softdeleted/${encodeURIComponent(String(dossierId))}`, { @@ -95,11 +91,11 @@ export class StatusControllerService { * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param reportProgress flag to report request and response progress. */ - public getDossierStatus(dossierId: string, observe?: 'body', reportProgress?: boolean): Observable>; + public getDossierStatus(dossierId: string, observe?: 'body', reportProgress?: boolean): Observable>; - public getDossierStatus(dossierId: string, observe?: 'response', reportProgress?: boolean): Observable>>; + public getDossierStatus(dossierId: string, observe?: 'response', reportProgress?: boolean): Observable>>; - public getDossierStatus(dossierId: string, observe?: 'events', reportProgress?: boolean): Observable>>; + public getDossierStatus(dossierId: string, observe?: 'events', reportProgress?: boolean): Observable>>; public getDossierStatus(dossierId: string, observe: any = 'body', reportProgress: boolean = false): Observable { if (dossierId === null || dossierId === undefined) { @@ -122,7 +118,7 @@ export class StatusControllerService { headers = headers.set('Accept', httpHeaderAcceptSelected); } - return this.httpClient.request>('get', `${this.basePath}/status/${encodeURIComponent(String(dossierId))}`, { + return this.httpClient.request>('get', `${this.basePath}/status/${encodeURIComponent(String(dossierId))}`, { withCredentials: this.configuration.withCredentials, headers: headers, observe: observe, @@ -138,21 +134,16 @@ export class StatusControllerService { * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param reportProgress flag to report request and response progress. */ - public getFileStatus(dossierId: string, fileId: string, observe?: 'body', reportProgress?: boolean): Observable; + public getFileStatus(dossierId: string, fileId: string, observe?: 'body', reportProgress?: boolean): Observable; public getFileStatus( dossierId: string, fileId: string, observe?: 'response', reportProgress?: boolean - ): Observable>; + ): Observable>; - public getFileStatus( - dossierId: string, - fileId: string, - observe?: 'events', - reportProgress?: boolean - ): Observable>; + public getFileStatus(dossierId: string, fileId: string, observe?: 'events', reportProgress?: boolean): Observable>; public getFileStatus(dossierId: string, fileId: string, observe: any = 'body', reportProgress: boolean = false): Observable { if (dossierId === null || dossierId === undefined) { @@ -179,7 +170,7 @@ export class StatusControllerService { headers = headers.set('Accept', httpHeaderAcceptSelected); } - return this.httpClient.request( + return this.httpClient.request( 'get', `${this.basePath}/status/${encodeURIComponent(String(dossierId))}/${encodeURIComponent(String(fileId))}`, { @@ -202,19 +193,19 @@ export class StatusControllerService { body: Array, observe?: 'body', reportProgress?: boolean - ): Observable<{ [key: string]: Array }>; + ): Observable<{ [key: string]: Array }>; public getFileStatusForDossiers( body: Array, observe?: 'response', reportProgress?: boolean - ): Observable }>>; + ): Observable }>>; public getFileStatusForDossiers( body: Array, observe?: 'events', reportProgress?: boolean - ): Observable }>>; + ): Observable }>>; public getFileStatusForDossiers(body: Array, observe: any = 'body', reportProgress: boolean = false): Observable { if (body === null || body === undefined) { @@ -244,7 +235,7 @@ export class StatusControllerService { headers = headers.set('Content-Type', httpContentTypeSelected); } - return this.httpClient.request<{ [key: string]: Array }>('post', `${this.basePath}/status`, { + return this.httpClient.request<{ [key: string]: Array }>('post', `${this.basePath}/status`, { body: body, withCredentials: this.configuration.withCredentials, headers: headers, diff --git a/libs/red-ui-http/src/lib/api/userController.service.ts b/libs/red-ui-http/src/lib/api/userController.service.ts index f7be77a31..1fbce4576 100644 --- a/libs/red-ui-http/src/lib/api/userController.service.ts +++ b/libs/red-ui-http/src/lib/api/userController.service.ts @@ -10,20 +10,20 @@ * Do not edit the class manually. */ /* tslint:disable:no-unused-variable member-ordering */ -import { Inject, Injectable, Optional } from '@angular/core'; -import { HttpClient, HttpEvent, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http'; -import { CustomHttpUrlEncodingCodec } from '../encoder'; +import { Inject, Injectable, Optional } from "@angular/core"; +import { HttpClient, HttpEvent, HttpHeaders, HttpParams, HttpResponse } from "@angular/common/http"; +import { CustomHttpUrlEncodingCodec } from "../encoder"; -import { Observable } from 'rxjs'; +import { Observable } from "rxjs"; -import { CreateUserRequest } from '../model/createUserRequest'; -import { ResetPasswordRequest } from '../model/resetPasswordRequest'; -import { UpdateMyProfileRequest } from '../model/updateMyProfileRequest'; -import { UpdateProfileRequest } from '../model/updateProfileRequest'; -import { User } from '../model/user'; +import { CreateUserRequest } from "../model/createUserRequest"; +import { ResetPasswordRequest } from "../model/resetPasswordRequest"; +import { UpdateMyProfileRequest } from "../model/updateMyProfileRequest"; +import { UpdateProfileRequest } from "../model/updateProfileRequest"; +import { IUser } from "../model/user"; -import { BASE_PATH } from '../variables'; -import { Configuration } from '../configuration'; +import { BASE_PATH } from "../variables"; +import { Configuration } from "../configuration"; @Injectable() export class UserControllerService { @@ -112,11 +112,11 @@ export class UserControllerService { * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param reportProgress flag to report request and response progress. */ - public createUser(body: CreateUserRequest, observe?: 'body', reportProgress?: boolean): Observable; + public createUser(body: CreateUserRequest, observe?: 'body', reportProgress?: boolean): Observable; - public createUser(body: CreateUserRequest, observe?: 'response', reportProgress?: boolean): Observable>; + public createUser(body: CreateUserRequest, observe?: 'response', reportProgress?: boolean): Observable>; - public createUser(body: CreateUserRequest, observe?: 'events', reportProgress?: boolean): Observable>; + public createUser(body: CreateUserRequest, observe?: 'events', reportProgress?: boolean): Observable>; public createUser(body: CreateUserRequest, observe: any = 'body', reportProgress: boolean = false): Observable { if (body === null || body === undefined) { @@ -146,7 +146,7 @@ export class UserControllerService { headers = headers.set('Content-Type', httpContentTypeSelected); } - return this.httpClient.request('post', `${this.basePath}/user`, { + return this.httpClient.request('post', `${this.basePath}/user`, { body: body, withCredentials: this.configuration.withCredentials, headers: headers, @@ -254,11 +254,11 @@ export class UserControllerService { * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param reportProgress flag to report request and response progress. */ - public getAllUsers(refreshCache?: boolean, observe?: 'body', reportProgress?: boolean): Observable>; + public getAllUsers(refreshCache?: boolean, observe?: 'body', reportProgress?: boolean): Observable>; - public getAllUsers(refreshCache?: boolean, observe?: 'response', reportProgress?: boolean): Observable>>; + public getAllUsers(refreshCache?: boolean, observe?: 'response', reportProgress?: boolean): Observable>>; - public getAllUsers(refreshCache?: boolean, observe?: 'events', reportProgress?: boolean): Observable>>; + public getAllUsers(refreshCache?: boolean, observe?: 'events', reportProgress?: boolean): Observable>>; public getAllUsers(refreshCache?: boolean, observe: any = 'body', reportProgress: boolean = false): Observable { let queryParameters = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); @@ -282,7 +282,7 @@ export class UserControllerService { headers = headers.set('Accept', httpHeaderAcceptSelected); } - return this.httpClient.request>('get', `${this.basePath}/user`, { + return this.httpClient.request>('get', `${this.basePath}/user`, { params: queryParameters, withCredentials: this.configuration.withCredentials, headers: headers, @@ -298,11 +298,11 @@ export class UserControllerService { * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param reportProgress flag to report request and response progress. */ - public getUserById(userId: string, observe?: 'body', reportProgress?: boolean): Observable; + public getUserById(userId: string, observe?: 'body', reportProgress?: boolean): Observable; - public getUserById(userId: string, observe?: 'response', reportProgress?: boolean): Observable>; + public getUserById(userId: string, observe?: 'response', reportProgress?: boolean): Observable>; - public getUserById(userId: string, observe?: 'events', reportProgress?: boolean): Observable>; + public getUserById(userId: string, observe?: 'events', reportProgress?: boolean): Observable>; public getUserById(userId: string, observe: any = 'body', reportProgress: boolean = false): Observable { if (userId === null || userId === undefined) { @@ -325,7 +325,7 @@ export class UserControllerService { headers = headers.set('Accept', httpHeaderAcceptSelected); } - return this.httpClient.request('get', `${this.basePath}/user/${encodeURIComponent(String(userId))}`, { + return this.httpClient.request('get', `${this.basePath}/user/${encodeURIComponent(String(userId))}`, { withCredentials: this.configuration.withCredentials, headers: headers, observe: observe, @@ -340,11 +340,11 @@ export class UserControllerService { * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param reportProgress flag to report request and response progress. */ - public getUsers(refreshCache?: boolean, observe?: 'body', reportProgress?: boolean): Observable>; + public getUsers(refreshCache?: boolean, observe?: 'body', reportProgress?: boolean): Observable>; - public getUsers(refreshCache?: boolean, observe?: 'response', reportProgress?: boolean): Observable>>; + public getUsers(refreshCache?: boolean, observe?: 'response', reportProgress?: boolean): Observable>>; - public getUsers(refreshCache?: boolean, observe?: 'events', reportProgress?: boolean): Observable>>; + public getUsers(refreshCache?: boolean, observe?: 'events', reportProgress?: boolean): Observable>>; public getUsers(refreshCache?: boolean, observe: any = 'body', reportProgress: boolean = false): Observable { let queryParameters = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); @@ -368,7 +368,7 @@ export class UserControllerService { headers = headers.set('Accept', httpHeaderAcceptSelected); } - return this.httpClient.request>('get', `${this.basePath}/user/red`, { + return this.httpClient.request>('get', `${this.basePath}/user/red`, { params: queryParameters, withCredentials: this.configuration.withCredentials, headers: headers, diff --git a/libs/red-ui-http/src/lib/configuration.ts b/libs/red-ui-http/src/lib/configuration.ts index ff7fb826b..211acc151 100644 --- a/libs/red-ui-http/src/lib/configuration.ts +++ b/libs/red-ui-http/src/lib/configuration.ts @@ -1,27 +1,27 @@ export interface ConfigurationParameters { - apiKeys?: { [key: string]: string }; - username?: string; - password?: string; - accessToken?: string | (() => string); - basePath?: string; - withCredentials?: boolean; + readonly apiKeys?: { [key: string]: string }; + readonly username?: string; + readonly password?: string; + readonly accessToken?: string | (() => string); + readonly basePath?: string; + readonly withCredentials?: boolean; } -export class Configuration { - apiKeys?: { [key: string]: string }; - username?: string; - password?: string; - accessToken?: string | (() => string); - basePath?: string; - withCredentials?: boolean; +export class Configuration implements ConfigurationParameters { + readonly apiKeys?: { [key: string]: string }; + readonly username?: string; + readonly password?: string; + readonly accessToken?: string | (() => string); + readonly basePath: string; + readonly withCredentials: boolean; constructor(configurationParameters: ConfigurationParameters = {}) { this.apiKeys = configurationParameters.apiKeys; this.username = configurationParameters.username; this.password = configurationParameters.password; this.accessToken = configurationParameters.accessToken; - this.basePath = configurationParameters.basePath; - this.withCredentials = configurationParameters.withCredentials; + this.basePath = configurationParameters.basePath ?? ''; + this.withCredentials = !!configurationParameters.withCredentials; } /** @@ -73,7 +73,7 @@ export class Configuration { * @return True if the given MIME is JSON, false otherwise. */ public isJsonMime(mime: string): boolean { - const jsonMime: RegExp = new RegExp('^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); + const jsonMime = new RegExp('^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); return mime !== null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); } } diff --git a/libs/red-ui-http/src/lib/index.ts b/libs/red-ui-http/src/lib/index.ts index 410623f1c..9e8b8971c 100644 --- a/libs/red-ui-http/src/lib/index.ts +++ b/libs/red-ui-http/src/lib/index.ts @@ -3,3 +3,4 @@ export * from './model/models'; export * from './variables'; export * from './configuration'; export * from './api.module'; +export * from './red-types'; diff --git a/libs/red-ui-http/src/lib/model/auditModel.ts b/libs/red-ui-http/src/lib/model/audit.ts similarity index 53% rename from libs/red-ui-http/src/lib/model/auditModel.ts rename to libs/red-ui-http/src/lib/model/audit.ts index 8bef378ea..9427a4896 100644 --- a/libs/red-ui-http/src/lib/model/auditModel.ts +++ b/libs/red-ui-http/src/lib/model/audit.ts @@ -10,12 +10,12 @@ * Do not edit the class manually. */ -export interface AuditModel { - category?: string; - details?: any; - message?: string; - objectId?: string; - recordDate?: string; - recordId?: string; - userId?: string; +export interface IAudit { + readonly category?: string; + readonly details?: unknown; + readonly message?: string; + readonly objectId?: string; + readonly recordDate?: string; + readonly recordId?: string; + readonly userId?: string; } diff --git a/libs/red-ui-http/src/lib/model/auditResponse.ts b/libs/red-ui-http/src/lib/model/auditResponse.ts index 33803a1aa..e47bd2dc9 100644 --- a/libs/red-ui-http/src/lib/model/auditResponse.ts +++ b/libs/red-ui-http/src/lib/model/auditResponse.ts @@ -9,10 +9,10 @@ * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. */ -import { AuditModel } from './auditModel'; +import { IAudit } from './audit'; export interface AuditResponse { - data?: Array; + data?: Array; page?: number; pageSize?: number; totalHits?: number; diff --git a/libs/red-ui-http/src/lib/model/dictionary.ts b/libs/red-ui-http/src/lib/model/dictionary.ts index 7b32c04be..5bfd45658 100644 --- a/libs/red-ui-http/src/lib/model/dictionary.ts +++ b/libs/red-ui-http/src/lib/model/dictionary.ts @@ -10,48 +10,50 @@ * Do not edit the class manually. */ +import { List } from "../red-types"; + /** * Object containing a list of dictionary entries and colors of an entry type. */ -export interface Dictionary { +export interface IDictionary { /** * If true the ui will add a action to add values to dictionary */ - addToDictionaryAction?: boolean; + readonly addToDictionaryAction?: boolean; /** * True if the entries in this type should be matched case insensitively, default is false. */ - caseInsensitive?: boolean; + readonly caseInsensitive?: boolean; /** * The description of the dictionary type */ - description?: string; + readonly description?: string; /** * The DossierTemplate Id for this type */ - dossierTemplateId?: string; + readonly dossierTemplateId?: string; /** * The list of dictionary entries of an entry type. */ - entries?: Array; + readonly entries?: List; /** * The value of color must be a correct hex color */ - hexColor?: string; + readonly hexColor?: string; /** * True if the type just for hint, not for redaction, default is false. */ - hint?: boolean; + readonly hint?: boolean; /** * Label of the type */ - label?: string; + readonly label?: string; /** * The rank of this dictionary, higher rank means higher importance. */ - rank?: number; + readonly rank?: number; /** * True if the type just for recommendations, not for redaction, default is false. */ - recommendation?: boolean; + readonly recommendation?: boolean; } diff --git a/libs/red-ui-http/src/lib/model/dossier.ts b/libs/red-ui-http/src/lib/model/dossier.ts index e5f28bc68..f87e6224b 100644 --- a/libs/red-ui-http/src/lib/model/dossier.ts +++ b/libs/red-ui-http/src/lib/model/dossier.ts @@ -9,38 +9,38 @@ * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. */ +import { List } from '../red-types'; -export interface Dossier { - approverIds?: Array; - date?: string; - description?: string; - dossierId?: string; - dossierName?: string; - dossierTemplateId?: string; - downloadFileTypes?: Array; - dueDate?: string; - hardDeletedTime?: string; - memberIds?: Array; - ownerId?: string; - reportTemplateIds?: Array; - reportTypes?: Array; - softDeletedTime?: string; - status?: Dossier.StatusEnum; - watermarkEnabled?: boolean; +export interface IDossier { + 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 reportTemplateIds?: List; + readonly reportTypes?: List; + readonly softDeletedTime?: string; + readonly status?: DossierStatus; + readonly watermarkEnabled?: boolean; } -export namespace Dossier { - export type DownloadFileTypesEnum = 'ANNOTATED' | 'FLATTEN' | 'ORIGINAL' | 'PREVIEW' | 'REDACTED'; - export const DownloadFileTypesEnum = { - ANNOTATED: 'ANNOTATED' as DownloadFileTypesEnum, - FLATTEN: 'FLATTEN' as DownloadFileTypesEnum, - ORIGINAL: 'ORIGINAL' as DownloadFileTypesEnum, - PREVIEW: 'PREVIEW' as DownloadFileTypesEnum, - REDACTED: 'REDACTED' as DownloadFileTypesEnum - }; - export type StatusEnum = 'ACTIVE' | 'DELETED'; - export const StatusEnum = { - ACTIVE: 'ACTIVE' as StatusEnum, - DELETED: 'DELETED' as StatusEnum - }; -} +export const DownloadFileTypes = { + ANNOTATED: 'ANNOTATED', + FLATTEN: 'FLATTEN', + ORIGINAL: 'ORIGINAL', + PREVIEW: 'PREVIEW', + REDACTED: 'REDACTED' +} as const; +export type DownloadFileType = keyof typeof DownloadFileTypes; + +export const DossierStatuses = { + ACTIVE: 'ACTIVE', + DELETED: 'DELETED' +} as const; +export type DossierStatus = keyof typeof DossierStatuses; diff --git a/libs/red-ui-http/src/lib/model/dossierAttributeConfig.ts b/libs/red-ui-http/src/lib/model/dossierAttributeConfig.ts index 16f90a718..570df6c11 100644 --- a/libs/red-ui-http/src/lib/model/dossierAttributeConfig.ts +++ b/libs/red-ui-http/src/lib/model/dossierAttributeConfig.ts @@ -10,20 +10,18 @@ * Do not edit the class manually. */ -export interface DossierAttributeConfig { - id: string; - editable?: boolean; - label?: string; - placeholder?: string; - type?: DossierAttributeConfig.TypeEnum; +export interface IDossierAttributeConfig { + readonly id: string; + readonly editable?: boolean; + readonly label?: string; + readonly placeholder?: string; + readonly type?: DossierAttributeConfigType; } -export namespace DossierAttributeConfig { - export type TypeEnum = 'DATE' | 'IMAGE' | 'NUMBER' | 'TEXT'; - export const TypeEnum = { - DATE: 'DATE' as TypeEnum, - IMAGE: 'IMAGE' as TypeEnum, - NUMBER: 'NUMBER' as TypeEnum, - TEXT: 'TEXT' as TypeEnum - }; -} +export const DossierAttributeConfigTypes = { + DATE: 'DATE', + IMAGE: 'IMAGE', + NUMBER: 'NUMBER', + TEXT: 'TEXT' +} as const; +export type DossierAttributeConfigType = keyof typeof DossierAttributeConfigTypes; diff --git a/libs/red-ui-http/src/lib/model/dossierAttributesConfig.ts b/libs/red-ui-http/src/lib/model/dossierAttributesConfig.ts index bdaf8a0af..a3ef99543 100644 --- a/libs/red-ui-http/src/lib/model/dossierAttributesConfig.ts +++ b/libs/red-ui-http/src/lib/model/dossierAttributesConfig.ts @@ -9,8 +9,8 @@ * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. */ -import { DossierAttributeConfig } from './dossierAttributeConfig'; +import { IDossierAttributeConfig } from './dossierAttributeConfig'; export interface DossierAttributesConfig { - dossierAttributeConfigs?: Array; + dossierAttributeConfigs?: Array; } diff --git a/libs/red-ui-http/src/lib/model/dossierRequest.ts b/libs/red-ui-http/src/lib/model/dossierRequest.ts index 744fa20c5..71682ec00 100644 --- a/libs/red-ui-http/src/lib/model/dossierRequest.ts +++ b/libs/red-ui-http/src/lib/model/dossierRequest.ts @@ -10,6 +10,8 @@ * Do not edit the class manually. */ +import { List } from "../red-types"; + /** * Object containing information about a dossier. */ @@ -17,51 +19,51 @@ export interface DossierRequest { /** * The id(s) of approvers associated to this dossier. */ - approverIds?: Array; + readonly approverIds?: List; /** * The dossier's description (optional). */ - description?: string; + readonly description?: string; /** * The id of the dossier, can be null for create requests. */ - dossierId?: string; + readonly dossierId?: string; /** * The name of the dossier. Must be unique. */ - dossierName?: string; + readonly dossierName?: string; /** * The dossierTemplateId for this dossier. can be null for update request. */ - dossierTemplateId?: string; + readonly dossierTemplateId?: string; /** * Download File Types for this dossiers submission package. */ - downloadFileTypes?: Array; + readonly downloadFileTypes?: List; /** * The date when the dossier is due. */ - dueDate?: string; + readonly dueDate?: string; /** * The id(s) of members associated to this dossier. */ - memberIds?: Array; + readonly memberIds?: List; /** * The id of the owning user. */ - ownerId?: string; + readonly ownerId?: string; /** * Id(s) of the word report templates used to generate downloads */ - reportTemplateIds?: Array; + readonly reportTemplateIds?: List; /** * Report File Types for this dossiers submission package. */ - reportTypes?: Array; + readonly reportTypes?: List; /** * Whether a watermark will be applied to the redacted files or not. */ - watermarkEnabled?: boolean; + readonly watermarkEnabled?: boolean; } export namespace DossierRequest { diff --git a/libs/red-ui-http/src/lib/model/dossierTemplateModel.ts b/libs/red-ui-http/src/lib/model/dossierTemplate.ts similarity index 59% rename from libs/red-ui-http/src/lib/model/dossierTemplateModel.ts rename to libs/red-ui-http/src/lib/model/dossierTemplate.ts index 77146e580..911014429 100644 --- a/libs/red-ui-http/src/lib/model/dossierTemplateModel.ts +++ b/libs/red-ui-http/src/lib/model/dossierTemplate.ts @@ -9,61 +9,52 @@ * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. */ +import { DownloadFileType } from './dossier'; +import { List } from '../red-types'; -export interface DossierTemplateModel { +export interface IDossierTemplate { /** * The userId of the user who created this DossierTemplate. Set by the system. */ - createdBy?: string; + readonly createdBy?: string; /** * The date when this dossierTemplate was created. Set by System on create. */ - dateAdded?: string; + readonly dateAdded?: string; /** * The date when this dossierTemplate was last modified. Set by System on create. */ - dateModified?: string; + readonly dateModified?: string; /** * The description of this dossierTemplate */ - description?: string; + readonly description?: string; /** * The Rule Set Id. Generated by the system on create. */ - dossierTemplateId?: string; + readonly dossierTemplateId?: string; /** * Download File Types for this dossierTemplate's dossiers submission package. */ - downloadFileTypes?: Array; + readonly downloadFileTypes?: List; /** * The userId of the user who last modified this DossierTemplate. Set by the system. */ - modifiedBy?: string; + readonly modifiedBy?: string; /** * The name of this dossierTemplate. Must be set on create / update requests */ - name?: string; + readonly name?: string; /** * Report File Types for this dossierTemplate's dossiers submission package. */ - reportTemplateIds?: string[]; + readonly reportTemplateIds?: List; /** * Validity of start this dossierTemplate. */ - validFrom?: string; + readonly validFrom?: string; /** * Validity of end this dossierTemplate. */ - validTo?: string; -} - -export namespace DossierTemplateModel { - export type DownloadFileTypesEnum = 'ANNOTATED' | 'FLATTEN' | 'ORIGINAL' | 'PREVIEW' | 'REDACTED'; - export const DownloadFileTypesEnum = { - ANNOTATED: 'ANNOTATED' as DownloadFileTypesEnum, - FLATTEN: 'FLATTEN' as DownloadFileTypesEnum, - ORIGINAL: 'ORIGINAL' as DownloadFileTypesEnum, - PREVIEW: 'PREVIEW' as DownloadFileTypesEnum, - REDACTED: 'REDACTED' as DownloadFileTypesEnum - }; + readonly validTo?: string; } diff --git a/libs/red-ui-http/src/lib/model/fileStatus.ts b/libs/red-ui-http/src/lib/model/file.ts similarity index 58% rename from libs/red-ui-http/src/lib/model/fileStatus.ts rename to libs/red-ui-http/src/lib/model/file.ts index 773c3cf48..1d5212519 100644 --- a/libs/red-ui-http/src/lib/model/fileStatus.ts +++ b/libs/red-ui-http/src/lib/model/file.ts @@ -14,43 +14,43 @@ import { FileAttributes } from './fileAttributes'; /** * Object containing information on a specific file. */ -export interface FileStatus { +export interface IFile { /** * Date and time when the file was added to the system. */ - added?: string; + readonly added?: string; /** * Shows if all manual changes have been applied by a reanalysis. */ - allManualRedactionsApplied?: boolean; + readonly allManualRedactionsApplied?: boolean; /** * Shows how long the last analysis took */ - analysisDuration?: number; + readonly analysisDuration?: number; /** * Shows if the file requires reanalysis. */ - analysisRequired?: boolean; + readonly analysisRequired?: boolean; /** * Shows the date of approval, if approved. */ - approvalDate?: string; + readonly approvalDate?: string; /** * The current reviewer's (if any) user id. */ - currentReviewer?: string; + readonly currentReviewer?: string; /** * Shows which dictionary versions was used during the analysis. */ - dictionaryVersion?: number; + readonly dictionaryVersion?: number; /** * Shows which dossier dictionary versions was used during the analysis. */ - dossierDictionaryVersion?: number; + readonly dossierDictionaryVersion?: number; /** * The ID of the dossier the file belongs to. */ - dossierId?: string; + readonly dossierId?: string; /** * The dossierTemplateId for this file. */ @@ -58,130 +58,116 @@ export interface FileStatus { /** * Shows if the file was excluded from analysis. */ - excluded?: boolean; + readonly excluded?: boolean; /** * Set of excluded pages for this file. */ - excludedPages?: Array; + readonly excludedPages?: Array; fileAttributes?: FileAttributes; /** * The ID of the file. */ - fileId?: string; + readonly fileId?: string; /** * The file's name. */ - filename?: string; + readonly filename?: string; /** * Shows if this file has comments on annotations. */ - hasAnnotationComments?: boolean; + readonly hasAnnotationComments?: boolean; /** * Shows if any hints were found during the analysis. */ - hasHints?: boolean; + readonly hasHints?: boolean; /** * Shows if any images were found during the analysis. */ - hasImages?: boolean; + readonly hasImages?: boolean; /** * Shows if any redactions were found during the analysis. */ - hasRedactions?: boolean; + readonly hasRedactions?: boolean; /** * Shows if any requests were found during the analysis. */ - hasRequests?: boolean; + readonly hasRequests?: boolean; /** * Shows if there are any Suggestions in this file. */ - hasSuggestions?: boolean; + readonly hasSuggestions?: boolean; /** * Shows if there is any change between the previous and current analysis. */ - hasUpdates?: boolean; + readonly hasUpdates?: boolean; /** * Date and time when the files attributes was last updated. */ - lastFileAttributeChange?: string; + readonly lastFileAttributeChange?: string; /** * Shows if this file has been OCRed by us. Last Time of OCR. */ - lastOCRTime?: string; + readonly lastOCRTime?: string; /** * Shows the last date of a successful analysis. */ - lastProcessed?: string; + readonly lastProcessed?: string; /** * The last reviewer's (if any) user id. */ - lastReviewer?: string; + readonly lastReviewer?: string; /** * Date and time when the file was last updated. */ - lastUpdated?: string; + readonly lastUpdated?: string; /** * Shows last date the document was uploaded. */ - lastUploaded?: string; + readonly lastUploaded?: string; /** * Shows which legal basis versions was used during the analysis. */ - legalBasisVersion?: number; + readonly legalBasisVersion?: number; /** * The number of times the file has been analyzed. */ - numberOfAnalyses?: number; + readonly numberOfAnalyses?: number; /** * The number of pages of the file. */ - numberOfPages?: number; + readonly numberOfPages?: number; /** * Shows which rules versions was used during the analysis. */ - rulesVersion?: number; + readonly rulesVersion?: number; /** * Shows if the file is soft deleted. */ - softDeleted?: string; + readonly softDeleted?: string; /** * The status of the file with regard to its analysis an review processes. */ - status?: FileStatus.StatusEnum; + readonly status?: FileStatus; /** * The ID of the user who uploaded the file. */ - uploader?: string; + readonly uploader?: string; } -export namespace FileStatus { - export type StatusEnum = - | 'APPROVED' - | 'DELETED' - | 'ERROR' - | 'EXCLUDED' - | 'FULLREPROCESS' - | 'INDEXING' - | 'OCR_PROCESSING' - | 'PROCESSING' - | 'REPROCESS' - | 'UNASSIGNED' - | 'UNDER_APPROVAL' - | 'UNDER_REVIEW' - | 'UNPROCESSED'; - export const StatusEnum = { - APPROVED: 'APPROVED' as StatusEnum, - DELETED: 'DELETED' as StatusEnum, - ERROR: 'ERROR' as StatusEnum, - EXCLUDED: 'EXCLUDED' as StatusEnum, - FULLREPROCESS: 'FULLREPROCESS' as StatusEnum, - INDEXING: 'INDEXING' as StatusEnum, - OCRPROCESSING: 'OCR_PROCESSING' as StatusEnum, - PROCESSING: 'PROCESSING' as StatusEnum, - REPROCESS: 'REPROCESS' as StatusEnum, - UNASSIGNED: 'UNASSIGNED' as StatusEnum, - UNDERAPPROVAL: 'UNDER_APPROVAL' as StatusEnum, - UNDERREVIEW: 'UNDER_REVIEW' as StatusEnum, - UNPROCESSED: 'UNPROCESSED' as StatusEnum - } as const; -} +export const FileStatuses = { + APPROVED: 'APPROVED', + DELETED: 'DELETED', + ERROR: 'ERROR', + EXCLUDED: 'EXCLUDED', + FULLREPROCESS: 'FULLREPROCESS', + INDEXING: 'INDEXING', + OCR_PROCESSING: 'OCR_PROCESSING', + PROCESSING: 'PROCESSING', + REPROCESS: 'REPROCESS', + UNASSIGNED: 'UNASSIGNED', + UNDER_APPROVAL: 'UNDER_APPROVAL', + UNDER_REVIEW: 'UNDER_REVIEW', + UNPROCESSED: 'UNPROCESSED' +} as const; + +export type FileStatus = keyof typeof FileStatuses; diff --git a/libs/red-ui-http/src/lib/model/fileAttributeConfig.ts b/libs/red-ui-http/src/lib/model/fileAttributeConfig.ts index 09e05543a..affcab95a 100644 --- a/libs/red-ui-http/src/lib/model/fileAttributeConfig.ts +++ b/libs/red-ui-http/src/lib/model/fileAttributeConfig.ts @@ -10,23 +10,21 @@ * Do not edit the class manually. */ -export interface FileAttributeConfig { - id: string; - csvColumnHeader?: string; - editable?: boolean; - label?: string; - placeholder?: string; - primaryAttribute?: boolean; - displayedInFileList?: boolean; - filterable?: boolean; - type?: FileAttributeConfig.TypeEnum; +export interface IFileAttributeConfig { + readonly id: string; + readonly csvColumnHeader?: string; + readonly editable?: boolean; + readonly label?: string; + readonly placeholder?: string; + readonly primaryAttribute?: boolean; + readonly displayedInFileList?: boolean; + readonly filterable?: boolean; + readonly type?: FileAttributeConfigType; } -export namespace FileAttributeConfig { - export type TypeEnum = 'DATE' | 'NUMBER' | 'TEXT'; - export const TypeEnum = { - DATE: 'DATE' as TypeEnum, - NUMBER: 'NUMBER' as TypeEnum, - TEXT: 'TEXT' as TypeEnum - }; -} +export const FileAttributeConfigTypes = { + DATE: 'DATE', + NUMBER: 'NUMBER', + TEXT: 'TEXT' +} as const; +export type FileAttributeConfigType = keyof typeof FileAttributeConfigTypes; diff --git a/libs/red-ui-http/src/lib/model/fileAttributesConfig.ts b/libs/red-ui-http/src/lib/model/fileAttributesConfig.ts index 086b504b8..00aefa3c5 100644 --- a/libs/red-ui-http/src/lib/model/fileAttributesConfig.ts +++ b/libs/red-ui-http/src/lib/model/fileAttributesConfig.ts @@ -9,10 +9,10 @@ * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. */ -import { FileAttributeConfig } from './fileAttributeConfig'; +import { IFileAttributeConfig } from './fileAttributeConfig'; export interface FileAttributesConfig { delimiter?: string; - fileAttributeConfigs?: Array; + fileAttributeConfigs?: Array; filenameMappingColumnHeaderName?: string; } diff --git a/libs/red-ui-http/src/lib/model/models.ts b/libs/red-ui-http/src/lib/model/models.ts index 5600d88f2..0bea96612 100644 --- a/libs/red-ui-http/src/lib/model/models.ts +++ b/libs/red-ui-http/src/lib/model/models.ts @@ -1,7 +1,7 @@ export * from './addCommentRequest'; export * from './addRedactionRequest'; export * from './approveRequest'; -export * from './auditModel'; +export * from './audit'; export * from './auditResponse'; export * from './auditSearchRequest'; export * from './authInfo'; @@ -23,7 +23,7 @@ export * from './dossierAttributesConfig'; export * from './dossierAttributesReq'; export * from './dossierAttributesRes'; export * from './dossierRequest'; -export * from './dossierTemplateModel'; +export * from './dossierTemplate'; export * from './downloadDetails'; export * from './downloadResponse'; export * from './downloadStatus'; @@ -31,7 +31,7 @@ export * from './downloadStatusResponse'; export * from './fileAttributeConfig'; export * from './fileAttributes'; export * from './fileAttributesConfig'; -export * from './fileStatus'; +export * from './file'; export * from './fileUploadResult'; export * from './forceRedactionRequest'; export * from './generalConfigurationModel'; diff --git a/libs/red-ui-http/src/lib/model/reportData.ts b/libs/red-ui-http/src/lib/model/reportData.ts index 562ac25f1..d5fba5555 100644 --- a/libs/red-ui-http/src/lib/model/reportData.ts +++ b/libs/red-ui-http/src/lib/model/reportData.ts @@ -41,12 +41,12 @@ export namespace ReportData { ERROR: 'ERROR' as StatusEnum, EXCLUDED: 'EXCLUDED' as StatusEnum, FULLREPROCESS: 'FULLREPROCESS' as StatusEnum, - OCRPROCESSING: 'OCR_PROCESSING' as StatusEnum, + OCR_PROCESSING: 'OCR_PROCESSING' as StatusEnum, PROCESSING: 'PROCESSING' as StatusEnum, REPROCESS: 'REPROCESS' as StatusEnum, UNASSIGNED: 'UNASSIGNED' as StatusEnum, - UNDERAPPROVAL: 'UNDER_APPROVAL' as StatusEnum, - UNDERREVIEW: 'UNDER_REVIEW' as StatusEnum, + UNDER_APPROVAL: 'UNDER_APPROVAL' as StatusEnum, + UNDER_REVIEW: 'UNDER_REVIEW' as StatusEnum, UNPROCESSED: 'UNPROCESSED' as StatusEnum }; } diff --git a/libs/red-ui-http/src/lib/model/typeResponse.ts b/libs/red-ui-http/src/lib/model/typeResponse.ts index 59e88f092..7093440c6 100644 --- a/libs/red-ui-http/src/lib/model/typeResponse.ts +++ b/libs/red-ui-http/src/lib/model/typeResponse.ts @@ -9,7 +9,7 @@ * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. */ -import { TypeValue } from './typeValue'; +import { ITypeValue } from "./typeValue"; /** * Object containing a list of values of an entry type. @@ -18,5 +18,5 @@ export interface TypeResponse { /** * The list of values of an entry type, which include colors, hint and caseInsensitive. */ - types?: Array; + types?: Array; } diff --git a/libs/red-ui-http/src/lib/model/typeValue.ts b/libs/red-ui-http/src/lib/model/typeValue.ts index c46a17a52..1eccf2099 100644 --- a/libs/red-ui-http/src/lib/model/typeValue.ts +++ b/libs/red-ui-http/src/lib/model/typeValue.ts @@ -13,45 +13,45 @@ /** * Object containing entry type with an array of r-g-b colors. */ -export interface TypeValue { +export interface ITypeValue { /** * If true the ui will add a action to add values to dictionary */ - addToDictionaryAction?: boolean; + readonly addToDictionaryAction?: boolean; /** * True if the entries in this type should be matched case insensitively, default is false. */ - caseInsensitive?: boolean; + readonly caseInsensitive?: boolean; /** * The description of the dictionary type */ - description?: string; + readonly description?: string; /** * The DossierTemplate Id for this type */ - dossierTemplateId?: string; + readonly dossierTemplateId?: string; /** * The value of color must be a correct hex color */ - hexColor?: string; + readonly hexColor?: string; /** * True if the type just for hint, not for redaction, default is false. */ - hint?: boolean; + readonly hint?: boolean; /** * The rank of this dictionary, higher rank means higher importance. */ - rank?: number; + readonly rank?: number; /** * True if the type just for recommendations, not for redaction, default is false. */ - recommendation?: boolean; + readonly recommendation?: boolean; /** * The nonnull entry type. */ - type?: string; + readonly type?: string; /** * The label of this type */ - label?: string; + readonly label?: string; } diff --git a/libs/red-ui-http/src/lib/model/user.ts b/libs/red-ui-http/src/lib/model/user.ts index 338f08774..12c831294 100644 --- a/libs/red-ui-http/src/lib/model/user.ts +++ b/libs/red-ui-http/src/lib/model/user.ts @@ -13,29 +13,29 @@ /** * Object containing information of user and roles. */ -export interface User { +export interface IUser { /** * Email of user. */ - email?: string; + readonly email?: string; /** * First name of user. */ - firstName?: string; + readonly firstName?: string; /** * Last name of user. */ - lastName?: string; + readonly lastName?: string; /** * The list of RED_* roles. */ - roles?: Array; + readonly roles?: readonly string[]; /** * Id of user. */ - userId?: string; + readonly userId?: string; /** * Username for login. */ - username?: string; + readonly username?: string; } diff --git a/libs/red-ui-http/src/lib/red-types.ts b/libs/red-ui-http/src/lib/red-types.ts new file mode 100644 index 000000000..5ead52e51 --- /dev/null +++ b/libs/red-ui-http/src/lib/red-types.ts @@ -0,0 +1,5 @@ +/** + * Custom list type to hold readonly arrays. + * Defaults to readonly string list + */ +export type List = readonly T[]; diff --git a/package.json b/package.json index 71a173926..c520b8d6d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "redaction", - "version": "2.232.0", + "version": "2.234.0", "private": true, "license": "MIT", "scripts": { @@ -106,8 +106,8 @@ "eslint": "7.32.0", "eslint-config-airbnb-typescript": "^14.0.0", "eslint-config-prettier": "8.3.0", - "eslint-plugin-prettier": "^4.0.0", "eslint-plugin-import": "2.24.2", + "eslint-plugin-prettier": "^4.0.0", "google-translate-api-browser": "^1.1.71", "husky": "4.3.8", "jest": "27.1.1", diff --git a/paligo-theme.tar.gz b/paligo-theme.tar.gz index 645fb50b2..0df1fd481 100644 Binary files a/paligo-theme.tar.gz and b/paligo-theme.tar.gz differ diff --git a/paligo-theme/paligo-styles/redacto-theme.css b/paligo-theme/paligo-styles/redacto-theme.css index 542debb6c..7b03d3de3 100644 --- a/paligo-theme/paligo-styles/redacto-theme.css +++ b/paligo-theme/paligo-styles/redacto-theme.css @@ -532,7 +532,7 @@ body { color: #283241; background-color: #f5f5f7; font-family: "Inter", sans-serif; - scrollbar-color: var(--iqser-quick-filter-border) var(--iqser-filter-bg); + scrollbar-color: var(--iqser-quick-filter-border) var(--iqser-grey-2); scrollbar-width: thin; /* Track */ /* Handle */ @@ -552,7 +552,7 @@ body::-webkit-scrollbar { width: 11px; } body::-webkit-scrollbar-track { - background: var(--iqser-filter-bg); + background: var(--iqser-grey-2); } body::-webkit-scrollbar-thumb { background: var(--iqser-quick-filter-border);