Dossier listing

This commit is contained in:
Adina Țeudan 2021-08-27 20:18:51 +03:00
parent 31dff7aad5
commit ce113ce464
6 changed files with 131 additions and 138 deletions

View File

@ -29,11 +29,8 @@
[noDataIcon]="'red:dictionary'"
[noDataText]="'dictionary-listing.no-data.title' | translate"
[noMatchText]="'dictionary-listing.no-match.title' | translate"
[routerLinkFn]="routerLinkFn"
[selectionEnabled]="true"
[showNoDataButton]="currentUser.isAdmin"
[tableColumnConfigs]="tableColumnConfigs"
[tableHeaderLabel]="tableHeaderLabel"
emptyColumnWidth="1fr"
></iqser-table>
</div>

View File

@ -19,10 +19,7 @@
[noDataIcon]="'red:template'"
[noDataText]="'dossier-templates-listing.no-data.title' | translate"
[noMatchText]="'dossier-templates-listing.no-match.title' | translate"
[routerLinkFn]="routerLinkFn"
[selectionEnabled]="true"
[tableColumnConfigs]="tableColumnConfigs"
[tableHeaderLabel]="tableHeaderLabel"
></iqser-table>
</div>
</div>

View File

@ -8,76 +8,16 @@
<div class="red-content-inner">
<div class="content-container">
<iqser-table-header [tableColumnConfigs]="tableColumnConfigs" [tableHeaderLabel]="tableHeaderLabel"></iqser-table-header>
<iqser-empty-state
(action)="openAddDossierDialog()"
*ngIf="entitiesService.noData$ | async"
[buttonLabel]="'dossier-listing.no-data.action' | translate"
[showButton]="currentUser.isManager"
[text]="'dossier-listing.no-data.title' | translate"
icon="red:folder"
></iqser-empty-state>
<iqser-empty-state *ngIf="noMatch$ | async" [text]="'dossier-listing.no-match.title' | translate"></iqser-empty-state>
<cdk-virtual-scroll-viewport #scrollViewport [itemSize]="itemSize" iqserHasScrollbar>
<div
*cdkVirtualFor="let dossier of sortedDisplayedEntities$ | async; trackBy: trackByPrimaryKey"
[class.pointer]="!!dossier"
[routerLink]="['/main/dossiers/' + dossier.dossierId.toString()]"
class="table-item"
>
<div class="filename">
<div [matTooltip]="dossier.dossierName" class="table-item-title heading" matTooltipPosition="above">
{{ dossier.dossierName }}
</div>
<div class="small-label stats-subtitle">
<div>
<mat-icon svgIcon="red:template"></mat-icon>
{{ dossier.dossierTemplateName }}
</div>
</div>
<div class="small-label stats-subtitle">
<div>
<mat-icon svgIcon="red:document"></mat-icon>
{{ dossier.filesLength }}
</div>
<div>
<mat-icon svgIcon="red:pages"></mat-icon>
{{ dossier.totalNumberOfPages }}
</div>
<div>
<mat-icon svgIcon="red:user"></mat-icon>
{{ dossier.memberCount }}
</div>
<div>
<mat-icon svgIcon="red:calendar"></mat-icon>
{{ dossier.date | date: 'mediumDate' }}
</div>
<div *ngIf="dossier.dueDate">
<mat-icon svgIcon="red:lightning"></mat-icon>
{{ dossier.dueDate | date: 'mediumDate' }}
</div>
</div>
</div>
<div>
<redaction-needs-work-badge [needsWorkInput]="dossier"></redaction-needs-work-badge>
</div>
<div class="user-column">
<redaction-initials-avatar [userId]="dossier.ownerId" [withName]="true"></redaction-initials-avatar>
</div>
<div class="status-container">
<redaction-dossier-listing-actions
(actionPerformed)="calculateData()"
[dossier]="dossier"
></redaction-dossier-listing-actions>
</div>
<div class="scrollbar-placeholder"></div>
</div>
</cdk-virtual-scroll-viewport>
<iqser-scroll-button [itemSize]="itemSize" [scrollViewport]="scrollViewport"></iqser-scroll-button>
<iqser-table
(noDataAction)="openAddDossierDialog()"
[hasScrollButton]="true"
[itemSize]="85"
[noDataButtonLabel]="'dossier-listing.no-data.action' | translate"
[noDataIcon]="'red:folder'"
[noDataText]="'dossier-listing.no-data.title' | translate"
[noMatchText]="'dossier-listing.no-match.title' | translate"
[showNoDataButton]="currentUser.isManager"
></iqser-table>
</div>
<div class="right-container" iqserHasScrollbar>
@ -90,6 +30,60 @@
</div>
</section>
<ng-template #needsWorkTemplate let-filter="filter">
<ng-template #needsWorkFilterTemplate let-filter="filter">
<redaction-type-filter [filter]="filter"></redaction-type-filter>
</ng-template>
<ng-template #nameTemplate let-dossier="entity">
<div class="cell">
<div [matTooltip]="dossier.dossierName" class="table-item-title heading" matTooltipPosition="above">
{{ dossier.dossierName }}
</div>
<div class="small-label stats-subtitle">
<div>
<mat-icon svgIcon="red:template"></mat-icon>
{{ dossier.dossierTemplateName }}
</div>
</div>
<div class="small-label stats-subtitle">
<div>
<mat-icon svgIcon="red:document"></mat-icon>
{{ dossier.filesLength }}
</div>
<div>
<mat-icon svgIcon="red:pages"></mat-icon>
{{ dossier.totalNumberOfPages }}
</div>
<div>
<mat-icon svgIcon="red:user"></mat-icon>
{{ dossier.memberCount }}
</div>
<div>
<mat-icon svgIcon="red:calendar"></mat-icon>
{{ dossier.date | date: 'mediumDate' }}
</div>
<div *ngIf="dossier.dueDate">
<mat-icon svgIcon="red:lightning"></mat-icon>
{{ dossier.dueDate | date: 'mediumDate' }}
</div>
</div>
</div>
</ng-template>
<ng-template #needsWorkTemplate let-dossier="entity">
<div class="cell">
<redaction-needs-work-badge [needsWorkInput]="dossier"></redaction-needs-work-badge>
</div>
</ng-template>
<ng-template #ownerTemplate let-dossier="entity">
<div class="cell user-column">
<redaction-initials-avatar [userId]="dossier.ownerId" [withName]="true"></redaction-initials-avatar>
</div>
</ng-template>
<ng-template #statusTemplate let-dossier="entity">
<div class="cell status-container">
<redaction-dossier-listing-actions (actionPerformed)="calculateData()" [dossier]="dossier"></redaction-dossier-listing-actions>
</div>
</ng-template>

