simplify sorting, add common config to base listing
This commit is contained in:
parent
9d92752655
commit
27de88ac57
@ -88,7 +88,7 @@
|
||||
<div
|
||||
(mouseenter)="setHoveredColumn.emit(field.csvColumn)"
|
||||
(mouseleave)="setHoveredColumn.emit()"
|
||||
*cdkVirtualFor="let field of displayedEntities$ | async"
|
||||
*cdkVirtualFor="let field of displayedEntities$ | async; trackBy: trackByPrimaryKey"
|
||||
class="table-item"
|
||||
>
|
||||
<div (click)="toggleEntitySelected($event, field)" class="selection-column">
|
||||
|
||||
@ -20,6 +20,7 @@ export class ActiveFieldsListingComponent extends BaseListingComponent<Field> im
|
||||
@Output() toggleFieldActive = new EventEmitter<Field>();
|
||||
|
||||
readonly typeOptions = [FileAttributeConfig.TypeEnum.TEXT, FileAttributeConfig.TypeEnum.NUMBER, FileAttributeConfig.TypeEnum.DATE];
|
||||
protected readonly _primaryKey = 'id';
|
||||
|
||||
constructor(protected readonly _injector: Injector) {
|
||||
super(_injector);
|
||||
|
||||
@ -101,7 +101,7 @@
|
||||
(click)="toggleFieldActive(field)"
|
||||
(mouseenter)="setHoveredColumn(field.csvColumn)"
|
||||
(mouseleave)="setHoveredColumn()"
|
||||
*ngFor="let field of displayedEntities$ | async"
|
||||
*ngFor="let field of displayedEntities$ | async; trackBy: trackByPrimaryKey"
|
||||
class="csv-header-pill-wrapper"
|
||||
>
|
||||
<div [class.selected]="isActive(field)" class="csv-header-pill">
|
||||
@ -109,7 +109,10 @@
|
||||
{{ field.csvColumn }}
|
||||
</div>
|
||||
<div class="secondary">
|
||||
<div class="entry-count small-label">{{ getEntries(field.csvColumn) }} entries</div>
|
||||
<div class="entry-count small-label">
|
||||
{{ getEntries(field.csvColumn) }}
|
||||
entries
|
||||
</div>
|
||||
<div class="sample small-label">Sample: {{ getSample(field.csvColumn) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -31,6 +31,8 @@ export interface Field {
|
||||
providers: [FilterService, SearchService, ScreenStateService, SortingService]
|
||||
})
|
||||
export class FileAttributesCsvImportDialogComponent extends BaseListingComponent<Field> {
|
||||
protected readonly _primaryKey = 'id';
|
||||
|
||||
csvFile: File;
|
||||
dossierTemplateId: string;
|
||||
parseResult: { data: any[]; errors: any[]; meta: any; fields: Field[] };
|
||||
@ -50,10 +52,10 @@ export class FileAttributesCsvImportDialogComponent extends BaseListingComponent
|
||||
private readonly _translateService: TranslateService,
|
||||
private readonly _toaster: Toaster,
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
public dialogRef: MatDialogRef<FileAttributesCsvImportDialogComponent>,
|
||||
readonly dialogRef: MatDialogRef<FileAttributesCsvImportDialogComponent>,
|
||||
protected readonly _injector: Injector,
|
||||
@Inject(MAT_DIALOG_DATA)
|
||||
public data: {
|
||||
readonly data: {
|
||||
csv: File;
|
||||
dossierTemplateId: string;
|
||||
existingConfiguration: FileAttributesConfig;
|
||||
|
||||
@ -22,10 +22,7 @@
|
||||
<div class="content-container">
|
||||
<div class="header-item">
|
||||
<span class="all-caps-label">
|
||||
{{
|
||||
'audit-screen.table-header.title'
|
||||
| translate: { length: logs?.totalHits || 0 }
|
||||
}}
|
||||
{{ 'audit-screen.table-header.title' | translate: { length: logs?.totalHits || 0 } }}
|
||||
</span>
|
||||
<div class="actions-wrapper">
|
||||
<redaction-pagination
|
||||
@ -37,10 +34,7 @@
|
||||
<div class="red-input-group w-150 mr-20">
|
||||
<mat-form-field class="no-label">
|
||||
<mat-select formControlName="category">
|
||||
<mat-option
|
||||
*ngFor="let category of categories"
|
||||
[value]="category"
|
||||
>
|
||||
<mat-option *ngFor="let category of categories" [value]="category">
|
||||
{{ 'audit-screen.categories.' + category | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
@ -56,10 +50,7 @@
|
||||
[withName]="true"
|
||||
size="small"
|
||||
></redaction-initials-avatar>
|
||||
<div
|
||||
*ngIf="filterForm.get('userId').value === ALL_USERS"
|
||||
[translate]="ALL_USERS"
|
||||
></div>
|
||||
<div *ngIf="filterForm.get('userId').value === ALL_USERS" [translate]="ALL_USERS"></div>
|
||||
</mat-select-trigger>
|
||||
<mat-option *ngFor="let userId of userIds" [value]="userId">
|
||||
<redaction-initials-avatar
|
||||
@ -68,26 +59,16 @@
|
||||
[withName]="true"
|
||||
size="small"
|
||||
></redaction-initials-avatar>
|
||||
<div
|
||||
*ngIf="userId === ALL_USERS"
|
||||
[translate]="ALL_USERS"
|
||||
></div>
|
||||
<div *ngIf="userId === ALL_USERS" [translate]="ALL_USERS"></div>
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="separator">·</div>
|
||||
<div class="red-input-group datepicker-wrapper mr-20">
|
||||
<input
|
||||
[matDatepicker]="fromPicker"
|
||||
formControlName="from"
|
||||
placeholder="dd/mm/yy"
|
||||
/>
|
||||
<input [matDatepicker]="fromPicker" formControlName="from" placeholder="dd/mm/yy" />
|
||||
<mat-datepicker-toggle [for]="fromPicker" matSuffix>
|
||||
<mat-icon
|
||||
matDatepickerToggleIcon
|
||||
svgIcon="red:calendar"
|
||||
></mat-icon>
|
||||
<mat-icon matDatepickerToggleIcon svgIcon="red:calendar"></mat-icon>
|
||||
</mat-datepicker-toggle>
|
||||
<mat-datepicker #fromPicker></mat-datepicker>
|
||||
</div>
|
||||
@ -95,16 +76,9 @@
|
||||
<div class="mr-20" translate="audit-screen.to"></div>
|
||||
|
||||
<div class="red-input-group datepicker-wrapper">
|
||||
<input
|
||||
[matDatepicker]="toPicker"
|
||||
formControlName="to"
|
||||
placeholder="dd/mm/yy"
|
||||
/>
|
||||
<input [matDatepicker]="toPicker" formControlName="to" placeholder="dd/mm/yy" />
|
||||
<mat-datepicker-toggle [for]="toPicker" matSuffix>
|
||||
<mat-icon
|
||||
matDatepickerToggleIcon
|
||||
svgIcon="red:calendar"
|
||||
></mat-icon>
|
||||
<mat-icon matDatepickerToggleIcon svgIcon="red:calendar"></mat-icon>
|
||||
</mat-datepicker-toggle>
|
||||
<mat-datepicker #toPicker></mat-datepicker>
|
||||
</div>
|
||||
@ -113,31 +87,18 @@
|
||||
</div>
|
||||
|
||||
<div class="table-header" redactionSyncWidth="table-item">
|
||||
<redaction-table-col-name
|
||||
column="message"
|
||||
label="audit-screen.table-col-names.message"
|
||||
></redaction-table-col-name>
|
||||
<redaction-table-col-name
|
||||
column="date"
|
||||
label="audit-screen.table-col-names.date"
|
||||
></redaction-table-col-name>
|
||||
<redaction-table-col-name column="message" label="audit-screen.table-col-names.message"></redaction-table-col-name>
|
||||
<redaction-table-col-name column="date" label="audit-screen.table-col-names.date"></redaction-table-col-name>
|
||||
<redaction-table-col-name
|
||||
class="user-column"
|
||||
column="user"
|
||||
label="audit-screen.table-col-names.user"
|
||||
></redaction-table-col-name>
|
||||
<redaction-table-col-name
|
||||
column="category"
|
||||
label="audit-screen.table-col-names.category"
|
||||
></redaction-table-col-name>
|
||||
<redaction-table-col-name column="category" label="audit-screen.table-col-names.category"></redaction-table-col-name>
|
||||
<div class="scrollbar-placeholder"></div>
|
||||
</div>
|
||||
|
||||
<redaction-empty-state
|
||||
*ngIf="!logs?.totalHits"
|
||||
icon="red:document"
|
||||
screen="audit-screen"
|
||||
></redaction-empty-state>
|
||||
<redaction-empty-state *ngIf="!logs?.totalHits" icon="red:document" screen="audit-screen"></redaction-empty-state>
|
||||
|
||||
<cdk-virtual-scroll-viewport [itemSize]="80" redactionHasScrollbar>
|
||||
<div *cdkVirtualFor="let log of logs?.data" class="table-item">
|
||||
@ -148,11 +109,7 @@
|
||||
{{ log.recordDate | date: 'd MMM. yyyy, hh:mm a' }}
|
||||
</div>
|
||||
<div class="user-column">
|
||||
<redaction-initials-avatar
|
||||
[userId]="log.userId"
|
||||
[withName]="true"
|
||||
size="small"
|
||||
></redaction-initials-avatar>
|
||||
<redaction-initials-avatar [userId]="log.userId" [withName]="true" size="small"></redaction-initials-avatar>
|
||||
</div>
|
||||
<div [translate]="'audit-screen.categories.' + log.category"></div>
|
||||
<div class="scrollbar-placeholder"></div>
|
||||
@ -162,7 +119,3 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<redaction-full-page-loading-indicator
|
||||
[displayed]="!viewReady"
|
||||
></redaction-full-page-loading-indicator>
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, OnDestroy } from '@angular/core';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { AuditControllerService, AuditResponse, AuditSearchRequest } from '@redaction/red-ui-http';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Moment } from 'moment';
|
||||
import { applyIntervalConstraints } from '@utils/date-inputs-utils';
|
||||
import { LoadingService } from '../../../../services/loading.service';
|
||||
import { AutoUnsubscribeComponent } from '../../../shared/base/auto-unsubscribe.component';
|
||||
|
||||
const PAGE_SIZE = 50;
|
||||
|
||||
@ -13,16 +14,14 @@ const PAGE_SIZE = 50;
|
||||
templateUrl: './audit-screen.component.html',
|
||||
styleUrls: ['./audit-screen.component.scss']
|
||||
})
|
||||
export class AuditScreenComponent {
|
||||
export class AuditScreenComponent extends AutoUnsubscribeComponent implements OnDestroy {
|
||||
readonly ALL_CATEGORIES = 'all-categories';
|
||||
readonly ALL_USERS = 'audit-screen.all-users';
|
||||
|
||||
filterForm: FormGroup;
|
||||
viewReady = false;
|
||||
categories: string[] = [];
|
||||
userIds: Set<string>;
|
||||
logs: AuditResponse;
|
||||
currentPage = 1;
|
||||
|
||||
private _previousFrom: Moment;
|
||||
private _previousTo: Moment;
|
||||
@ -31,8 +30,9 @@ export class AuditScreenComponent {
|
||||
readonly permissionsService: PermissionsService,
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
private readonly _auditControllerService: AuditControllerService,
|
||||
private readonly _translateService: TranslateService
|
||||
private readonly _loadingService: LoadingService
|
||||
) {
|
||||
super();
|
||||
this.filterForm = this._formBuilder.group({
|
||||
category: [this.ALL_CATEGORIES],
|
||||
userId: [this.ALL_USERS],
|
||||
@ -40,7 +40,7 @@ export class AuditScreenComponent {
|
||||
to: []
|
||||
});
|
||||
|
||||
this.filterForm.valueChanges.subscribe(value => {
|
||||
this.addSubscription = this.filterForm.valueChanges.subscribe(value => {
|
||||
if (!this._updateDateFilters(value)) {
|
||||
this._fetchData();
|
||||
}
|
||||
@ -61,16 +61,7 @@ export class AuditScreenComponent {
|
||||
}
|
||||
|
||||
private _updateDateFilters(value): boolean {
|
||||
if (
|
||||
applyIntervalConstraints(
|
||||
value,
|
||||
this._previousFrom,
|
||||
this._previousTo,
|
||||
this.filterForm,
|
||||
'from',
|
||||
'to'
|
||||
)
|
||||
) {
|
||||
if (applyIntervalConstraints(value, this._previousFrom, this._previousTo, this.filterForm, 'from', 'to')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -80,7 +71,7 @@ export class AuditScreenComponent {
|
||||
}
|
||||
|
||||
private _fetchData(page?: number) {
|
||||
this.viewReady = false;
|
||||
this._loadingService.start();
|
||||
const promises = [];
|
||||
const category = this.filterForm.get('category').value;
|
||||
const userId = this.filterForm.get('userId').value;
|
||||
@ -110,7 +101,7 @@ export class AuditScreenComponent {
|
||||
for (const id of this.logs.data.map(log => log.userId).filter(uid => !!uid)) {
|
||||
this.userIds.add(id);
|
||||
}
|
||||
this.viewReady = true;
|
||||
this._loadingService.stop();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,14 +22,12 @@
|
||||
<div class="content-container">
|
||||
<div class="header-item">
|
||||
<span class="all-caps-label">
|
||||
{{ 'default-colors-screen.table-header.title' | translate: { length: screenStateService.allEntitiesLength$ } }}
|
||||
{{ 'default-colors-screen.table-header.title' | translate: { length: screenStateService.allEntitiesLength$ | async } }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="table-header" redactionSyncWidth="table-item">
|
||||
<redaction-table-col-name
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[withSort]="true"
|
||||
column="key"
|
||||
label="default-colors-screen.table-col-names.key"
|
||||
@ -46,10 +44,7 @@
|
||||
|
||||
<cdk-virtual-scroll-viewport [itemSize]="80" redactionHasScrollbar>
|
||||
<!-- Table lines -->
|
||||
<div
|
||||
*cdkVirtualFor="let color of screenStateService.allEntities$ | async | sortBy: sortingOption.order:sortingOption.column"
|
||||
class="table-item"
|
||||
>
|
||||
<div *cdkVirtualFor="let color of sortedDisplayedEntities$ | async; trackBy: trackByPrimaryKey" class="table-item">
|
||||
<div>
|
||||
<div [translate]="'default-colors-screen.types.' + color.key" class="table-item-title heading"></div>
|
||||
</div>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Component, Injector, OnInit } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, Injector, OnInit } from '@angular/core';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { Colors, DictionaryControllerService } from '@redaction/red-ui-http';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
@ -8,12 +8,13 @@ import { LoadingService } from '@services/loading.service';
|
||||
import { FilterService } from '@shared/services/filter.service';
|
||||
import { SearchService } from '@shared/services/search.service';
|
||||
import { ScreenStateService } from '@shared/services/screen-state.service';
|
||||
import { ScreenNames, SortingService } from '@services/sorting.service';
|
||||
import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||
import { SortingOrders, SortingService } from '../../../../services/sorting.service';
|
||||
|
||||
@Component({
|
||||
templateUrl: './default-colors-screen.component.html',
|
||||
styleUrls: ['./default-colors-screen.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [FilterService, SearchService, ScreenStateService, SortingService]
|
||||
})
|
||||
export class DefaultColorsScreenComponent
|
||||
@ -24,6 +25,7 @@ export class DefaultColorsScreenComponent
|
||||
implements OnInit
|
||||
{
|
||||
private _colorsObj: Colors;
|
||||
protected readonly _primaryKey = 'key';
|
||||
|
||||
constructor(
|
||||
private readonly _appStateService: AppStateService,
|
||||
@ -35,7 +37,6 @@ export class DefaultColorsScreenComponent
|
||||
protected readonly _injector: Injector
|
||||
) {
|
||||
super(_injector);
|
||||
this.sortingService.setScreenName(ScreenNames.DEFAULT_COLORS);
|
||||
_appStateService.activateDossierTemplate(_activatedRoute.snapshot.params.dossierTemplateId);
|
||||
}
|
||||
|
||||
@ -52,9 +53,7 @@ export class DefaultColorsScreenComponent
|
||||
colorKey: color.key,
|
||||
dossierTemplateId: this._appStateService.activeDossierTemplateId
|
||||
},
|
||||
async () => {
|
||||
await this._loadColors();
|
||||
}
|
||||
async () => await this._loadColors()
|
||||
);
|
||||
}
|
||||
|
||||
@ -62,12 +61,12 @@ export class DefaultColorsScreenComponent
|
||||
this._loadingService.start();
|
||||
const data = await this._dictionaryControllerService.getColors(this._appStateService.activeDossierTemplateId).toPromise();
|
||||
this._colorsObj = data;
|
||||
this.screenStateService.setEntities(
|
||||
Object.keys(data).map(key => ({
|
||||
key,
|
||||
value: data[key]
|
||||
}))
|
||||
);
|
||||
const entities = Object.keys(data).map(key => ({
|
||||
key,
|
||||
value: data[key]
|
||||
}));
|
||||
this.screenStateService.setEntities(entities);
|
||||
this.screenStateService.setDisplayedEntities(entities);
|
||||
this._loadingService.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="openDeleteDictionariesDialog($event)"
|
||||
*ngIf="canBulkDelete$(permissionsService.isAdmin())"
|
||||
*ngIf="canBulkDelete$(permissionsService.isAdmin()) | async"
|
||||
icon="red:trash"
|
||||
tooltip="dictionary-listing.bulk.delete"
|
||||
type="dark-bg"
|
||||
@ -63,16 +63,12 @@
|
||||
<div class="select-oval-placeholder"></div>
|
||||
|
||||
<redaction-table-col-name
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[withSort]="true"
|
||||
column="label"
|
||||
label="dictionary-listing.table-col-names.type"
|
||||
></redaction-table-col-name>
|
||||
|
||||
<redaction-table-col-name
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[withSort]="true"
|
||||
class="flex-center"
|
||||
column="rank"
|
||||
@ -98,7 +94,11 @@
|
||||
<redaction-empty-state *ngIf="noMatch$ | async" screen="dictionary-listing" type="no-match"></redaction-empty-state>
|
||||
|
||||
<cdk-virtual-scroll-viewport [itemSize]="80" redactionHasScrollbar>
|
||||
<div *cdkVirtualFor="let dict of sortedDisplayedEntities$ | async" [routerLink]="[dict.type]" class="table-item pointer">
|
||||
<div
|
||||
*cdkVirtualFor="let dict of sortedDisplayedEntities$ | async; trackBy: trackByPrimaryKey"
|
||||
[routerLink]="[dict.type]"
|
||||
class="table-item pointer"
|
||||
>
|
||||
<div (click)="toggleEntitySelected($event, dict)" class="selection-column">
|
||||
<redaction-round-checkbox [active]="isSelected(dict)"></redaction-round-checkbox>
|
||||
</div>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Component, Injector, OnInit } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, Injector, OnInit } 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';
|
||||
@ -12,7 +12,7 @@ import { LoadingService } from '@services/loading.service';
|
||||
import { FilterService } from '@shared/services/filter.service';
|
||||
import { SearchService } from '@shared/services/search.service';
|
||||
import { ScreenStateService } from '@shared/services/screen-state.service';
|
||||
import { ScreenNames, SortingService } from '@services/sorting.service';
|
||||
import { SortingService } from '../../../../services/sorting.service';
|
||||
import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||
import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
|
||||
@ -31,6 +31,8 @@ const toChartConfig = (dict: TypeValueWrapper): DoughnutChartConfig => ({
|
||||
export class DictionaryListingScreenComponent extends BaseListingComponent<TypeValueWrapper> implements OnInit {
|
||||
chartData: DoughnutChartConfig[] = [];
|
||||
|
||||
protected readonly _primaryKey = 'label';
|
||||
|
||||
constructor(
|
||||
private readonly _dialogService: AdminDialogService,
|
||||
private readonly _dictionaryControllerService: DictionaryControllerService,
|
||||
@ -43,8 +45,6 @@ export class DictionaryListingScreenComponent extends BaseListingComponent<TypeV
|
||||
) {
|
||||
super(_injector);
|
||||
_loadingService.start();
|
||||
this.sortingService.setScreenName(ScreenNames.DOSSIER_LISTING);
|
||||
this.searchService.setSearchKey('label');
|
||||
_appStateService.activateDossierTemplate(_activatedRoute.snapshot.params.dossierTemplateId);
|
||||
}
|
||||
|
||||
|
||||
@ -4,20 +4,10 @@
|
||||
<redaction-admin-side-nav type="settings"></redaction-admin-side-nav>
|
||||
|
||||
<div>
|
||||
<div class="page-header">
|
||||
<div class="breadcrumb" translate="digital-signature"></div>
|
||||
|
||||
<div class="actions">
|
||||
<redaction-circle-button
|
||||
*ngIf="permissionsService.isUser()"
|
||||
class="ml-6"
|
||||
icon="red:close"
|
||||
redactionNavigateLastDossiersScreen
|
||||
tooltip="common.close"
|
||||
tooltipPosition="below"
|
||||
></redaction-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
<redaction-page-header
|
||||
[pageLabel]="'digital-signature' | translate"
|
||||
[showCloseButton]="permissionsService.isUser()"
|
||||
></redaction-page-header>
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="content-container">
|
||||
@ -111,5 +101,3 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<redaction-full-page-loading-indicator [displayed]="!viewReady"></redaction-full-page-loading-indicator>
|
||||
|
||||
@ -5,6 +5,7 @@ import { Toaster } from '../../../../services/toaster.service';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { lastIndexOfEnd } from '@utils/functions';
|
||||
import { AutoUnsubscribeComponent } from '../../../shared/base/auto-unsubscribe.component';
|
||||
import { LoadingService } from '../../../../services/loading.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-digital-signature-screen',
|
||||
@ -15,13 +16,13 @@ export class DigitalSignatureScreenComponent extends AutoUnsubscribeComponent im
|
||||
digitalSignature: DigitalSignature;
|
||||
digitalSignatureForm: FormGroup;
|
||||
|
||||
viewReady = false;
|
||||
digitalSignatureExists = false;
|
||||
|
||||
constructor(
|
||||
private readonly _digitalSignatureControllerService: DigitalSignatureControllerService,
|
||||
private readonly _toaster: Toaster,
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
private readonly _loadingService: LoadingService,
|
||||
readonly permissionsService: PermissionsService
|
||||
) {
|
||||
super();
|
||||
@ -82,7 +83,7 @@ export class DigitalSignatureScreenComponent extends AutoUnsubscribeComponent im
|
||||
}
|
||||
|
||||
loadDigitalSignatureAndInitializeForm() {
|
||||
this.viewReady = false;
|
||||
this._loadingService.start();
|
||||
this.addSubscription = this._digitalSignatureControllerService
|
||||
.getDigitalSignature()
|
||||
.subscribe(
|
||||
@ -97,7 +98,7 @@ export class DigitalSignatureScreenComponent extends AutoUnsubscribeComponent im
|
||||
)
|
||||
.add(() => {
|
||||
this._initForm();
|
||||
this.viewReady = true;
|
||||
this._loadingService.stop();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -65,16 +65,12 @@
|
||||
<div class="select-oval-placeholder"></div>
|
||||
|
||||
<redaction-table-col-name
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[withSort]="true"
|
||||
column="label"
|
||||
label="dossier-attributes-listing.table-col-names.label"
|
||||
></redaction-table-col-name>
|
||||
<redaction-table-col-name label="dossier-attributes-listing.table-col-names.placeholder"></redaction-table-col-name>
|
||||
<redaction-table-col-name
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[withSort]="true"
|
||||
column="type"
|
||||
label="dossier-attributes-listing.table-col-names.type"
|
||||
@ -94,7 +90,10 @@
|
||||
<redaction-empty-state *ngIf="noMatch$ | async" screen="dossier-attributes-listing" type="no-match"></redaction-empty-state>
|
||||
|
||||
<cdk-virtual-scroll-viewport [itemSize]="50" redactionHasScrollbar>
|
||||
<div *cdkVirtualFor="let attribute of sortedDisplayedEntities$ | async" class="table-item pointer">
|
||||
<div
|
||||
*cdkVirtualFor="let attribute of sortedDisplayedEntities$ | async; trackBy: trackByPrimaryKey"
|
||||
class="table-item pointer"
|
||||
>
|
||||
<div (click)="toggleEntitySelected($event, attribute)" class="selection-column">
|
||||
<redaction-round-checkbox [active]="isSelected(attribute)"></redaction-round-checkbox>
|
||||
</div>
|
||||
|
||||
@ -5,7 +5,7 @@ import { AppStateService } from '@state/app-state.service';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
import { LoadingService } from '@services/loading.service';
|
||||
import { ScreenNames, SortingService } from '@services/sorting.service';
|
||||
import { SortingService } from '../../../../services/sorting.service';
|
||||
import { FilterService } from '@shared/services/filter.service';
|
||||
import { SearchService } from '@shared/services/search.service';
|
||||
import { ScreenStateService } from '@shared/services/screen-state.service';
|
||||
@ -18,6 +18,8 @@ import { DossierAttributesService } from '@shared/services/controller-wrappers/d
|
||||
providers: [FilterService, SearchService, ScreenStateService, SortingService]
|
||||
})
|
||||
export class DossierAttributesListingScreenComponent extends BaseListingComponent<DossierAttributeConfig> implements OnInit {
|
||||
protected readonly _primaryKey = 'label';
|
||||
|
||||
constructor(
|
||||
protected readonly _injector: Injector,
|
||||
private readonly _appStateService: AppStateService,
|
||||
@ -28,8 +30,6 @@ export class DossierAttributesListingScreenComponent extends BaseListingComponen
|
||||
readonly permissionsService: PermissionsService
|
||||
) {
|
||||
super(_injector);
|
||||
this.searchService.setSearchKey('label');
|
||||
this.sortingService.setScreenName(ScreenNames.DOSSIER_ATTRIBUTES_LISTING);
|
||||
_appStateService.activateDossierTemplate(_activatedRoute.snapshot.params.dossierTemplateId);
|
||||
}
|
||||
|
||||
|
||||
@ -4,17 +4,10 @@
|
||||
<redaction-admin-side-nav type="settings"></redaction-admin-side-nav>
|
||||
|
||||
<div>
|
||||
<div class="page-header">
|
||||
<div class="breadcrumb" translate="dossier-templates"></div>
|
||||
|
||||
<redaction-circle-button
|
||||
*ngIf="permissionsService.isUser()"
|
||||
icon="red:close"
|
||||
redactionNavigateLastDossiersScreen
|
||||
tooltip="common.close"
|
||||
tooltipPosition="below"
|
||||
></redaction-circle-button>
|
||||
</div>
|
||||
<redaction-page-header
|
||||
[pageLabel]="'dossier-templates' | translate"
|
||||
[showCloseButton]="permissionsService.isUser()"
|
||||
></redaction-page-header>
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="content-container">
|
||||
@ -34,15 +27,13 @@
|
||||
}}
|
||||
</span>
|
||||
|
||||
<ng-container *ngIf="screenStateService.areSomeEntitiesSelected$ | async">
|
||||
<redaction-circle-button
|
||||
(action)="openDeleteTemplatesDialog($event)"
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
icon="red:trash"
|
||||
tooltip="dossier-templates-listing.bulk.delete"
|
||||
type="dark-bg"
|
||||
></redaction-circle-button>
|
||||
</ng-container>
|
||||
<redaction-circle-button
|
||||
(action)="openDeleteTemplatesDialog($event)"
|
||||
*ngIf="canBulkDelete$(permissionsService.isAdmin()) | async"
|
||||
icon="red:trash"
|
||||
tooltip="dossier-templates-listing.bulk.delete"
|
||||
type="dark-bg"
|
||||
></redaction-circle-button>
|
||||
|
||||
<div class="actions flex-1">
|
||||
<redaction-input-with-action
|
||||
@ -65,8 +56,6 @@
|
||||
<div class="select-oval-placeholder"></div>
|
||||
|
||||
<redaction-table-col-name
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[withSort]="true"
|
||||
column="name"
|
||||
label="dossier-templates-listing.table-col-names.name"
|
||||
@ -76,19 +65,16 @@
|
||||
label="dossier-templates-listing.table-col-names.created-by"
|
||||
></redaction-table-col-name>
|
||||
<redaction-table-col-name
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[withSort]="true"
|
||||
column="dateAdded"
|
||||
label="dossier-templates-listing.table-col-names.created-on"
|
||||
></redaction-table-col-name>
|
||||
<redaction-table-col-name
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[withSort]="true"
|
||||
column="dateModified"
|
||||
label="dossier-templates-listing.table-col-names.modified-on"
|
||||
></redaction-table-col-name>
|
||||
|
||||
<div class="scrollbar-placeholder"></div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -9,8 +9,8 @@ import { DossierTemplateControllerService } from '@redaction/red-ui-http';
|
||||
import { FilterService } from '@shared/services/filter.service';
|
||||
import { SearchService } from '@shared/services/search.service';
|
||||
import { ScreenStateService } from '@shared/services/screen-state.service';
|
||||
import { ScreenNames, SortingService } from '@services/sorting.service';
|
||||
import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||
import { SortingService } from '../../../../services/sorting.service';
|
||||
|
||||
@Component({
|
||||
templateUrl: './dossier-templates-listing-screen.component.html',
|
||||
@ -19,6 +19,8 @@ import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||
providers: [FilterService, SearchService, ScreenStateService, SortingService]
|
||||
})
|
||||
export class DossierTemplatesListingScreenComponent extends BaseListingComponent<DossierTemplateModelWrapper> implements OnInit {
|
||||
protected _primaryKey = 'name';
|
||||
|
||||
constructor(
|
||||
private readonly _dialogService: AdminDialogService,
|
||||
private readonly _appStateService: AppStateService,
|
||||
@ -29,8 +31,6 @@ export class DossierTemplatesListingScreenComponent extends BaseListingComponent
|
||||
readonly userPreferenceService: UserPreferenceService
|
||||
) {
|
||||
super(_injector);
|
||||
this.sortingService.setScreenName(ScreenNames.DOSSIER_TEMPLATES_LISTING);
|
||||
this.searchService.setSearchKey('name');
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
|
||||
<redaction-circle-button
|
||||
(click)="openConfirmDeleteAttributeDialog($event)"
|
||||
*ngIf="permissionsService.isAdmin() && screenStateService.areSomeEntitiesSelected$ | async"
|
||||
*ngIf="canBulkDelete$(permissionsService.isAdmin()) | async"
|
||||
icon="red:trash"
|
||||
tooltip="file-attributes-listing.bulk-actions.delete"
|
||||
type="dark-bg"
|
||||
@ -74,24 +74,18 @@
|
||||
<div class="select-oval-placeholder"></div>
|
||||
|
||||
<redaction-table-col-name
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[withSort]="true"
|
||||
column="label"
|
||||
label="file-attributes-listing.table-col-names.name"
|
||||
></redaction-table-col-name>
|
||||
|
||||
<redaction-table-col-name
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[withSort]="true"
|
||||
column="type"
|
||||
label="file-attributes-listing.table-col-names.type"
|
||||
></redaction-table-col-name>
|
||||
|
||||
<redaction-table-col-name
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[withSort]="true"
|
||||
class="flex-center"
|
||||
column="editable"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ChangeDetectionStrategy, Component, ElementRef, Injector, OnInit, ViewChild } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, ElementRef, Injector, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { FileAttributeConfig, FileAttributesConfig, FileAttributesControllerService } from '@redaction/red-ui-http';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
@ -8,7 +8,7 @@ import { LoadingService } from '@services/loading.service';
|
||||
import { FilterService } from '@shared/services/filter.service';
|
||||
import { SearchService } from '@shared/services/search.service';
|
||||
import { ScreenStateService } from '@shared/services/screen-state.service';
|
||||
import { ScreenNames, SortingService } from '@services/sorting.service';
|
||||
import { SortingService } from '../../../../services/sorting.service';
|
||||
import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||
|
||||
@Component({
|
||||
@ -17,7 +17,9 @@ import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [FilterService, SearchService, ScreenStateService, SortingService]
|
||||
})
|
||||
export class FileAttributesListingScreenComponent extends BaseListingComponent<FileAttributeConfig> implements OnInit {
|
||||
export class FileAttributesListingScreenComponent extends BaseListingComponent<FileAttributeConfig> implements OnInit, OnDestroy {
|
||||
protected readonly _primaryKey = 'label';
|
||||
|
||||
private _existingConfiguration: FileAttributesConfig;
|
||||
@ViewChild('fileInput') private _fileInput: ElementRef;
|
||||
|
||||
@ -31,8 +33,6 @@ export class FileAttributesListingScreenComponent extends BaseListingComponent<F
|
||||
protected readonly _injector: Injector
|
||||
) {
|
||||
super(_injector);
|
||||
this.sortingService.setScreenName(ScreenNames.FILE_ATTRIBUTES_LISTING);
|
||||
this.searchService.setSearchKey('label');
|
||||
_appStateService.activateDossierTemplate(_activatedRoute.snapshot.params.dossierTemplateId);
|
||||
}
|
||||
|
||||
|
||||
@ -3,27 +3,12 @@
|
||||
|
||||
<redaction-admin-side-nav type="settings"></redaction-admin-side-nav>
|
||||
|
||||
<div *ngIf="viewReady">
|
||||
<div class="page-header">
|
||||
<div class="breadcrumb" translate="license-information"></div>
|
||||
|
||||
<div class="actions">
|
||||
<button
|
||||
(click)="sendMail()"
|
||||
color="primary"
|
||||
mat-flat-button
|
||||
translate="license-info-screen.email-report"
|
||||
></button>
|
||||
<redaction-circle-button
|
||||
*ngIf="permissionsService.isUser()"
|
||||
class="ml-6"
|
||||
icon="red:close"
|
||||
redactionNavigateLastDossiersScreen
|
||||
tooltip="common.close"
|
||||
tooltipPosition="below"
|
||||
></redaction-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<redaction-page-header
|
||||
[pageLabel]="'license-information' | translate"
|
||||
[showCloseButton]="permissionsService.isUser()"
|
||||
[buttonConfigs]="buttonConfigs"
|
||||
></redaction-page-header>
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="content-container">
|
||||
@ -46,10 +31,7 @@
|
||||
<div class="row">
|
||||
<div translate="license-info-screen.copyright-claim-title"></div>
|
||||
<div>
|
||||
{{
|
||||
'license-info-screen.copyright-claim-text'
|
||||
| translate: { currentYear: currentYear }
|
||||
}}
|
||||
{{ 'license-info-screen.copyright-claim-text' | translate: { currentYear: currentYear } }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -64,10 +46,7 @@
|
||||
<!-- <div>Future feature: we will provide that with the /info endpoint</div>-->
|
||||
<!-- </div>-->
|
||||
|
||||
<div
|
||||
class="section-title all-caps-label"
|
||||
translate="license-info-screen.licensing-details"
|
||||
></div>
|
||||
<div class="section-title all-caps-label" translate="license-info-screen.licensing-details"></div>
|
||||
|
||||
<div class="row">
|
||||
<div translate="license-info-screen.licensed-to"></div>
|
||||
@ -92,28 +71,18 @@
|
||||
<div>{{ currentInfo.numberOfAnalyzedPages }}</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="section-title all-caps-label"
|
||||
translate="license-info-screen.usage-details"
|
||||
></div>
|
||||
<div class="section-title all-caps-label" translate="license-info-screen.usage-details"></div>
|
||||
|
||||
<div class="row">
|
||||
<div>
|
||||
{{
|
||||
'license-info-screen.total-analyzed'
|
||||
| translate: { date: totalInfo.startDate | date: 'longDate' }
|
||||
}}
|
||||
{{ 'license-info-screen.total-analyzed' | translate: { date: totalInfo.startDate | date: 'longDate' } }}
|
||||
</div>
|
||||
<div>{{ totalInfo.numberOfAnalyzedPages }}</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div translate="license-info-screen.current-analyzed"></div>
|
||||
<div>
|
||||
{{ currentInfo.numberOfAnalyzedPages }} ({{
|
||||
analysisPercentageOfLicense | number: '1.0-2'
|
||||
}}%)
|
||||
</div>
|
||||
<div>{{ currentInfo.numberOfAnalyzedPages }} ({{ analysisPercentageOfLicense | number: '1.0-2' }}%)</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="!!unlicensedInfo" class="row">
|
||||
@ -150,7 +119,3 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<redaction-full-page-loading-indicator
|
||||
[displayed]="!viewReady"
|
||||
></redaction-full-page-loading-indicator>
|
||||
|
||||
@ -4,6 +4,9 @@ import { LicenseReport, LicenseReportControllerService } from '@redaction/red-ui
|
||||
import { AppConfigService } from '@app-config/app-config.service';
|
||||
import * as moment from 'moment';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { LoadingService } from '../../../../services/loading.service';
|
||||
import { ButtonConfig } from '../../../shared/components/page-header/models/button-config.model';
|
||||
import { IconButtonTypes } from '../../../shared/components/buttons/icon-button/icon-button.component';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-license-information-screen',
|
||||
@ -16,7 +19,6 @@ export class LicenseInformationScreenComponent implements OnInit {
|
||||
unlicensedInfo: LicenseReport = {};
|
||||
totalLicensedNumberOfPages = 0;
|
||||
analysisPercentageOfLicense = 100;
|
||||
viewReady = false;
|
||||
barChart: any[] = [];
|
||||
lineChartSeries: any[] = [];
|
||||
yAxisLabel = this._translateService.instant('license-info-screen.chart.pages-per-month');
|
||||
@ -31,13 +33,23 @@ export class LicenseInformationScreenComponent implements OnInit {
|
||||
group: 'Ordinal',
|
||||
domain: ['#0389ec']
|
||||
};
|
||||
buttonConfigs: ButtonConfig[] = [
|
||||
{
|
||||
label: this._translateService.instant('license-info-screen.email-report'),
|
||||
action: () => this.sendMail(),
|
||||
type: IconButtonTypes.PRIMARY
|
||||
}
|
||||
];
|
||||
|
||||
constructor(
|
||||
readonly permissionsService: PermissionsService,
|
||||
readonly appConfigService: AppConfigService,
|
||||
private readonly _licenseReportController: LicenseReportControllerService,
|
||||
private readonly _translateService: TranslateService
|
||||
) {}
|
||||
private readonly _translateService: TranslateService,
|
||||
private readonly _loadingService: LoadingService
|
||||
) {
|
||||
_loadingService.start();
|
||||
}
|
||||
|
||||
get currentYear(): number {
|
||||
return new Date().getFullYear();
|
||||
@ -63,18 +75,15 @@ export class LicenseInformationScreenComponent implements OnInit {
|
||||
const unlicensedConfig = {
|
||||
startDate: endDate.toDate()
|
||||
};
|
||||
promises.push(
|
||||
this._licenseReportController.licenseReport(unlicensedConfig).toPromise()
|
||||
);
|
||||
promises.push(this._licenseReportController.licenseReport(unlicensedConfig).toPromise());
|
||||
}
|
||||
|
||||
Promise.all(promises).then(reports => {
|
||||
[this.currentInfo, this.totalInfo, this.unlicensedInfo] = reports;
|
||||
this.viewReady = true;
|
||||
this._loadingService.stop();
|
||||
this.analysisPercentageOfLicense =
|
||||
this.totalLicensedNumberOfPages > 0
|
||||
? (this.currentInfo.numberOfAnalyzedPages / this.totalLicensedNumberOfPages) *
|
||||
100
|
||||
? (this.currentInfo.numberOfAnalyzedPages / this.totalLicensedNumberOfPages) * 100
|
||||
: 100;
|
||||
});
|
||||
}
|
||||
@ -92,9 +101,7 @@ export class LicenseInformationScreenComponent implements OnInit {
|
||||
pages: this.totalLicensedNumberOfPages
|
||||
})
|
||||
].join('%0D%0A');
|
||||
window.location.href = `mailto:${this.appConfigService.getConfig(
|
||||
'LICENSE_EMAIL'
|
||||
)}?subject=${subject}&body=${body}`;
|
||||
window.location.href = `mailto:${this.appConfigService.getConfig('LICENSE_EMAIL')}?subject=${subject}&body=${body}`;
|
||||
}
|
||||
|
||||
private async _setMonthlyStats(startDate: moment.Moment, endDate: moment.Moment) {
|
||||
|
||||
@ -39,8 +39,6 @@
|
||||
<div class="select-oval-placeholder"></div>
|
||||
|
||||
<redaction-table-col-name
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[label]="'trash.table-col-names.name' | translate"
|
||||
[withSort]="true"
|
||||
column="name"
|
||||
@ -50,15 +48,11 @@
|
||||
class="user-column"
|
||||
></redaction-table-col-name>
|
||||
<redaction-table-col-name
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[label]="'trash.table-col-names.deleted-on' | translate"
|
||||
[withSort]="true"
|
||||
column="dateDeleted"
|
||||
></redaction-table-col-name>
|
||||
<redaction-table-col-name
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[label]="'trash.table-col-names.time-to-restore' | translate"
|
||||
[withSort]="true"
|
||||
column="timeToRestore"
|
||||
@ -71,7 +65,7 @@
|
||||
<redaction-empty-state *ngIf="noMatch$ | async" screen="trash" type="no-match"></redaction-empty-state>
|
||||
|
||||
<cdk-virtual-scroll-viewport [itemSize]="itemSize" redactionHasScrollbar>
|
||||
<div *cdkVirtualFor="let entity of sortedDisplayedEntities$ | async; trackBy: trackById" class="table-item">
|
||||
<div *cdkVirtualFor="let entity of sortedDisplayedEntities$ | async; trackBy: trackByPrimaryKey" class="table-item">
|
||||
<div (click)="toggleEntitySelected($event, entity)" class="selection-column">
|
||||
<redaction-round-checkbox [active]="isSelected(entity)"></redaction-round-checkbox>
|
||||
</div>
|
||||
|
||||
@ -8,7 +8,7 @@ import * as moment from 'moment';
|
||||
import { FilterService } from '@shared/services/filter.service';
|
||||
import { SearchService } from '@shared/services/search.service';
|
||||
import { ScreenStateService } from '@shared/services/screen-state.service';
|
||||
import { ScreenNames, SortingService } from '@services/sorting.service';
|
||||
import { SortingService } from '../../../../services/sorting.service';
|
||||
import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||
import { DossiersService } from '../../../dossier/services/dossiers.service';
|
||||
|
||||
@ -21,6 +21,7 @@ import { DossiersService } from '../../../dossier/services/dossiers.service';
|
||||
export class TrashScreenComponent extends BaseListingComponent<Dossier> implements OnInit {
|
||||
readonly itemSize = 85;
|
||||
private readonly _deleteRetentionHours = this._appConfigService.getConfig(AppConfigKey.DELETE_RETENTION_HOURS);
|
||||
protected readonly _primaryKey = 'dossierName';
|
||||
|
||||
constructor(
|
||||
private readonly _appStateService: AppStateService,
|
||||
@ -32,7 +33,6 @@ export class TrashScreenComponent extends BaseListingComponent<Dossier> implemen
|
||||
private readonly _appConfigService: AppConfigService
|
||||
) {
|
||||
super(_injector);
|
||||
this.sortingService.setScreenName(ScreenNames.DOSSIER_LISTING);
|
||||
}
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
@ -52,10 +52,6 @@ export class TrashScreenComponent extends BaseListingComponent<Dossier> implemen
|
||||
return moment(softDeletedTime).add(this._deleteRetentionHours, 'hours').toISOString();
|
||||
}
|
||||
|
||||
trackById(index: number, dossier: Dossier): string {
|
||||
return dossier.dossierId;
|
||||
}
|
||||
|
||||
bulkDelete(dossierIds = this.screenStateService.selectedEntities.map(d => d.dossierId)) {
|
||||
this._loadingService.loadWhile(this._hardDelete(dossierIds));
|
||||
}
|
||||
|
||||
@ -76,7 +76,7 @@
|
||||
|
||||
<cdk-virtual-scroll-viewport [itemSize]="80" redactionHasScrollbar>
|
||||
<!-- Table lines -->
|
||||
<div *cdkVirtualFor="let user of displayedEntities$ | async; trackBy: trackById" class="table-item">
|
||||
<div *cdkVirtualFor="let user of displayedEntities$ | async; trackBy: trackByPrimaryKey" class="table-item">
|
||||
<div (click)="toggleEntitySelected($event, user)" class="selection-column">
|
||||
<redaction-round-checkbox [active]="isSelected(user)"></redaction-round-checkbox>
|
||||
</div>
|
||||
|
||||
@ -23,6 +23,8 @@ import { map } from 'rxjs/operators';
|
||||
providers: [FilterService, SearchService, ScreenStateService, SortingService]
|
||||
})
|
||||
export class UserListingScreenComponent extends BaseListingComponent<User> implements OnInit {
|
||||
protected readonly _primaryKey = 'userId';
|
||||
|
||||
collapsedDetails = false;
|
||||
chartData: DoughnutChartConfig[] = [];
|
||||
@ViewChildren(InitialsAvatarComponent)
|
||||
@ -81,10 +83,6 @@ export class UserListingScreenComponent extends BaseListingComponent<User> imple
|
||||
this.openDeleteUsersDialog(this.screenStateService.allEntities.filter(u => this.isSelected(u)));
|
||||
}
|
||||
|
||||
trackById(index: number, user: User) {
|
||||
return user.userId;
|
||||
}
|
||||
|
||||
private async _loadData() {
|
||||
this.screenStateService.setEntities(await this._userControllerService.getAllUsers().toPromise());
|
||||
await this.userService.loadAllUsers();
|
||||
|
||||
@ -21,8 +21,7 @@
|
||||
icon="red:assign-me"
|
||||
tooltip="dossier-overview.assign-me"
|
||||
type="dark-bg"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
></redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="setToUnderApproval()"
|
||||
@ -30,8 +29,7 @@
|
||||
icon="red:ready-for-approval"
|
||||
tooltip="dossier-overview.under-approval"
|
||||
type="dark-bg"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
></redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="setToUnderReview()"
|
||||
@ -39,13 +37,9 @@
|
||||
icon="red:undo"
|
||||
tooltip="dossier-overview.under-review"
|
||||
type="dark-bg"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
></redaction-circle-button>
|
||||
|
||||
<redaction-file-download-btn
|
||||
[dossier]="dossier"
|
||||
[file]="selectedFiles"
|
||||
></redaction-file-download-btn>
|
||||
<redaction-file-download-btn [dossier]="dossier" [file]="selectedFiles"></redaction-file-download-btn>
|
||||
|
||||
<!-- Approved-->
|
||||
<redaction-circle-button
|
||||
@ -55,8 +49,7 @@
|
||||
[tooltip]="canApprove ? 'dossier-overview.approve' : 'dossier-overview.approve-disabled'"
|
||||
icon="red:approved"
|
||||
type="dark-bg"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
></redaction-circle-button>
|
||||
|
||||
<!-- Back to approval -->
|
||||
<redaction-circle-button
|
||||
@ -65,8 +58,7 @@
|
||||
icon="red:undo"
|
||||
tooltip="dossier-overview.under-approval"
|
||||
type="dark-bg"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
></redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="ocr()"
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
import { ChangeDetectorRef, Component, EventEmitter, Output } from '@angular/core';
|
||||
import { Component, EventEmitter, Output } from '@angular/core';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { FileManagementControllerService, ReanalysisControllerService } from '@redaction/red-ui-http';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { FileStatusWrapper } from '@models/file/file-status.wrapper';
|
||||
import { FileActionService } from '../../services/file-action.service';
|
||||
import { from, Observable } from 'rxjs';
|
||||
import { StatusOverlayService } from '@upload-download/services/status-overlay.service';
|
||||
import { DossiersDialogService } from '../../services/dossiers-dialog.service';
|
||||
import { LoadingService } from '../../../../services/loading.service';
|
||||
import { ConfirmationDialogInput } from '../../../shared/dialogs/confirmation-dialog/confirmation-dialog.component';
|
||||
@ -23,14 +21,11 @@ export class DossierOverviewBulkActionsComponent {
|
||||
|
||||
constructor(
|
||||
private readonly _appStateService: AppStateService,
|
||||
private readonly _userService: UserService,
|
||||
private readonly _dialogService: DossiersDialogService,
|
||||
private readonly _fileManagementControllerService: FileManagementControllerService,
|
||||
private readonly _reanalysisControllerService: ReanalysisControllerService,
|
||||
private readonly _permissionsService: PermissionsService,
|
||||
private readonly _fileActionService: FileActionService,
|
||||
private readonly _statusOverlayService: StatusOverlayService,
|
||||
private readonly _changeDetectorRef: ChangeDetectorRef,
|
||||
private readonly _loadingService: LoadingService,
|
||||
private readonly _screenStateService: ScreenStateService<FileStatusWrapper>
|
||||
) {}
|
||||
|
||||
@ -72,7 +72,7 @@ export class DossierDetailsComponent implements OnInit {
|
||||
key: key
|
||||
});
|
||||
}
|
||||
this.documentsChartData.sort(StatusSorter.byKey);
|
||||
this.documentsChartData.sort(StatusSorter.byStatus);
|
||||
this.documentsChartData = this.translateChartService.translateStatus(this.documentsChartData);
|
||||
this._changeDetectorRef.detectChanges();
|
||||
}
|
||||
|
||||
@ -2,7 +2,6 @@ import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { DossierWrapper } from '@state/model/dossier.wrapper';
|
||||
import { StatusSorter } from '@utils/sorters/status-sorter';
|
||||
import { FileManagementControllerService } from '@redaction/red-ui-http';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { DossiersDialogService } from '../../services/dossiers-dialog.service';
|
||||
|
||||
@ -19,16 +18,13 @@ export class DossierListingActionsComponent {
|
||||
constructor(
|
||||
readonly permissionsService: PermissionsService,
|
||||
readonly appStateService: AppStateService,
|
||||
private readonly _dialogService: DossiersDialogService,
|
||||
private readonly _fileManagementControllerService: FileManagementControllerService
|
||||
private readonly _dialogService: DossiersDialogService
|
||||
) {}
|
||||
|
||||
openEditDossierDialog($event: MouseEvent, dossierWrapper: DossierWrapper) {
|
||||
this._dialogService.openDialog('editDossier', $event, {
|
||||
dossierWrapper,
|
||||
afterSave: () => {
|
||||
this.actionPerformed.emit();
|
||||
}
|
||||
afterSave: () => this.actionPerformed.emit()
|
||||
});
|
||||
}
|
||||
|
||||
@ -51,7 +47,7 @@ export class DossierListingActionsComponent {
|
||||
}, {});
|
||||
|
||||
return Object.keys(obj)
|
||||
.sort((a, b) => StatusSorter[a] - StatusSorter[b])
|
||||
.sort(StatusSorter.byStatus)
|
||||
.map(status => ({ length: obj[status], color: status }));
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,10 +18,8 @@
|
||||
|
||||
<div class="table-header" redactionSyncWidth="table-item">
|
||||
<redaction-table-col-name
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[withSort]="true"
|
||||
column="dossier.dossierName"
|
||||
column="dossierName"
|
||||
label="dossier-listing.table-col-names.name"
|
||||
></redaction-table-col-name>
|
||||
|
||||
@ -45,7 +43,7 @@
|
||||
|
||||
<cdk-virtual-scroll-viewport [itemSize]="itemSize" redactionHasScrollbar>
|
||||
<div
|
||||
*cdkVirtualFor="let dw of sortedDisplayedEntities$ | async"
|
||||
*cdkVirtualFor="let dw of sortedDisplayedEntities$ | async; trackBy: trackByPrimaryKey"
|
||||
[class.pointer]="!!dw"
|
||||
[routerLink]="[!!dw ? '/main/dossiers/' + dw.dossier.dossierId : []]"
|
||||
class="table-item"
|
||||
|
||||
@ -28,7 +28,7 @@ import { FilterService } from '@shared/services/filter.service';
|
||||
import { SearchService } from '@shared/services/search.service';
|
||||
import { ScreenStateService } from '@shared/services/screen-state.service';
|
||||
import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||
import { ScreenNames, SortingService } from '@services/sorting.service';
|
||||
import { SortingService } from '@services/sorting.service';
|
||||
|
||||
const isLeavingScreen = event => event instanceof NavigationStart && event.url !== '/main/dossiers';
|
||||
|
||||
@ -39,6 +39,8 @@ const isLeavingScreen = event => event instanceof NavigationStart && event.url !
|
||||
})
|
||||
export class DossierListingScreenComponent extends BaseListingComponent<DossierWrapper> implements OnInit, OnDestroy, OnAttach, OnDetach {
|
||||
readonly itemSize = 95;
|
||||
protected readonly _primaryKey = 'dossierName';
|
||||
|
||||
dossiersChartData: DoughnutChartConfig[] = [];
|
||||
documentsChartData: DoughnutChartConfig[] = [];
|
||||
buttonConfigs: ButtonConfig[] = [
|
||||
@ -68,8 +70,6 @@ export class DossierListingScreenComponent extends BaseListingComponent<DossierW
|
||||
protected readonly _injector: Injector
|
||||
) {
|
||||
super(_injector);
|
||||
this.sortingService.setScreenName(ScreenNames.DOSSIER_LISTING);
|
||||
this.searchService.setSearchKey('name');
|
||||
this._appStateService.reset();
|
||||
this._loadEntitiesFromState();
|
||||
}
|
||||
@ -153,7 +153,7 @@ export class DossierListingScreenComponent extends BaseListingComponent<DossierW
|
||||
key: key
|
||||
});
|
||||
}
|
||||
this.documentsChartData.sort(StatusSorter.byKey);
|
||||
this.documentsChartData.sort(StatusSorter.byStatus);
|
||||
this.documentsChartData = this._translateChartService.translateStatus(this.documentsChartData);
|
||||
}
|
||||
|
||||
@ -192,7 +192,7 @@ export class DossierListingScreenComponent extends BaseListingComponent<DossierW
|
||||
slug: 'statusFilters',
|
||||
label: this._translateService.instant('filters.status'),
|
||||
icon: 'red:status',
|
||||
values: statusFilters.sort(StatusSorter.byKey),
|
||||
values: statusFilters.sort(StatusSorter.byStatus),
|
||||
checker: dossierStatusChecker
|
||||
});
|
||||
|
||||
|
||||
@ -59,16 +59,12 @@
|
||||
<div class="select-oval-placeholder"></div>
|
||||
|
||||
<redaction-table-col-name
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[withSort]="true"
|
||||
column="filename"
|
||||
label="dossier-overview.table-col-names.name"
|
||||
></redaction-table-col-name>
|
||||
|
||||
<redaction-table-col-name
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[withSort]="true"
|
||||
column="added"
|
||||
label="dossier-overview.table-col-names.added-on"
|
||||
@ -77,8 +73,6 @@
|
||||
<redaction-table-col-name label="dossier-overview.table-col-names.needs-work"></redaction-table-col-name>
|
||||
|
||||
<redaction-table-col-name
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[withSort]="true"
|
||||
class="user-column"
|
||||
column="reviewerName"
|
||||
@ -86,16 +80,12 @@
|
||||
></redaction-table-col-name>
|
||||
|
||||
<redaction-table-col-name
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[withSort]="true"
|
||||
column="pages"
|
||||
label="dossier-overview.table-col-names.pages"
|
||||
></redaction-table-col-name>
|
||||
|
||||
<redaction-table-col-name
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[withSort]="true"
|
||||
class="flex-end"
|
||||
column="statusSort"
|
||||
@ -116,7 +106,7 @@
|
||||
|
||||
<cdk-virtual-scroll-viewport [itemSize]="itemSize" redactionHasScrollbar>
|
||||
<div
|
||||
*cdkVirtualFor="let fileStatus of sortedDisplayedEntities$ | async; trackBy: trackByFileId"
|
||||
*cdkVirtualFor="let fileStatus of sortedDisplayedEntities$ | async; trackBy: trackByPrimaryKey"
|
||||
[class.disabled]="fileStatus.isExcluded"
|
||||
[class.last-opened]="isLastOpenedFile(fileStatus)"
|
||||
[class.pointer]="permissionsService.canOpenFile(fileStatus)"
|
||||
|
||||
@ -26,7 +26,7 @@ import { ActionConfig } from '@shared/components/page-header/models/action-confi
|
||||
import { FilterService } from '@shared/services/filter.service';
|
||||
import { SearchService } from '@shared/services/search.service';
|
||||
import { ScreenStateService } from '@shared/services/screen-state.service';
|
||||
import { ScreenNames, SortingService } from '@services/sorting.service';
|
||||
import { SortingService } from '../../../../services/sorting.service';
|
||||
import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||
import { LoadingService } from '@services/loading.service';
|
||||
import { DossierAttributesService } from '@shared/services/controller-wrappers/dossier-attributes.service';
|
||||
@ -42,8 +42,9 @@ export class DossierOverviewScreenComponent
|
||||
extends BaseListingComponent<FileStatusWrapper>
|
||||
implements OnInit, OnDestroy, OnDetach, OnAttach
|
||||
{
|
||||
collapsedDetails = false;
|
||||
readonly itemSize = 80;
|
||||
protected readonly _primaryKey = 'filename';
|
||||
collapsedDetails = false;
|
||||
actionConfigs: ActionConfig[];
|
||||
dossierAttributes: DossierAttributeWithValue[] = [];
|
||||
@ViewChild(DossierDetailsComponent, { static: false })
|
||||
@ -73,8 +74,6 @@ export class DossierOverviewScreenComponent
|
||||
protected readonly _injector: Injector
|
||||
) {
|
||||
super(_injector);
|
||||
this.sortingService.setScreenName(ScreenNames.DOSSIER_OVERVIEW);
|
||||
this.searchService.setSearchKey('searchField');
|
||||
this._loadEntitiesFromState();
|
||||
}
|
||||
|
||||
@ -82,8 +81,8 @@ export class DossierOverviewScreenComponent
|
||||
return this._appStateService.activeDossier;
|
||||
}
|
||||
|
||||
get user() {
|
||||
return this._userService.user;
|
||||
get userId() {
|
||||
return this._userService.userId;
|
||||
}
|
||||
|
||||
get checkedRequiredFilters() {
|
||||
@ -170,10 +169,6 @@ export class DossierOverviewScreenComponent
|
||||
this._changeDetectorRef.detectChanges();
|
||||
}
|
||||
|
||||
trackByFileId(index: number, item: FileStatusWrapper) {
|
||||
return item.fileId;
|
||||
}
|
||||
|
||||
@HostListener('drop', ['$event'])
|
||||
onDrop(event: DragEvent) {
|
||||
handleFileDrop(event, this.activeDossier, this._uploadFiles.bind(this));
|
||||
@ -272,7 +267,7 @@ export class DossierOverviewScreenComponent
|
||||
slug: 'statusFilters',
|
||||
label: this._translateService.instant('filters.status'),
|
||||
icon: 'red:status',
|
||||
values: statusFilters.sort(StatusSorter.byKey),
|
||||
values: statusFilters.sort(StatusSorter.byStatus),
|
||||
checker: keyChecker('status')
|
||||
});
|
||||
|
||||
@ -348,7 +343,7 @@ export class DossierOverviewScreenComponent
|
||||
{
|
||||
key: 'assigned-to-me',
|
||||
label: this._translateService.instant('dossier-overview.quick-filters.assigned-to-me'),
|
||||
checker: (file: FileStatusWrapper) => file.currentReviewer === this.user.id
|
||||
checker: (file: FileStatusWrapper) => file.currentReviewer === this.userId
|
||||
},
|
||||
{
|
||||
key: 'unassigned',
|
||||
@ -358,7 +353,7 @@ export class DossierOverviewScreenComponent
|
||||
{
|
||||
key: 'assigned-to-others',
|
||||
label: this._translateService.instant('dossier-overview.quick-filters.assigned-to-others'),
|
||||
checker: (file: FileStatusWrapper) => !!file.currentReviewer && file.currentReviewer !== this.user.id
|
||||
checker: (file: FileStatusWrapper) => !!file.currentReviewer && file.currentReviewer !== this.userId
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Component, Injector, OnDestroy, ViewChild } from '@angular/core';
|
||||
import { SortingOption, SortingService } from '@services/sorting.service';
|
||||
import { SortingOrders, SortingService } from '@services/sorting.service';
|
||||
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
||||
import { FilterService } from '../services/filter.service';
|
||||
import { SearchService } from '../services/search.service';
|
||||
@ -20,13 +20,30 @@ export abstract class BaseListingComponent<T> extends AutoUnsubscribeComponent i
|
||||
readonly searchService: SearchService<T>;
|
||||
readonly screenStateService: ScreenStateService<T>;
|
||||
|
||||
/**
|
||||
* Key used in the *trackBy* function with **ngFor* or **cdkVirtualFor*
|
||||
* and in the default sorting and as the search field
|
||||
* @protected
|
||||
*/
|
||||
protected abstract _primaryKey: string;
|
||||
|
||||
protected constructor(protected readonly _injector: Injector) {
|
||||
super();
|
||||
this.trackByPrimaryKey = this.trackByPrimaryKey.bind(this);
|
||||
this.permissionsService = this._injector.get(PermissionsService);
|
||||
this.filterService = this._injector.get(FilterService);
|
||||
this.sortingService = this._injector.get(SortingService);
|
||||
this.searchService = this._injector.get(SearchService);
|
||||
this.screenStateService = this._injector.get<ScreenStateService<T>>(ScreenStateService);
|
||||
setTimeout(() => this.setInitialConfig());
|
||||
}
|
||||
|
||||
setInitialConfig() {
|
||||
this.sortingService.setSortingOption({
|
||||
column: this._primaryKey,
|
||||
order: SortingOrders.ASC
|
||||
});
|
||||
this.searchService.setSearchKey(this._primaryKey);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
@ -45,22 +62,16 @@ export abstract class BaseListingComponent<T> extends AutoUnsubscribeComponent i
|
||||
return this.screenStateService.allEntities;
|
||||
}
|
||||
|
||||
get sortingOption(): SortingOption {
|
||||
return this.sortingService.getSortingOption();
|
||||
}
|
||||
|
||||
get noMatch$(): Observable<boolean> {
|
||||
return combineLatest([this.screenStateService.allEntitiesLength$, this.screenStateService.displayedLength$]).pipe(
|
||||
map(res => res[0] && !res[1])
|
||||
map(([hasEntities, hasDisplayedEntities]) => hasEntities && !hasDisplayedEntities)
|
||||
);
|
||||
}
|
||||
|
||||
canBulkDelete$(hasPermission = true) {
|
||||
return this.screenStateService.areSomeEntitiesSelected$.pipe(map(res => res && hasPermission));
|
||||
}
|
||||
|
||||
toggleSort($event) {
|
||||
this.sortingService.toggleSort($event);
|
||||
return this.screenStateService.areSomeEntitiesSelected$.pipe(
|
||||
map(areSomeEntitiesSelected => areSomeEntitiesSelected && hasPermission)
|
||||
);
|
||||
}
|
||||
|
||||
toggleSelectAll() {
|
||||
@ -75,4 +86,8 @@ export abstract class BaseListingComponent<T> extends AutoUnsubscribeComponent i
|
||||
isSelected(entity: T): boolean {
|
||||
return this.screenStateService.isSelected(entity);
|
||||
}
|
||||
|
||||
trackByPrimaryKey(index: number, item: T) {
|
||||
return item[this._primaryKey];
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,31 +16,26 @@
|
||||
</ng-container>
|
||||
|
||||
<redaction-input-with-action
|
||||
*ngIf="searchService.isSearchNeeded"
|
||||
*ngIf="searchPlaceholder"
|
||||
[form]="searchService.searchForm"
|
||||
[placeholder]="searchPlaceholder"
|
||||
type="search"
|
||||
></redaction-input-with-action>
|
||||
|
||||
<div
|
||||
(click)="resetFilters()"
|
||||
*ngIf="(filterService.showResetFilters$ | async) || searchService.searchValue"
|
||||
class="reset-filters"
|
||||
translate="reset-filters"
|
||||
></div>
|
||||
<div (click)="resetFilters()" *ngIf="showResetFilters$ | async" class="reset-filters" translate="reset-filters"></div>
|
||||
</div>
|
||||
|
||||
<ng-container *ngFor="let config of buttonConfigs; trackBy: trackByLabel">
|
||||
<redaction-icon-button
|
||||
(action)="config.action($event)"
|
||||
*ngIf="!config.hide"
|
||||
[icon]="config.icon"
|
||||
[text]="config.label"
|
||||
[type]="config.type"
|
||||
></redaction-icon-button>
|
||||
</ng-container>
|
||||
<div class="actions" *ngIf="showCloseButton || actionConfigs || buttonConfigs">
|
||||
<ng-container *ngFor="let config of buttonConfigs; trackBy: trackByLabel">
|
||||
<redaction-icon-button
|
||||
(action)="config.action($event)"
|
||||
*ngIf="!config.hide"
|
||||
[icon]="config.icon"
|
||||
[text]="config.label"
|
||||
[type]="config.type"
|
||||
></redaction-icon-button>
|
||||
</ng-container>
|
||||
|
||||
<div class="actions" *ngIf="showCloseButton || actionConfigs">
|
||||
<ng-container *ngFor="let config of actionConfigs; trackBy: trackByLabel">
|
||||
<redaction-circle-button
|
||||
(action)="config.action($event)"
|
||||
@ -56,7 +51,7 @@
|
||||
|
||||
<redaction-circle-button
|
||||
[class.ml-6]="actionConfigs"
|
||||
*ngIf="showCloseButton && permissionsService.isUser()"
|
||||
*ngIf="showCloseButton"
|
||||
icon="red:close"
|
||||
redactionNavigateLastDossiersScreen
|
||||
tooltip="common.close"
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { Component, Input, Optional } 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 } from '@shared/services/filter.service';
|
||||
import { SearchService } from '@shared/services/search.service';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { distinctUntilChanged, map } from 'rxjs/operators';
|
||||
import { combineLatest, Observable } from 'rxjs';
|
||||
import { FilterWrapper } from '@shared/components/filters/popup-filter/model/filter-wrapper.model';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-page-header',
|
||||
@ -18,22 +19,29 @@ export class PageHeaderComponent<T> {
|
||||
@Input() buttonConfigs: ButtonConfig[];
|
||||
@Input() searchPlaceholder: string;
|
||||
|
||||
constructor(
|
||||
readonly permissionsService: PermissionsService,
|
||||
readonly filterService: FilterService<T>,
|
||||
readonly searchService: SearchService<T>
|
||||
) {}
|
||||
constructor(@Optional() readonly filterService: FilterService<T>, @Optional() readonly searchService: SearchService<T>) {}
|
||||
|
||||
get filters$() {
|
||||
return this.filterService.allFilters$.pipe(map(all => all.filter(f => f.icon)));
|
||||
get filters$(): Observable<FilterWrapper[]> {
|
||||
return this.filterService?.allFilters$.pipe(map(all => all.filter(f => f.icon)));
|
||||
}
|
||||
|
||||
resetFilters() {
|
||||
get showResetFilters$(): Observable<boolean> {
|
||||
const filtersLength$ = this.filters$.pipe(
|
||||
map(f => f.length),
|
||||
distinctUntilChanged()
|
||||
);
|
||||
return combineLatest([filtersLength$, this.filterService.showResetFilters$, this.searchService.valueChanges$]).pipe(
|
||||
map(([hasFilters, showResetFilters, searchValue]) => hasFilters && (showResetFilters || !!searchValue)),
|
||||
distinctUntilChanged()
|
||||
);
|
||||
}
|
||||
|
||||
resetFilters(): void {
|
||||
this.filterService.reset();
|
||||
this.searchService.reset();
|
||||
}
|
||||
|
||||
trackByLabel(index: number, item) {
|
||||
trackByLabel<K extends { label?: string }>(index: number, item: K): string {
|
||||
return item.label;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,18 +1,13 @@
|
||||
<div (click)="withSort && toggleSort.emit(column)" [class.pointer]="withSort" [ngClass]="class">
|
||||
<div (click)="withSort && sortingService?.toggleSort(column)" [class.pointer]="withSort" [ngClass]="class">
|
||||
<mat-icon *ngIf="!!leftIcon" [svgIcon]="leftIcon"></mat-icon>
|
||||
<span [translate]="label" class="all-caps-label"></span>
|
||||
<mat-icon
|
||||
*ngIf="!!rightIcon"
|
||||
[matTooltip]="rightIconTooltip | translate"
|
||||
[svgIcon]="rightIcon"
|
||||
matTooltipPosition="above"
|
||||
></mat-icon>
|
||||
<mat-icon *ngIf="!!rightIcon" [matTooltip]="rightIconTooltip | translate" [svgIcon]="rightIcon" matTooltipPosition="above"></mat-icon>
|
||||
<div
|
||||
*ngIf="withSort"
|
||||
[class.force-display]="activeSortingOption.column === column"
|
||||
*ngIf="withSort && sortingService"
|
||||
[class.force-display]="sortingService.sortingOption?.column === column"
|
||||
class="sort-arrows-container"
|
||||
>
|
||||
<mat-icon *ngIf="activeSortingOption?.order === 'asc'" svgIcon="red:sort-asc"></mat-icon>
|
||||
<mat-icon *ngIf="activeSortingOption?.order === 'desc'" svgIcon="red:sort-desc"></mat-icon>
|
||||
<mat-icon *ngIf="sortingService.sortingOption?.order === 'asc'" svgIcon="red:sort-asc"></mat-icon>
|
||||
<mat-icon *ngIf="sortingService.sortingOption?.order === 'desc'" svgIcon="red:sort-desc"></mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { SortingOption } from '@services/sorting.service';
|
||||
import { Component, Input, Optional } from '@angular/core';
|
||||
import { SortingService } from '@services/sorting.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-table-col-name',
|
||||
@ -7,7 +7,6 @@ import { SortingOption } from '@services/sorting.service';
|
||||
styleUrls: ['./table-col-name.component.scss']
|
||||
})
|
||||
export class TableColNameComponent {
|
||||
@Input() activeSortingOption: SortingOption;
|
||||
@Input() column: string;
|
||||
@Input() label: string;
|
||||
@Input() withSort = false;
|
||||
@ -16,5 +15,5 @@ export class TableColNameComponent {
|
||||
@Input() rightIcon: string;
|
||||
@Input() rightIconTooltip: string;
|
||||
|
||||
@Output() toggleSort = new EventEmitter<string>();
|
||||
constructor(@Optional() readonly sortingService: SortingService) {}
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ export class FilterService<T> {
|
||||
get showResetFilters$() {
|
||||
return this.allFilters$.pipe(
|
||||
map(all => this._toFlatFilters(all)),
|
||||
filter(f => !!f.find(el => el.checked)),
|
||||
map(f => !!f.find(el => el.checked)),
|
||||
distinctUntilChanged()
|
||||
);
|
||||
}
|
||||
|
||||
@ -74,7 +74,9 @@ export class ScreenStateService<T> {
|
||||
}
|
||||
|
||||
get areAllEntitiesSelected$(): Observable<boolean> {
|
||||
return combineLatest([this.displayedLength$, this.selectedLength$]).pipe(map(res => res[0] && res[0] === res[1]));
|
||||
return combineLatest([this.displayedLength$, this.selectedLength$]).pipe(
|
||||
map(([displayedLength, selectedLength]) => displayedLength && displayedLength === selectedLength)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -88,7 +90,9 @@ export class ScreenStateService<T> {
|
||||
* Indicates that some entities are selected, but not all
|
||||
*/
|
||||
get notAllEntitiesSelected$(): Observable<boolean> {
|
||||
return combineLatest([this.areAllEntitiesSelected$, this.areSomeEntitiesSelected$]).pipe(map(res => !res[0] && res[1]));
|
||||
return combineLatest([this.areAllEntitiesSelected$, this.areSomeEntitiesSelected$]).pipe(
|
||||
map(([allEntitiesAreSelected, someEntitiesAreSelected]) => !allEntitiesAreSelected && someEntitiesAreSelected)
|
||||
);
|
||||
}
|
||||
|
||||
isSelected(entity: T): boolean {
|
||||
|
||||
@ -2,18 +2,24 @@ import { Injectable } from '@angular/core';
|
||||
import { debounce } from '@utils/debounce';
|
||||
import { ScreenStateService } from '@shared/services/screen-state.service';
|
||||
import { FormBuilder } from '@angular/forms';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
@Injectable()
|
||||
export class SearchService<T> {
|
||||
private _searchValue = '';
|
||||
private _searchKey: string;
|
||||
|
||||
valueChanges$ = new BehaviorSubject(this._searchValue);
|
||||
|
||||
readonly searchForm = this._formBuilder.group({
|
||||
query: ['']
|
||||
});
|
||||
|
||||
constructor(private readonly _screenStateService: ScreenStateService<T>, private readonly _formBuilder: FormBuilder) {
|
||||
this.searchForm.valueChanges.subscribe(() => this.executeSearch());
|
||||
this.searchForm.valueChanges.subscribe(() => {
|
||||
this.valueChanges$.next(this.searchValue.toLowerCase());
|
||||
this.executeSearch();
|
||||
});
|
||||
}
|
||||
|
||||
@debounce(200)
|
||||
@ -23,7 +29,9 @@ export class SearchService<T> {
|
||||
}
|
||||
|
||||
executeSearchImmediately(): void {
|
||||
const displayed = this._screenStateService.filteredEntities || this._screenStateService.allEntities;
|
||||
const displayed = this._screenStateService.filteredEntities.length
|
||||
? this._screenStateService.filteredEntities
|
||||
: this._screenStateService.allEntities;
|
||||
|
||||
if (!this._searchKey) {
|
||||
return this._screenStateService.setDisplayedEntities(displayed);
|
||||
@ -39,10 +47,6 @@ export class SearchService<T> {
|
||||
this._searchKey = value;
|
||||
}
|
||||
|
||||
get isSearchNeeded(): boolean {
|
||||
return !!this._searchKey;
|
||||
}
|
||||
|
||||
get searchValue(): string {
|
||||
return this.searchForm.get('query').value;
|
||||
}
|
||||
|
||||
@ -13,40 +13,12 @@ export interface SortingOption {
|
||||
column: string;
|
||||
}
|
||||
|
||||
export type ScreenName =
|
||||
| 'dossier-listing'
|
||||
| 'dossier-overview'
|
||||
| 'dictionary-listing'
|
||||
| 'dossier-templates-listing'
|
||||
| 'default-colors'
|
||||
| 'file-attributes-listing'
|
||||
| 'dossier-attributes-listing';
|
||||
|
||||
export const enum ScreenNames {
|
||||
DOSSIER_LISTING = 'dossier-listing',
|
||||
DOSSIER_OVERVIEW = 'dossier-overview',
|
||||
DICTIONARY_LISTING = 'dictionary-listing',
|
||||
DOSSIER_TEMPLATES_LISTING = 'dossier-templates-listing',
|
||||
DEFAULT_COLORS = 'default-colors',
|
||||
FILE_ATTRIBUTES_LISTING = 'file-attributes-listing',
|
||||
DOSSIER_ATTRIBUTES_LISTING = 'dossier-attributes-listing'
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class SortingService {
|
||||
private _currentScreenName: string;
|
||||
private readonly _options: { [key in ScreenName]: SortingOption } = {
|
||||
[ScreenNames.DOSSIER_LISTING]: { column: 'dossier.dossierName', order: SortingOrders.ASC },
|
||||
[ScreenNames.DOSSIER_OVERVIEW]: { column: 'filename', order: SortingOrders.ASC },
|
||||
[ScreenNames.DICTIONARY_LISTING]: { column: 'label', order: SortingOrders.ASC },
|
||||
[ScreenNames.DOSSIER_TEMPLATES_LISTING]: { column: 'name', order: SortingOrders.ASC },
|
||||
[ScreenNames.DEFAULT_COLORS]: { column: 'key', order: SortingOrders.ASC },
|
||||
[ScreenNames.FILE_ATTRIBUTES_LISTING]: { column: 'label', order: SortingOrders.ASC },
|
||||
[ScreenNames.DOSSIER_ATTRIBUTES_LISTING]: { column: 'label', order: 'asc' }
|
||||
};
|
||||
private _sortingOption: SortingOption;
|
||||
|
||||
setScreenName(value: string) {
|
||||
this._currentScreenName = value;
|
||||
setSortingOption(value: SortingOption): void {
|
||||
this._sortingOption = value;
|
||||
}
|
||||
|
||||
sort<T>(values: T[], order = '', column: string = ''): T[] {
|
||||
@ -67,26 +39,26 @@ export class SortingService {
|
||||
}
|
||||
|
||||
defaultSort<T>(values: T[]) {
|
||||
return this.sort(values, this.getSortingOption().order, this.getSortingOption().column);
|
||||
return this.sort(values, this.sortingOption?.order, this.sortingOption?.column);
|
||||
}
|
||||
|
||||
toggleSort(column: string) {
|
||||
if (this._options[this._currentScreenName].column === column) {
|
||||
if (this._sortingOption.column === column) {
|
||||
this._currentOrder = this._currentOrder === SortingOrders.ASC ? SortingOrders.DESC : SortingOrders.ASC;
|
||||
} else {
|
||||
this._options[this._currentScreenName] = { column, order: SortingOrders.ASC };
|
||||
this._sortingOption = { column, order: SortingOrders.ASC };
|
||||
}
|
||||
}
|
||||
|
||||
getSortingOption(): SortingOption {
|
||||
return this._options[this._currentScreenName];
|
||||
get sortingOption(): SortingOption {
|
||||
return this._sortingOption;
|
||||
}
|
||||
|
||||
private get _currentOrder(): string {
|
||||
return this._options[this._currentScreenName].order;
|
||||
private get _currentOrder(): SortingOrder {
|
||||
return this._sortingOption.order;
|
||||
}
|
||||
|
||||
private set _currentOrder(value: string) {
|
||||
this._options[this._currentScreenName].order = value;
|
||||
private set _currentOrder(value: SortingOrder) {
|
||||
this._sortingOption.order = value;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,13 @@
|
||||
type StatusSorterItem = { key?: string } | string;
|
||||
|
||||
const byStatus = (a: StatusSorterItem, b: StatusSorterItem) => {
|
||||
if (typeof a !== typeof b) return;
|
||||
|
||||
const x = typeof a === 'string' ? a : a.key;
|
||||
const y = typeof b === 'string' ? b : b.key;
|
||||
return (StatusSorter[x] = StatusSorter[y]);
|
||||
};
|
||||
|
||||
export const StatusSorter = {
|
||||
ERROR: 0,
|
||||
UNPROCESSED: 1,
|
||||
@ -9,5 +19,5 @@ export const StatusSorter = {
|
||||
UNDER_REVIEW: 15,
|
||||
UNDER_APPROVAL: 20,
|
||||
APPROVED: 25,
|
||||
byKey: (a: { key?: string }, b: { key?: string }) => StatusSorter[a.key] - StatusSorter[b.key]
|
||||
byStatus: byStatus
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user