RED-5289 - Docs/Pages switch in dossier stats
This commit is contained in:
parent
1e741ce67e
commit
764525af7e
@ -24,7 +24,7 @@
|
||||
[config]="chartConfig"
|
||||
[radius]="63"
|
||||
[strokeWidth]="15"
|
||||
[subtitle]="'user-stats.chart.users' | translate"
|
||||
[subtitles]="['user-stats.chart.users' | translate]"
|
||||
direction="row"
|
||||
filterKey="roleFilters"
|
||||
totalType="sum"
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
[config]="chartConfig"
|
||||
[radius]="80"
|
||||
[strokeWidth]="15"
|
||||
[subtitle]="'dossier-states-listing.chart.dossier-states' | translate: { count: chartConfig.length }"
|
||||
[subtitles]="['dossier-states-listing.chart.dossier-states' | translate: { count: chartConfig.length }]"
|
||||
[totalType]="'simpleLabel'"
|
||||
></redaction-donut-chart>
|
||||
</div>
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
[config]="translateChartService.translateDossierStates(dossierTemplate.dossiersChartConfig, dossierTemplate.id)"
|
||||
[radius]="63"
|
||||
[strokeWidth]="15"
|
||||
[subtitle]="'dossier-template-stats.active-dossiers' | translate: { count: dossierTemplate.numberOfActiveDossiers }"
|
||||
[subtitles]="['dossier-template-stats.active-dossiers' | translate: { count: dossierTemplate.numberOfActiveDossiers }]"
|
||||
direction="row"
|
||||
totalType="sum"
|
||||
></redaction-donut-chart>
|
||||
@ -52,7 +52,7 @@
|
||||
[config]="translateChartService.translateWorkflowStatus(dossierTemplate.documentsChartConfig)"
|
||||
[radius]="63"
|
||||
[strokeWidth]="15"
|
||||
[subtitle]="'dossier-template-stats.total-documents' | translate"
|
||||
[subtitles]="['dossier-template-stats.total-documents' | translate]"
|
||||
direction="row"
|
||||
totalType="sum"
|
||||
></redaction-donut-chart>
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
<ng-container *ngIf="dossier$ | async as dossier">
|
||||
<ng-container *ngIf="componentContext$ | async as ctx">
|
||||
<div class="collapsed-wrapper">
|
||||
<ng-container *ngTemplateOutlet="collapsible; context: { action: 'expand', tooltip: (expandTooltip | translate) }"></ng-container>
|
||||
<div class="all-caps-label" translate="dossier-details.title"></div>
|
||||
</div>
|
||||
|
||||
<div class="header-wrapper mt-8">
|
||||
<div class="heading-xl flex-1" id="dossierDetailsDossierName">{{ dossier.dossierName }}</div>
|
||||
<div class="heading-xl flex-1" id="dossierDetailsDossierName">{{ ctx.dossier?.dossierName }}</div>
|
||||
<ng-container
|
||||
*ngTemplateOutlet="collapsible; context: { action: 'collapse', tooltip: (collapseTooltip | translate) }"
|
||||
></ng-container>
|
||||
@ -15,7 +15,7 @@
|
||||
<div class="all-caps-label" translate="dossier-details.owner"></div>
|
||||
<div class="mt-12 d-flex">
|
||||
<ng-container *ngIf="!editingOwner; else editOwner">
|
||||
<iqser-initials-avatar [user]="dossier.ownerId" [withName]="true" color="gray" size="large"></iqser-initials-avatar>
|
||||
<iqser-initials-avatar [user]="ctx.dossier?.ownerId" [withName]="true" color="gray" size="large"></iqser-initials-avatar>
|
||||
|
||||
<iqser-circle-button
|
||||
(action)="editingOwner = true"
|
||||
@ -32,23 +32,31 @@
|
||||
|
||||
<div class="mt-16">
|
||||
<div class="all-caps-label" translate="dossier-details.members"></div>
|
||||
<redaction-team-members [dossierId]="dossier.dossierId" [memberIds]="dossier.memberIds" [perLine]="9"></redaction-team-members>
|
||||
<redaction-team-members
|
||||
[dossierId]="ctx.dossier?.dossierId"
|
||||
[memberIds]="ctx.dossier?.memberIds"
|
||||
[perLine]="9"
|
||||
></redaction-team-members>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="dossierStats$ | async as stats">
|
||||
<ng-container *ngIf="ctx.dossierStats as stats">
|
||||
<div *ngIf="stats.hasFiles" class="mt-24">
|
||||
<redaction-donut-chart
|
||||
[config]="chartConfig$ | async"
|
||||
[config]="chartConfig"
|
||||
[filterKey]="'statusFilters'"
|
||||
[helpModeKey]="'filter_document_list'"
|
||||
[radius]="63"
|
||||
[strokeWidth]="15"
|
||||
[subtitle]="'dossier-overview.dossier-details.charts.documents-in-dossier' | translate"
|
||||
[subtitles]="[
|
||||
'dossier-overview.dossier-details.charts.documents-in-dossier' | translate,
|
||||
'dossier-overview.dossier-details.charts.pages-in-dossier' | translate
|
||||
]"
|
||||
(subtitleChanged)="onSubtitleChanged($event)"
|
||||
direction="row"
|
||||
></redaction-donut-chart>
|
||||
</div>
|
||||
|
||||
<div *ngIf="statusConfig$ | async as statusConfig" class="mt-24">
|
||||
<div *ngIf="ctx.statusConfig as statusConfig" class="mt-24">
|
||||
<iqser-progress-bar
|
||||
*ngFor="let config of statusConfig"
|
||||
[config]="config"
|
||||
@ -57,26 +65,25 @@
|
||||
></iqser-progress-bar>
|
||||
</div>
|
||||
|
||||
<div
|
||||
*ngIf="stats.hasFiles && needsWorkFilters$ | async as filters"
|
||||
[iqserHelpMode]="'dashboard_in_dossier'"
|
||||
class="mt-32 legend pb-32"
|
||||
>
|
||||
<div *ngIf="stats.hasFiles && ctx.needsWorkFilters as filters" [iqserHelpMode]="'dashboard_in_dossier'" class="mt-32 legend pb-32">
|
||||
<div
|
||||
(click)="filterService.toggleFilter('needsWorkFilters', filter.id)"
|
||||
*ngFor="let filter of filters"
|
||||
[class.active]="filter.checked"
|
||||
>
|
||||
<redaction-type-filter [dossierTemplateId]="dossier.dossierTemplateId" [filter]="filter"></redaction-type-filter>
|
||||
<redaction-type-filter [dossierTemplateId]="ctx.dossier?.dossierTemplateId" [filter]="filter"></redaction-type-filter>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div [class.mt-24]="!stats.hasFiles" class="pb-32">
|
||||
<redaction-dossier-details-stats [dossierAttributes]="dossierAttributes" [dossier]="dossier"></redaction-dossier-details-stats>
|
||||
<redaction-dossier-details-stats
|
||||
[dossierAttributes]="dossierAttributes"
|
||||
[dossier]="ctx.dossier"
|
||||
></redaction-dossier-details-stats>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<div *ngIf="dossier.description as description" class="pb-32">
|
||||
<div *ngIf="ctx.dossier?.description as description" class="pb-32">
|
||||
<div class="heading" translate="dossier-overview.dossier-details.description"></div>
|
||||
<div class="mt-8">{{ description }}</div>
|
||||
</div>
|
||||
@ -84,9 +91,9 @@
|
||||
<ng-template #editOwner>
|
||||
<redaction-assign-user-dropdown
|
||||
(cancel)="editingOwner = false"
|
||||
(save)="editingOwner = false; assignOwner($event, dossier)"
|
||||
(save)="editingOwner = false; assignOwner($event, ctx.dossier)"
|
||||
[options]="managers"
|
||||
[value]="dossier.ownerId"
|
||||
[value]="ctx.dossier?.ownerId"
|
||||
></redaction-assign-user-dropdown>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import {
|
||||
DonutChartConfig,
|
||||
Dossier,
|
||||
DOSSIER_ID,
|
||||
DossierAttributeWithValue,
|
||||
DossierStats,
|
||||
File,
|
||||
IDossierRequest,
|
||||
ProcessingTypes,
|
||||
StatusSorter,
|
||||
@ -12,13 +13,22 @@ import {
|
||||
} from '@red/domain';
|
||||
import { TranslateChartService } from '@services/translate-chart.service';
|
||||
import { UserService } from '@users/user.service';
|
||||
import { FilterService, getParam, ProgressBarConfigModel, shareLast, Toaster } from '@iqser/common-ui';
|
||||
import { ContextComponent, FilterService, getParam, INestedFilter, ProgressBarConfigModel, shareLast, Toaster } from '@iqser/common-ui';
|
||||
import { workflowFileStatusTranslations } from '@translations/file-status-translations';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { firstValueFrom, Observable } from 'rxjs';
|
||||
import { firstValueFrom, Observable, of } from 'rxjs';
|
||||
import { DossierStatsService } from '@services/dossiers/dossier-stats.service';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { DossiersService } from '@services/dossiers/dossiers.service';
|
||||
import { FilesMapService } from '@services/files/files-map.service';
|
||||
|
||||
interface DossierDetailsContext {
|
||||
needsWorkFilters: INestedFilter[] | undefined;
|
||||
dossier: Dossier;
|
||||
dossierStats: DossierStats;
|
||||
chartConfig: void;
|
||||
statusConfig: ProgressBarConfigModel[];
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-dossier-details',
|
||||
@ -26,36 +36,52 @@ import { DossiersService } from '@services/dossiers/dossiers.service';
|
||||
styleUrls: ['./dossier-details.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class DossierDetailsComponent {
|
||||
export class DossierDetailsComponent extends ContextComponent<DossierDetailsContext> implements OnInit {
|
||||
@Input() dossierAttributes: DossierAttributeWithValue[];
|
||||
@Output() readonly toggleCollapse = new EventEmitter();
|
||||
|
||||
editingOwner = false;
|
||||
#currentChartSubtitleIndex = 0;
|
||||
|
||||
readonly #dossierId: string;
|
||||
readonly collapseTooltip = _('dossier-details.collapse');
|
||||
readonly expandTooltip = _('dossier-details.expand');
|
||||
readonly needsWorkFilters$ = this.filterService.getFilterModels$('needsWorkFilters');
|
||||
readonly currentUser = this._userService.currentUser;
|
||||
readonly dossier$: Observable<Dossier>;
|
||||
readonly dossierStats$: Observable<DossierStats>;
|
||||
readonly chartConfig$: Observable<DonutChartConfig[]>;
|
||||
readonly chartConfig$: Observable<void>;
|
||||
readonly statusConfig$: Observable<ProgressBarConfigModel[]>;
|
||||
|
||||
chartConfig: DonutChartConfig[] = [];
|
||||
|
||||
constructor(
|
||||
private readonly _toaster: Toaster,
|
||||
readonly filterService: FilterService,
|
||||
dossierStatsService: DossierStatsService,
|
||||
private readonly _userService: UserService,
|
||||
private readonly _dossiersService: DossiersService,
|
||||
private readonly _filesMapService: FilesMapService,
|
||||
readonly dossierStatsService: DossierStatsService,
|
||||
readonly filterService: FilterService,
|
||||
readonly translateChartService: TranslateChartService,
|
||||
) {
|
||||
const dossierId = getParam(DOSSIER_ID);
|
||||
this.dossier$ = _dossiersService.getEntityChanged$(dossierId).pipe(shareLast());
|
||||
this.dossierStats$ = dossierStatsService.watch$(dossierId).pipe(shareLast());
|
||||
super();
|
||||
this.#dossierId = getParam(DOSSIER_ID);
|
||||
this.dossier$ = _dossiersService.getEntityChanged$(this.#dossierId).pipe(shareLast());
|
||||
this.dossierStats$ = dossierStatsService.watch$(this.#dossierId).pipe(shareLast());
|
||||
this.chartConfig$ = this.dossierStats$.pipe(map(stats => this.#calculateChartConfig(stats)));
|
||||
this.statusConfig$ = this.dossierStats$.pipe(map(stats => this.#calculateStatusConfig(stats)));
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
super._initContext({
|
||||
needsWorkFilters: this.needsWorkFilters$,
|
||||
dossier: this.dossier$,
|
||||
dossierStats: this.dossierStats$,
|
||||
chartConfig: this.chartConfig$,
|
||||
statusConfig: this.statusConfig$,
|
||||
});
|
||||
}
|
||||
|
||||
get managers() {
|
||||
return this._userService.managerUsers.map(manager => manager.id);
|
||||
}
|
||||
@ -70,15 +96,24 @@ export class DossierDetailsComponent {
|
||||
this._toaster.info(_('assignment.owner'), { params: { ownerName, dossierName } });
|
||||
}
|
||||
|
||||
#calculateChartConfig(stats: DossierStats): DonutChartConfig[] {
|
||||
#calculateChartConfig(stats: DossierStats): void {
|
||||
const documentsChartConfig: DonutChartConfig[] = Object.keys(stats.fileCountPerWorkflowStatus).map(status => ({
|
||||
value: stats.fileCountPerWorkflowStatus[status],
|
||||
value: !this.#currentChartSubtitleIndex
|
||||
? stats.fileCountPerWorkflowStatus[status]
|
||||
: this.#getPageCountPerWorkflowStatus(status),
|
||||
color: status,
|
||||
label: workflowFileStatusTranslations[status],
|
||||
key: status,
|
||||
}));
|
||||
documentsChartConfig.sort((a, b) => StatusSorter.byStatus(a.key, b.key));
|
||||
return this.translateChartService.translateLabels(documentsChartConfig);
|
||||
this.chartConfig = this.translateChartService.translateLabels(documentsChartConfig);
|
||||
}
|
||||
|
||||
#getPageCountPerWorkflowStatus(status: string) {
|
||||
const files = this._filesMapService.get(this.#dossierId);
|
||||
return files
|
||||
.filter((file: File) => file.workflowStatus === status)
|
||||
.reduce((sum: number, file: File) => sum + file.numberOfPages, 0);
|
||||
}
|
||||
|
||||
#calculateStatusConfig(stats: DossierStats): ProgressBarConfigModel[] {
|
||||
@ -113,4 +148,9 @@ export class DossierDetailsComponent {
|
||||
},
|
||||
].filter(config => config.count > 0);
|
||||
}
|
||||
|
||||
onSubtitleChanged(subtitleIndex: number) {
|
||||
this.#currentChartSubtitleIndex = subtitleIndex;
|
||||
this.#calculateChartConfig(this.dossierStatsService.get(this.#dossierId));
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
[config]="dossiersChartConfig$ | async"
|
||||
[radius]="80"
|
||||
[strokeWidth]="15"
|
||||
[subtitle]="'dossier-template-stats.active-dossiers' | translate: { count: stats.numberOfActiveDossiers }"
|
||||
[subtitles]="['dossier-template-stats.active-dossiers' | translate: { count: stats.numberOfActiveDossiers }]"
|
||||
filterKey="dossierStatesFilters"
|
||||
></redaction-donut-chart>
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
[config]="documentsChartConfig$ | async"
|
||||
[radius]="80"
|
||||
[strokeWidth]="15"
|
||||
[subtitle]="'dossier-template-stats.total-documents' | translate"
|
||||
[subtitles]="['dossier-template-stats.total-documents' | translate]"
|
||||
filterKey="statusFilters"
|
||||
></redaction-donut-chart>
|
||||
</div>
|
||||
|
||||
@ -15,6 +15,7 @@ export class IconsModule {
|
||||
'approved',
|
||||
'archive',
|
||||
'arrow-up',
|
||||
'arrow-down',
|
||||
'assign',
|
||||
'assign-me',
|
||||
'attribute',
|
||||
|
||||
@ -19,7 +19,14 @@
|
||||
|
||||
<div [style]="'height: ' + size + 'px; width: ' + size + 'px; padding: ' + (strokeWidth + 5) + 'px;'" class="text-container">
|
||||
<div class="heading-xl">{{ displayedDataTotal }}</div>
|
||||
<div class="mt-5">{{ subtitle }}</div>
|
||||
<div *ngIf="subtitles.length === 1" class="mt-5">{{ subtitles[0] }}</div>
|
||||
<mat-select
|
||||
*ngIf="subtitles.length > 1"
|
||||
[value]="subtitles[0]"
|
||||
(selectionChange)="subtitleChanged.emit(subtitles.indexOf($event.value))"
|
||||
>
|
||||
<mat-option *ngFor="let subtitle of subtitles" [value]="subtitle"> {{ subtitle }} </mat-option>
|
||||
</mat-select>
|
||||
</div>
|
||||
|
||||
<div [iqserHelpMode]="helpModeKey" class="breakdown-container">
|
||||
|
||||
@ -70,3 +70,18 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mat-select {
|
||||
width: unset;
|
||||
margin-top: 5px;
|
||||
margin-left: 10px;
|
||||
|
||||
::ng-deep .mat-select-value,
|
||||
::ng-deep .mat-select-arrow {
|
||||
color: var(--iqser-text);
|
||||
}
|
||||
|
||||
::ng-deep .mat-select-arrow {
|
||||
margin-top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Component, Input, OnChanges, OnInit, Optional } from '@angular/core';
|
||||
import { Component, EventEmitter, Input, OnChanges, OnInit, Optional, Output } from '@angular/core';
|
||||
import { DonutChartConfig } from '@red/domain';
|
||||
import { FilterService, get, INestedFilter, shareLast } from '@iqser/common-ui';
|
||||
import { Observable, of } from 'rxjs';
|
||||
@ -10,7 +10,7 @@ import { map } from 'rxjs/operators';
|
||||
styleUrls: ['./donut-chart.component.scss'],
|
||||
})
|
||||
export class DonutChartComponent implements OnChanges, OnInit {
|
||||
@Input() subtitle: string;
|
||||
@Input() subtitles: string[];
|
||||
@Input() config: DonutChartConfig[] = [];
|
||||
@Input() radius = 85;
|
||||
@Input() strokeWidth = 20;
|
||||
@ -20,6 +20,8 @@ export class DonutChartComponent implements OnChanges, OnInit {
|
||||
@Input() filterKey;
|
||||
@Input() helpModeKey;
|
||||
|
||||
@Output() readonly subtitleChanged = new EventEmitter<number>();
|
||||
|
||||
chartData: any[] = [];
|
||||
cx = 0;
|
||||
cy = 0;
|
||||
|
||||
@ -832,7 +832,8 @@
|
||||
"show-less": "weniger anzeigen"
|
||||
},
|
||||
"charts": {
|
||||
"documents-in-dossier": "Dokumente im Dossier"
|
||||
"documents-in-dossier": "Dokumente",
|
||||
"pages-in-dossier": ""
|
||||
},
|
||||
"description": "Beschreibung",
|
||||
"dictionary": "Dossier-Wörterbuch",
|
||||
|
||||
@ -832,7 +832,8 @@
|
||||
"show-less": "show less"
|
||||
},
|
||||
"charts": {
|
||||
"documents-in-dossier": "Documents in Dossier"
|
||||
"documents-in-dossier": "Documents",
|
||||
"pages-in-dossier": "Pages"
|
||||
},
|
||||
"description": "Description",
|
||||
"dictionary": "Dossier Dictionary",
|
||||
|
||||
14
apps/red-ui/src/assets/icons/general/arrow-down.svg
Normal file
14
apps/red-ui/src/assets/icons/general/arrow-down.svg
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="1280.000000pt" height="1280.000000pt" viewBox="0 0 1280.000000 1280.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.16, written by Peter Selinger 2001-2019
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,1280.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M3672 8198 c14 -18 631 -842 1373 -1830 741 -989 1351 -1798 1355
|
||||
-1798 4 0 614 809 1355 1798 742 988 1359 1812 1373 1830 l24 32 -2752 0
|
||||
-2752 0 24 -32z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 576 B |
Loading…
x
Reference in New Issue
Block a user