View File

@ -1,37 +1,23 @@
@import '../../../../../assets/styles/variables';
.content-container {
position: relative;
cdk-virtual-scroll-viewport {
::ng-deep.cdk-virtual-scroll-content-wrapper {
grid-template-columns: 2fr 1fr 1fr auto 11px;
.table-item .status-container {
width: 160px;
padding-right: 13px;
}
:host {
::ng-deep iqser-table cdk-virtual-scroll-viewport .cdk-virtual-scroll-content-wrapper .table-item > div.cell {
&.status-container {
width: 160px;
padding-right: 13px;
}
}
.right-container {
display: flex;
width: 466px;
min-width: 466px;
padding-right: 11px;
&.has-scrollbar:hover {
::ng-deep.cdk-virtual-scroll-content-wrapper {
grid-template-columns: 2fr 1fr 1fr auto;
}
padding-right: 0;
}
redaction-dossier-listing-details {
min-width: 466px;
}
}
}
.right-container {
display: flex;
width: 466px;
min-width: 466px;
padding-right: 11px;
&.has-scrollbar:hover {
padding-right: 0;
}
redaction-dossier-listing-details {
min-width: 466px;
}
}

View File

@ -1,4 +1,4 @@
import { AfterViewInit, Component, Injector, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { AfterViewInit, Component, forwardRef, Injector, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { Dossier } from '@redaction/red-ui-http';
import { AppStateService } from '@state/app-state.service';
import { UserService } from '@services/user.service';
@ -16,18 +16,17 @@ import { DossiersDialogService } from '../../services/dossiers-dialog.service';
import { OnAttach, OnDetach } from '@utils/custom-route-reuse.strategy';
import { UserPreferenceService } from '@services/user-preference.service';
import { ButtonConfig } from '@shared/components/page-header/models/button-config.model';
import { DefaultListingServices, ListingComponent, NestedFilter, TableColumnConfig } from '@iqser/common-ui';
import { DefaultListingServices, ListingComponent, NestedFilter, TableColumnConfig, TableComponent } from '@iqser/common-ui';
import { workloadTranslations } from '../../translations/workload-translations';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { fileStatusTranslations } from '../../translations/file-status-translations';
import { annotationFilterChecker, dossierMemberChecker, dossierStatusChecker, dossierTemplateChecker } from '@utils/filter-utils';
import { PermissionsService } from '@services/permissions.service';
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
@Component({
templateUrl: './dossier-listing-screen.component.html',
styleUrls: ['./dossier-listing-screen.component.scss'],
providers: [...DefaultListingServices]
providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => DossierListingScreenComponent) }]
})
export class DossierListingScreenComponent
extends ListingComponent<DossierWrapper>
@ -44,32 +43,21 @@ export class DossierListingScreenComponent
type: 'primary'
}
];
readonly tableColumnConfigs: readonly TableColumnConfig<DossierWrapper>[] = [
{
label: _('dossier-listing.table-col-names.name'),
sortByKey: 'dossierName'
},
{
label: _('dossier-listing.table-col-names.needs-work')
},
{
label: _('dossier-listing.table-col-names.owner'),
class: 'user-column'
},
{
label: _('dossier-listing.table-col-names.status'),
class: 'flex-end'
}
];
tableColumnConfigs: TableColumnConfig<DossierWrapper>[];
dossiersChartData: DoughnutChartConfig[] = [];
documentsChartData: DoughnutChartConfig[] = [];
readonly itemSize = 85;
@ViewChild('nameTemplate', { static: true }) nameTemplate: TemplateRef<never>;
@ViewChild('needsWorkTemplate', { static: true }) needsWorkTemplate: TemplateRef<never>;
@ViewChild('ownerTemplate', { static: true }) ownerTemplate: TemplateRef<never>;
@ViewChild('statusTemplate', { static: true }) statusTemplate: TemplateRef<never>;
protected readonly _primaryKey = 'dossierName';
private _lastScrolledIndex: number;
@ViewChild('needsWorkTemplate', { read: TemplateRef, static: true })
private readonly _needsWorkTemplate: TemplateRef<unknown>;
@ViewChild(CdkVirtualScrollViewport)
private readonly _scrollViewport: CdkVirtualScrollViewport;
@ViewChild('needsWorkFilterTemplate', {
read: TemplateRef,
static: true
})
private readonly _needsWorkFilterTemplate: TemplateRef<unknown>;
@ViewChild(TableComponent) private readonly _tableComponent: TableComponent<DossierWrapper>;
constructor(
private readonly _router: Router,
@ -95,7 +83,10 @@ export class DossierListingScreenComponent
return this.entitiesService.all.length - this._activeDossiersCount;
}
routerLinkFn = (dossier: DossierWrapper) => ['/main/dossiers/' + dossier.dossierId];
ngOnInit(): void {
this._setColumnConfig();
this.calculateData();
this.addSubscription = timer(0, 10000).subscribe(async () => {
@ -110,7 +101,9 @@ export class DossierListingScreenComponent
}
ngAfterViewInit(): void {
this.addSubscription = this._scrollViewport.scrolledIndexChange.pipe(tap(index => (this._lastScrolledIndex = index))).subscribe();
this.addSubscription = this._tableComponent.scrollViewport.scrolledIndexChange
.pipe(tap(index => (this._lastScrolledIndex = index)))
.subscribe();
}
ngOnAttach(): void {
@ -118,7 +111,7 @@ export class DossierListingScreenComponent
this._loadEntitiesFromState();
this.ngOnInit();
this.ngAfterViewInit();
this._scrollViewport.scrollToIndex(this._lastScrolledIndex, 'smooth');
this._tableComponent.scrollViewport.scrollToIndex(this._lastScrolledIndex, 'smooth');
}
ngOnDetach(): void {
@ -159,6 +152,32 @@ export class DossierListingScreenComponent
this.documentsChartData = this._translateChartService.translateStatus(this.documentsChartData);
}
private _setColumnConfig() {
this.tableColumnConfigs = [
{
label: _('dossier-listing.table-col-names.name'),
sortByKey: 'dossierName',
template: this.nameTemplate,
width: '2fr'
},
{
label: _('dossier-listing.table-col-names.needs-work'),
template: this.needsWorkTemplate
},
{
label: _('dossier-listing.table-col-names.owner'),
class: 'user-column',
template: this.ownerTemplate
},
{
label: _('dossier-listing.table-col-names.status'),
class: 'flex-end',
template: this.statusTemplate,
width: 'auto'
}
];
}
private _loadEntitiesFromState() {
this.entitiesService.setEntities(this._appStateService.allDossiers);
}
@ -230,7 +249,7 @@ export class DossierListingScreenComponent
slug: 'needsWorkFilters',
label: this._translateService.instant('filters.needs-work'),
icon: 'red:needs-work',
filterTemplate: this._needsWorkTemplate,
filterTemplate: this._needsWorkFilterTemplate,
filters: needsWorkFilters.sort(RedactionFilterSorter.byKey),
checker: annotationFilterChecker,
matchAll: true

@ -1 +1 @@
Subproject commit b1e1bc3f1a95ae53c30485a3f2ac044d71255c00
Subproject commit 704ea8221e6a6a198811c91f2a5fd15ed25c46da