RED-10405: added labels and filtering for timeout pending type.
This commit is contained in:
parent
9e71ae3fa8
commit
887157e588
@ -61,7 +61,8 @@
|
||||
*ngFor="let config of statusConfig"
|
||||
[attr.help-mode-key]="'dashboard_in_dossier'"
|
||||
[config]="config"
|
||||
filterKey="processingTypeFilters"
|
||||
[class.indent]="!!PendingTypes[config.id]"
|
||||
[filterKey]="PendingTypes[config.id] ? 'pendingTypeFilters' : 'processingTypeFilters'"
|
||||
></iqser-progress-bar>
|
||||
</div>
|
||||
|
||||
|
||||
@ -45,3 +45,7 @@
|
||||
iqser-progress-bar:not(:last-child) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.indent {
|
||||
margin-left: 32px;
|
||||
}
|
||||
|
||||
@ -1,15 +1,7 @@
|
||||
import { AsyncPipe, NgForOf, NgIf, NgTemplateOutlet } from '@angular/common';
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import {
|
||||
CircleButtonComponent,
|
||||
CircleButtonTypes,
|
||||
getConfig,
|
||||
IqserAllowDirective,
|
||||
IqserLoadingModule,
|
||||
ProgressBarConfigModel,
|
||||
Toaster,
|
||||
} from '@iqser/common-ui';
|
||||
import { CircleButtonComponent, CircleButtonTypes, getConfig, IqserLoadingModule, ProgressBarConfigModel, Toaster } from '@iqser/common-ui';
|
||||
import { FilterService, INestedFilter } from '@iqser/common-ui/lib/filtering';
|
||||
import { getCurrentUser, InitialsAvatarComponent } from '@iqser/common-ui/lib/users';
|
||||
import { ContextComponent, getParam, IqserTooltipPositions, shareLast } from '@iqser/common-ui/lib/utils';
|
||||
@ -21,7 +13,9 @@ import {
|
||||
DossierAttributeWithValue,
|
||||
DossierStats,
|
||||
File,
|
||||
FileErrorCodes,
|
||||
IDossierRequest,
|
||||
PendingTypes,
|
||||
ProcessingTypes,
|
||||
StatusSorter,
|
||||
User,
|
||||
@ -58,7 +52,6 @@ interface DossierDetailsContext {
|
||||
NgIf,
|
||||
AsyncPipe,
|
||||
CircleButtonComponent,
|
||||
IqserAllowDirective,
|
||||
TranslateModule,
|
||||
DonutChartComponent,
|
||||
IqserLoadingModule,
|
||||
@ -74,6 +67,7 @@ export class DossierDetailsComponent extends ContextComponent<DossierDetailsCont
|
||||
#currentChartSubtitleIndex = 0;
|
||||
readonly #dossierId = getParam(DOSSIER_ID);
|
||||
protected readonly circleButtonTypes = CircleButtonTypes;
|
||||
protected readonly PendingTypes = PendingTypes;
|
||||
@Input() dossierAttributes: DossierAttributeWithValue[];
|
||||
@Output() readonly toggleCollapse = new EventEmitter();
|
||||
editingOwner = false;
|
||||
@ -97,14 +91,17 @@ export class DossierDetailsComponent extends ContextComponent<DossierDetailsCont
|
||||
super();
|
||||
const dossier$ = _dossiersService.getEntityChanged$(this.#dossierId).pipe(shareLast());
|
||||
const filesChanged$ = _filesMapService.watchChanged$(this.#dossierId).pipe(shareLast());
|
||||
const files$ = _filesMapService.get$(this.#dossierId).pipe(shareLast());
|
||||
const dossierStats$ = dossierStatsService.watch$(this.#dossierId).pipe(shareLast());
|
||||
const dossierStatsWithEffects$ = dossierStats$.pipe(
|
||||
combineLatestWith(filesChanged$),
|
||||
tap(([stats]) => this.#calculateChartConfig(stats)),
|
||||
map(([stats]) => stats),
|
||||
);
|
||||
const statusConfig$ = dossierStats$.pipe(map(stats => this.#calculateStatusConfig(stats)));
|
||||
|
||||
const statusConfig$ = dossierStats$.pipe(
|
||||
combineLatestWith(files$),
|
||||
map(([stats, files]) => this.#calculateStatusConfig(stats, files)),
|
||||
);
|
||||
super._initContext({
|
||||
needsWorkFilters: filterService.getFilterModels$('needsWorkFilters'),
|
||||
dossier: dossier$,
|
||||
@ -152,7 +149,8 @@ export class DossierDetailsComponent extends ContextComponent<DossierDetailsCont
|
||||
.reduce((sum: number, file: File) => sum + file.numberOfPages, 0);
|
||||
}
|
||||
|
||||
#calculateStatusConfig(stats: DossierStats): ProgressBarConfigModel[] {
|
||||
#calculateStatusConfig(stats: DossierStats, files: File[]): ProgressBarConfigModel[] {
|
||||
const numberOfTimeoutFiles = files.filter(file => file.errorCode === FileErrorCodes.RULES_EXECUTION_TIMEOUT).length;
|
||||
return [
|
||||
{
|
||||
id: ProcessingTypes.pending,
|
||||
@ -161,6 +159,13 @@ export class DossierDetailsComponent extends ContextComponent<DossierDetailsCont
|
||||
count: stats.processingStats.pending,
|
||||
icon: 'red:reanalyse',
|
||||
},
|
||||
{
|
||||
id: PendingTypes.timeout,
|
||||
label: _('processing-status.pending-timeout'),
|
||||
total: stats.numberOfFiles,
|
||||
count: numberOfTimeoutFiles,
|
||||
icon: 'red:reanalyse',
|
||||
},
|
||||
{
|
||||
id: ProcessingTypes.ocr,
|
||||
label: _('processing-status.ocr'),
|
||||
|
||||
@ -39,7 +39,12 @@
|
||||
</ng-container>
|
||||
|
||||
<div [class.extend-cols]="file.isError" class="status-container cell">
|
||||
<div *ngIf="file.isError" class="small-label error" translate="dossier-overview.file-listing.file-entry.file-error"></div>
|
||||
<div
|
||||
*ngIf="file.isError"
|
||||
class="small-label error"
|
||||
translate="dossier-overview.file-listing.file-entry.file-error"
|
||||
[translateParams]="{ errorCode: file.errorCode }"
|
||||
></div>
|
||||
|
||||
<div *ngIf="file.isUnprocessed" class="small-label" translate="dossier-overview.file-listing.file-entry.file-pending"></div>
|
||||
|
||||
@ -61,8 +66,8 @@
|
||||
[configs]="[
|
||||
{
|
||||
color: file.workflowStatus,
|
||||
length: 1
|
||||
}
|
||||
length: 1,
|
||||
},
|
||||
]"
|
||||
></iqser-status-bar>
|
||||
</ng-template>
|
||||
|
||||
@ -24,6 +24,7 @@ import {
|
||||
FileAttributeConfigType,
|
||||
FileAttributeConfigTypes,
|
||||
IFileAttributeConfig,
|
||||
PendingType,
|
||||
ProcessingType,
|
||||
StatusSorter,
|
||||
User,
|
||||
@ -184,6 +185,7 @@ export class ConfigService {
|
||||
const allDistinctPeople = new Set<string>();
|
||||
const allDistinctNeedsWork = new Set<string>();
|
||||
const allDistinctProcessingTypes = new Set<ProcessingType>();
|
||||
const allDistinctPendingTypes = new Set<PendingType>();
|
||||
|
||||
const dynamicFilters = new Map<string, { type: FileAttributeConfigType; filterValue: Set<string> }>();
|
||||
|
||||
@ -216,6 +218,7 @@ export class ConfigService {
|
||||
}
|
||||
|
||||
allDistinctProcessingTypes.add(file.processingType);
|
||||
allDistinctPendingTypes.add(file.pendingType);
|
||||
|
||||
// extract values for dynamic filters
|
||||
fileAttributeConfigs.forEach(config => {
|
||||
@ -317,6 +320,14 @@ export class ConfigService {
|
||||
hide: true,
|
||||
});
|
||||
|
||||
const pendingTypesFilters = [...allDistinctPendingTypes].map(item => new NestedFilter({ id: item, label: item }));
|
||||
filterGroups.push({
|
||||
slug: 'pendingTypeFilters',
|
||||
filters: pendingTypesFilters,
|
||||
checker: (file: File, filter: INestedFilter) => file.pendingType === filter.id,
|
||||
hide: true,
|
||||
});
|
||||
|
||||
dynamicFilters.forEach((value: { filterValue: Set<string>; type: FileAttributeConfigType }, filterKey: string) => {
|
||||
const id = filterKey.split(':')[0];
|
||||
const key = filterKey.split(':')[1];
|
||||
|
||||
@ -969,7 +969,7 @@
|
||||
"download-file-disabled": "Download: Sie müssen Genehmiger im Dossier sein und die initiale Verarbeitung {count, plural, one{der Datei} other{der Dateien}} muss abgeschlossen sein.",
|
||||
"file-listing": {
|
||||
"file-entry": {
|
||||
"file-error": "Reanalyse erforderlich",
|
||||
"file-error": "Reanalyse erforderlich {errorCode, select, RULES_EXECUTION_TIMEOUT{(Zeitlimit für Regeln)} other{}}",
|
||||
"file-pending": "Ausstehend ..."
|
||||
}
|
||||
},
|
||||
@ -2041,6 +2041,7 @@
|
||||
"processing-status": {
|
||||
"ocr": "OCR",
|
||||
"pending": "Ausstehend",
|
||||
"pending-timeout": "Ausstehend (Zeitlimit für Regeln)",
|
||||
"processed": "verarbeitet",
|
||||
"processing": "Verarbeitung läuft"
|
||||
},
|
||||
|
||||
@ -969,7 +969,7 @@
|
||||
"download-file-disabled": "To download, ensure you are an approver in the dossier, and the {count, plural, one{file has undergone} other{files have undergone}} initial processing.",
|
||||
"file-listing": {
|
||||
"file-entry": {
|
||||
"file-error": "Re-processing required",
|
||||
"file-error": "Re-processing required {errorCode, select, RULES_EXECUTION_TIMEOUT{(Rules timeout)} other{}}",
|
||||
"file-pending": "Pending..."
|
||||
}
|
||||
},
|
||||
@ -2041,6 +2041,7 @@
|
||||
"processing-status": {
|
||||
"ocr": "OCR",
|
||||
"pending": "Pending",
|
||||
"pending-timeout": "Pending (Rules timeout)",
|
||||
"processed": "processed",
|
||||
"processing": "Processing"
|
||||
},
|
||||
|
||||
@ -969,7 +969,7 @@
|
||||
"download-file-disabled": "You need to be approver in the dossier and the {count, plural, one{file needs} other{files need}} to be initially processed in order to download.",
|
||||
"file-listing": {
|
||||
"file-entry": {
|
||||
"file-error": "Reanalyse erforderlich",
|
||||
"file-error": "Reanalyse erforderlich {errorCode, select, RULES_EXECUTION_TIMEOUT{(Zeitlimit für Regeln)} other{}}",
|
||||
"file-pending": "Ausstehend ..."
|
||||
}
|
||||
},
|
||||
@ -2041,6 +2041,7 @@
|
||||
"processing-status": {
|
||||
"ocr": "OCR",
|
||||
"pending": "Pending",
|
||||
"pending-timeout": "Ausstehend (Zeitlimit für Regeln)",
|
||||
"processed": "Processed",
|
||||
"processing": "Processing"
|
||||
},
|
||||
|
||||
@ -969,7 +969,7 @@
|
||||
"download-file-disabled": "You need to be approver in the dossier and the {count, plural, one{file needs} other{files need}} to be initially processed in order to download.",
|
||||
"file-listing": {
|
||||
"file-entry": {
|
||||
"file-error": "Re-processing required",
|
||||
"file-error": "Re-processing required {errorCode, select, RULES_EXECUTION_TIMEOUT{(Rules timeout)} other{}}",
|
||||
"file-pending": "Pending..."
|
||||
}
|
||||
},
|
||||
@ -2041,6 +2041,7 @@
|
||||
"processing-status": {
|
||||
"ocr": "OCR",
|
||||
"pending": "Pending",
|
||||
"pending-timeout": "Pending (Rules timeout)",
|
||||
"processed": "Processed",
|
||||
"processing": "Processing"
|
||||
},
|
||||
|
||||
@ -1,22 +1,6 @@
|
||||
import {
|
||||
isProcessingStatuses,
|
||||
OCR_STATES,
|
||||
PENDING_STATES,
|
||||
PROCESSED_STATES,
|
||||
PROCESSING_STATES,
|
||||
ProcessingFileStatus,
|
||||
} from '../files/types';
|
||||
import { isProcessingStatuses, OCR_STATES, PENDING_STATES, PROCESSED_STATES, PROCESSING_STATES, ProcessingFileStatus } from '../files';
|
||||
import { IDossierStats } from './dossier-stats';
|
||||
import { FileCountPerProcessingStatus, FileCountPerWorkflowStatus } from './types';
|
||||
|
||||
export const ProcessingTypes = {
|
||||
pending: 'pending',
|
||||
ocr: 'ocr',
|
||||
processing: 'processing',
|
||||
processed: 'processed',
|
||||
} as const;
|
||||
|
||||
export type ProcessingType = keyof typeof ProcessingTypes;
|
||||
import { FileCountPerProcessingStatus, FileCountPerWorkflowStatus, ProcessingType } from './types';
|
||||
|
||||
export type ProcessingStats = Record<ProcessingType, number>;
|
||||
|
||||
|
||||
@ -2,3 +2,18 @@ import { ProcessingFileStatus, WorkflowFileStatus } from '../files/types';
|
||||
|
||||
export type FileCountPerWorkflowStatus = { [key in WorkflowFileStatus]?: number };
|
||||
export type FileCountPerProcessingStatus = { [key in ProcessingFileStatus]?: number };
|
||||
|
||||
export const ProcessingTypes = {
|
||||
pending: 'pending',
|
||||
ocr: 'ocr',
|
||||
processing: 'processing',
|
||||
processed: 'processed',
|
||||
} as const;
|
||||
|
||||
export type ProcessingType = keyof typeof ProcessingTypes;
|
||||
|
||||
export const PendingTypes = {
|
||||
timeout: 'timeout',
|
||||
} as const;
|
||||
|
||||
export type PendingType = keyof typeof PendingTypes;
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import { Entity } from '@iqser/common-ui';
|
||||
import { ProcessingType, ProcessingTypes } from '../dossier-stats/dossier-stats.model';
|
||||
import { ARCHIVE_ROUTE, DOSSIERS_ROUTE } from '../dossiers/constants';
|
||||
import { FileAttributes } from '../file-attributes/file-attributes';
|
||||
import { StatusSorter } from '../shared/sorters/status-sorter';
|
||||
import { ARCHIVE_ROUTE, DOSSIERS_ROUTE } from '../dossiers';
|
||||
import { FileAttributes } from '../file-attributes';
|
||||
import { StatusSorter } from '../shared';
|
||||
import { IFile } from './file';
|
||||
import {
|
||||
FileErrorCode,
|
||||
FileErrorCodes,
|
||||
isFullProcessingStatuses,
|
||||
isProcessingStatuses,
|
||||
OCR_STATES,
|
||||
@ -15,6 +16,7 @@ import {
|
||||
WorkflowFileStatus,
|
||||
WorkflowFileStatuses,
|
||||
} from './types';
|
||||
import { PendingType, PendingTypes, ProcessingType, ProcessingTypes } from '../dossier-stats';
|
||||
|
||||
export class File extends Entity<IFile> implements IFile {
|
||||
readonly added?: string;
|
||||
@ -81,6 +83,8 @@ export class File extends Entity<IFile> implements IFile {
|
||||
readonly canBeOCRed: boolean;
|
||||
|
||||
readonly processingType: ProcessingType;
|
||||
readonly errorCode?: FileErrorCode;
|
||||
readonly pendingType?: PendingType;
|
||||
|
||||
constructor(
|
||||
file: IFile,
|
||||
@ -157,6 +161,8 @@ export class File extends Entity<IFile> implements IFile {
|
||||
file.fileAttributes && file.fileAttributes.attributeIdToValue ? file.fileAttributes : { attributeIdToValue: {} };
|
||||
|
||||
this.processingType = this.#processingType;
|
||||
this.errorCode = this.isError ? file.fileErrorInfo?.errorCode : undefined;
|
||||
this.pendingType = this.processingType === ProcessingTypes.pending ? this.#pendingType : undefined;
|
||||
}
|
||||
|
||||
get deleted(): boolean {
|
||||
@ -176,6 +182,13 @@ export class File extends Entity<IFile> implements IFile {
|
||||
return this.canBeOpened ? `/main/${this.dossierTemplateId}/${routerPath}/${this.dossierId}/file/${this.fileId}` : undefined;
|
||||
}
|
||||
|
||||
get #pendingType(): PendingType | undefined {
|
||||
if (this.errorCode === FileErrorCodes.RULES_EXECUTION_TIMEOUT) {
|
||||
return PendingTypes.timeout;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
get #processingType(): ProcessingType {
|
||||
if (PENDING_STATES.includes(this.processingStatus)) {
|
||||
return ProcessingTypes.pending;
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
* Object containing information on a specific file.
|
||||
*/
|
||||
import { FileAttributes } from '../file-attributes';
|
||||
import { ProcessingFileStatus, WorkflowFileStatus } from './types';
|
||||
import { FileErrorInfo, ProcessingFileStatus, WorkflowFileStatus } from './types';
|
||||
|
||||
export interface IFile {
|
||||
/**
|
||||
@ -147,4 +147,5 @@ export interface IFile {
|
||||
readonly fileManipulationDate: string | null;
|
||||
readonly redactionModificationDate: string | null;
|
||||
readonly lastManualChangeDate?: string;
|
||||
readonly fileErrorInfo?: FileErrorInfo;
|
||||
}
|
||||
|
||||
@ -96,3 +96,18 @@ export const PROCESSING_STATES: ProcessingFileStatus[] = [
|
||||
export const PROCESSED_STATES: ProcessingFileStatus[] = [ProcessingFileStatuses.PROCESSED];
|
||||
|
||||
export const OCR_STATES: ProcessingFileStatus[] = [ProcessingFileStatuses.OCR_PROCESSING, ProcessingFileStatuses.OCR_PROCESSING_QUEUED];
|
||||
|
||||
export const FileErrorCodes = {
|
||||
RULES_EXECUTION_TIMEOUT: 'RULES_EXECUTION_TIMEOUT',
|
||||
LOCKED_RULES: 'LOCKED_RULES',
|
||||
} as const;
|
||||
|
||||
export type FileErrorCode = keyof typeof FileErrorCodes;
|
||||
|
||||
export interface FileErrorInfo {
|
||||
cause: string;
|
||||
queue: string;
|
||||
service: string;
|
||||
timestamp: string;
|
||||
errorCode?: FileErrorCode;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user