change base listing component
This commit is contained in:
parent
6c21b6e957
commit
bb53a1a6dc
@ -3,7 +3,7 @@
|
||||
<redaction-round-checkbox
|
||||
(click)="toggleSelectAll()"
|
||||
[active]="areAllEntitiesSelected"
|
||||
[indeterminate]="areSomeEntitiesSelected && !areAllEntitiesSelected"
|
||||
[indeterminate]="(areSomeEntitiesSelected$ | async) && !areAllEntitiesSelected"
|
||||
></redaction-round-checkbox>
|
||||
</div>
|
||||
<span class="all-caps-label">
|
||||
@ -13,22 +13,20 @@
|
||||
}}
|
||||
</span>
|
||||
|
||||
<ng-container *ngIf="areSomeEntitiesSelected">
|
||||
<ng-container *ngIf="areSomeEntitiesSelected$ | async">
|
||||
<redaction-circle-button
|
||||
[matMenuTriggerFor]="readOnlyMenu"
|
||||
icon="red:read-only"
|
||||
tooltip="file-attributes-csv-import.table-header.actions.read-only"
|
||||
type="dark-bg"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
></redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="deactivateSelection()"
|
||||
icon="red:trash"
|
||||
tooltip="file-attributes-csv-import.table-header.actions.remove-selected"
|
||||
type="dark-bg"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
></redaction-circle-button>
|
||||
|
||||
<div class="separator"></div>
|
||||
|
||||
@ -92,7 +90,7 @@
|
||||
</div>
|
||||
|
||||
<redaction-empty-state
|
||||
*ngIf="!allEntities.length"
|
||||
*ngIf="(allEntities$ | async)?.length === 0"
|
||||
icon="red:attribute"
|
||||
screen="file-attributes-csv-import"
|
||||
></redaction-empty-state>
|
||||
@ -102,7 +100,7 @@
|
||||
<div
|
||||
(mouseenter)="setHoveredColumn.emit(field.csvColumn)"
|
||||
(mouseleave)="setHoveredColumn.emit()"
|
||||
*cdkVirtualFor="let field of displayedEntities"
|
||||
*cdkVirtualFor="let field of displayedEntities$ | async"
|
||||
class="table-item"
|
||||
>
|
||||
<div (click)="toggleEntitySelected($event, field)" class="selection-column">
|
||||
@ -127,23 +125,20 @@
|
||||
icon="red:edit"
|
||||
tooltip="file-attributes-csv-import.action.edit-name"
|
||||
type="dark-bg"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
></redaction-circle-button>
|
||||
<ng-container *ngIf="field.editingName">
|
||||
<redaction-circle-button
|
||||
(action)="field.editingName = false; field.name = field.temporaryName"
|
||||
icon="red:check"
|
||||
tooltip="file-attributes-csv-import.action.save-name"
|
||||
type="dark-bg"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
></redaction-circle-button>
|
||||
<redaction-circle-button
|
||||
(action)="field.editingName = false; field.temporaryName = field.name"
|
||||
icon="red:close"
|
||||
tooltip="file-attributes-csv-import.action.cancel-edit-name"
|
||||
type="dark-bg"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
></redaction-circle-button>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div>
|
||||
@ -174,8 +169,7 @@
|
||||
icon="red:trash"
|
||||
tooltip="file-attributes-csv-import.action.remove"
|
||||
type="dark-bg"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
></redaction-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="scrollbar-placeholder"></div>
|
||||
|
||||
@ -7,13 +7,13 @@ import {
|
||||
Output,
|
||||
SimpleChanges
|
||||
} from '@angular/core';
|
||||
import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||
import { Field } from '../file-attributes-csv-import-dialog.component';
|
||||
import { FileAttributeConfig } 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 { SortingService } from '../../../../../services/sorting.service';
|
||||
import { BaseListingComponent } from '../../../../shared/base/base-listing.component';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-active-fields-listing',
|
||||
@ -22,8 +22,8 @@ import { SortingService } from '../../../../../services/sorting.service';
|
||||
providers: [FilterService, SearchService, ScreenStateService, SortingService]
|
||||
})
|
||||
export class ActiveFieldsListingComponent extends BaseListingComponent<Field> implements OnChanges {
|
||||
@Input() allEntities: Field[];
|
||||
@Output() allEntitiesChange = new EventEmitter<Field[]>();
|
||||
@Input() entities: Field[];
|
||||
@Output() entitiesChange = new EventEmitter<Field[]>();
|
||||
@Output() setHoveredColumn = new EventEmitter<string>();
|
||||
@Output() toggleFieldActive = new EventEmitter<Field>();
|
||||
|
||||
@ -33,16 +33,16 @@ export class ActiveFieldsListingComponent extends BaseListingComponent<Field> im
|
||||
FileAttributeConfig.TypeEnum.DATE
|
||||
];
|
||||
|
||||
protected readonly _selectionKey = 'csvColumn';
|
||||
|
||||
constructor(protected readonly _injector: Injector) {
|
||||
super(_injector);
|
||||
this._screenStateService.setIdKey('csvColumn');
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes.allEntities) {
|
||||
this.displayedEntities = this.allEntities;
|
||||
this._updateSelection();
|
||||
if (changes.entities) {
|
||||
this._screenStateService.setEntities(this.entities);
|
||||
this._screenStateService.setDisplayedEntities(this.entities);
|
||||
this._screenStateService.updateSelection();
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,13 +50,15 @@ export class ActiveFieldsListingComponent extends BaseListingComponent<Field> im
|
||||
this.allEntities
|
||||
.filter(field => this.isSelected(field))
|
||||
.forEach(field => (field.primaryAttribute = false));
|
||||
this.allEntities = [...this.allEntities.filter(field => !this.isSelected(field))];
|
||||
this.allEntitiesChange.emit(this.allEntities);
|
||||
this.selectedEntitiesIds = [];
|
||||
this._screenStateService.setEntities([
|
||||
...this.allEntities.filter(field => !this.isSelected(field))
|
||||
]);
|
||||
this.entitiesChange.emit(this.allEntities);
|
||||
this._screenStateService.setSelectedEntitiesIds([]);
|
||||
}
|
||||
|
||||
setAttributeForSelection(attribute: string, value: any) {
|
||||
for (const csvColumn of this.selectedEntitiesIds) {
|
||||
for (const csvColumn of this._screenStateService.selectedEntitiesIds) {
|
||||
this.allEntities.find(f => f.csvColumn === csvColumn)[attribute] = value;
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,7 +119,7 @@
|
||||
(click)="toggleFieldActive(field)"
|
||||
(mouseenter)="setHoveredColumn(field.csvColumn)"
|
||||
(mouseleave)="setHoveredColumn()"
|
||||
*ngFor="let field of displayedEntities"
|
||||
*ngFor="let field of displayedEntities$ | async"
|
||||
class="csv-header-pill-wrapper"
|
||||
>
|
||||
<div [class.selected]="isActive(field)" class="csv-header-pill">
|
||||
@ -177,7 +177,7 @@
|
||||
<redaction-active-fields-listing
|
||||
(setHoveredColumn)="setHoveredColumn($event)"
|
||||
(toggleFieldActive)="toggleFieldActive($event)"
|
||||
[(allEntities)]="activeFields"
|
||||
[(entities)]="activeFields"
|
||||
></redaction-active-fields-listing>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Component, Inject, Injector } from '@angular/core';
|
||||
import { AbstractControl, FormGroup, ValidatorFn, Validators } from '@angular/forms';
|
||||
import { AbstractControl, FormBuilder, FormGroup, ValidatorFn, Validators } from '@angular/forms';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import * as Papa from 'papaparse';
|
||||
@ -10,13 +10,13 @@ import {
|
||||
} from '@redaction/red-ui-http';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map, startWith } from 'rxjs/operators';
|
||||
import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||
import { NotificationService, NotificationType } from '@services/notification.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { FilterService } from '../../../shared/services/filter.service';
|
||||
import { SearchService } from '../../../shared/services/search.service';
|
||||
import { ScreenStateService } from '../../../shared/services/screen-state.service';
|
||||
import { SortingService } from '../../../../services/sorting.service';
|
||||
import { BaseListingComponent } from '../../../shared/base/base-listing.component';
|
||||
|
||||
export interface Field {
|
||||
id?: string;
|
||||
@ -55,6 +55,7 @@ export class FileAttributesCsvImportDialogComponent extends BaseListingComponent
|
||||
private readonly _fileAttributesControllerService: FileAttributesControllerService,
|
||||
private readonly _translateService: TranslateService,
|
||||
private readonly _notificationService: NotificationService,
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
public dialogRef: MatDialogRef<FileAttributesCsvImportDialogComponent>,
|
||||
protected readonly _injector: Injector,
|
||||
@Inject(MAT_DIALOG_DATA)
|
||||
@ -102,10 +103,10 @@ export class FileAttributesCsvImportDialogComponent extends BaseListingComponent
|
||||
this.parseResult.meta.fields = Object.keys(this.parseResult.data[0]);
|
||||
}
|
||||
|
||||
this.allEntities = this.parseResult.meta.fields.map(field =>
|
||||
this._buildAttribute(field)
|
||||
this._screenStateService.setEntities(
|
||||
this.parseResult.meta.fields.map(field => this._buildAttribute(field))
|
||||
);
|
||||
this.displayedEntities = [...this.allEntities];
|
||||
this._screenStateService.setDisplayedEntities(this.allEntities);
|
||||
this.activeFields = [];
|
||||
|
||||
for (const entity of this.allEntities) {
|
||||
@ -175,9 +176,9 @@ export class FileAttributesCsvImportDialogComponent extends BaseListingComponent
|
||||
}
|
||||
}
|
||||
return count;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
isActive(field: Field): boolean {
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
<span class="all-caps-label">
|
||||
{{
|
||||
'default-colors-screen.table-header.title'
|
||||
| translate: { length: allEntities.length }
|
||||
| translate: { length: (allEntities$ | async).length }
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
@ -51,7 +51,9 @@
|
||||
<!-- Table lines -->
|
||||
<div
|
||||
*cdkVirtualFor="
|
||||
let color of allEntities | sortBy: sortingOption.order:sortingOption.column
|
||||
let color of allEntities$
|
||||
| async
|
||||
| sortBy: sortingOption.order:sortingOption.column
|
||||
"
|
||||
class="table-item"
|
||||
>
|
||||
@ -77,8 +79,7 @@
|
||||
icon="red:edit"
|
||||
tooltip="default-colors-screen.action.edit"
|
||||
type="dark-bg"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
></redaction-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="scrollbar-placeholder"></div>
|
||||
|
||||
@ -4,12 +4,12 @@ import { Colors, DictionaryControllerService } from '@redaction/red-ui-http';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||
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';
|
||||
|
||||
@Component({
|
||||
templateUrl: './default-colors-screen.component.html',
|
||||
@ -64,10 +64,12 @@ export class DefaultColorsScreenComponent
|
||||
.getColors(this._appStateService.activeDossierTemplateId)
|
||||
.toPromise();
|
||||
this._colorsObj = data;
|
||||
this.allEntities = Object.keys(data).map(key => ({
|
||||
key,
|
||||
value: data[key]
|
||||
}));
|
||||
this._screenStateService.setEntities(
|
||||
Object.keys(data).map(key => ({
|
||||
key,
|
||||
value: data[key]
|
||||
}))
|
||||
);
|
||||
this._loadingService.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,6 @@ import { forkJoin, of } from 'rxjs';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||
import { TypeValueWrapper } from '../../../../models/file/type-value.wrapper';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { LoadingService } from '../../../../services/loading.service';
|
||||
@ -15,7 +14,7 @@ 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 { NewBaseListingComponent } from '../../../shared/base/new-base-listing.component';
|
||||
import { BaseListingComponent } from '../../../shared/base/base-listing.component';
|
||||
|
||||
const toChartConfig = (dict: TypeValueWrapper): DoughnutChartConfig => ({
|
||||
value: dict.entries ? dict.entries.length : 0,
|
||||
@ -30,7 +29,7 @@ const toChartConfig = (dict: TypeValueWrapper): DoughnutChartConfig => ({
|
||||
providers: [FilterService, SearchService, ScreenStateService, SortingService]
|
||||
})
|
||||
export class DictionaryListingScreenComponent
|
||||
extends NewBaseListingComponent<TypeValueWrapper>
|
||||
extends BaseListingComponent<TypeValueWrapper>
|
||||
implements OnInit
|
||||
{
|
||||
chartData: DoughnutChartConfig[] = [];
|
||||
|
||||
@ -10,7 +10,7 @@ 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 { NewBaseListingComponent } from '../../../shared/base/new-base-listing.component';
|
||||
import { BaseListingComponent } from '../../../shared/base/base-listing.component';
|
||||
|
||||
@Component({
|
||||
templateUrl: './dossier-templates-listing-screen.component.html',
|
||||
@ -19,7 +19,7 @@ import { NewBaseListingComponent } from '../../../shared/base/new-base-listing.c
|
||||
providers: [FilterService, SearchService, ScreenStateService, SortingService]
|
||||
})
|
||||
export class DossierTemplatesListingScreenComponent
|
||||
extends NewBaseListingComponent<DossierTemplateModelWrapper>
|
||||
extends BaseListingComponent<DossierTemplateModelWrapper>
|
||||
implements OnInit
|
||||
{
|
||||
constructor(
|
||||
|
||||
@ -25,17 +25,22 @@
|
||||
<redaction-round-checkbox
|
||||
(click)="toggleSelectAll()"
|
||||
[active]="areAllEntitiesSelected"
|
||||
[indeterminate]="areSomeEntitiesSelected && !areAllEntitiesSelected"
|
||||
[indeterminate]="
|
||||
(areSomeEntitiesSelected$ | async) && !areAllEntitiesSelected
|
||||
"
|
||||
></redaction-round-checkbox>
|
||||
</div>
|
||||
|
||||
<span class="all-caps-label">
|
||||
{{ 'file-attributes-listing.table-header.title' | translate: { length: displayedEntities.length } }}
|
||||
{{
|
||||
'file-attributes-listing.table-header.title'
|
||||
| translate: { length: (displayedEntities$ | async)?.length }
|
||||
}}
|
||||
</span>
|
||||
|
||||
<redaction-circle-button
|
||||
(click)="openConfirmDeleteAttributeDialog($event)"
|
||||
*ngIf="areSomeEntitiesSelected"
|
||||
*ngIf="areSomeEntitiesSelected$ | async"
|
||||
icon="red:trash"
|
||||
tooltip="file-attributes-listing.bulk-actions.delete"
|
||||
type="dark-bg"
|
||||
@ -67,7 +72,11 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div [class.no-data]="!allEntities.length" class="table-header" redactionSyncWidth="table-item">
|
||||
<div
|
||||
[class.no-data]="(allEntities$ | async)?.length === 0"
|
||||
class="table-header"
|
||||
redactionSyncWidth="table-item"
|
||||
>
|
||||
<div class="select-oval-placeholder"></div>
|
||||
|
||||
<redaction-table-col-name
|
||||
@ -110,13 +119,13 @@
|
||||
</div>
|
||||
|
||||
<redaction-empty-state
|
||||
*ngIf="!allEntities.length"
|
||||
*ngIf="(allEntities$ | async)?.length === 0"
|
||||
icon="red:attribute"
|
||||
screen="file-attributes-listing"
|
||||
></redaction-empty-state>
|
||||
|
||||
<redaction-empty-state
|
||||
*ngIf="allEntities.length && !displayedEntities.length"
|
||||
*ngIf="(allEntities$ | async)?.length && (displayedEntities$ | async)?.length === 0"
|
||||
screen="file-attributes-listing"
|
||||
type="no-match"
|
||||
></redaction-empty-state>
|
||||
@ -124,7 +133,11 @@
|
||||
<cdk-virtual-scroll-viewport [itemSize]="80" redactionHasScrollbar>
|
||||
<!-- Table lines -->
|
||||
<div
|
||||
*cdkVirtualFor="let attribute of displayedEntities | sortBy: sortingOption.order:sortingOption.column"
|
||||
*cdkVirtualFor="
|
||||
let attribute of displayedEntities$
|
||||
| async
|
||||
| sortBy: sortingOption.order:sortingOption.column
|
||||
"
|
||||
class="table-item"
|
||||
>
|
||||
<div (click)="toggleEntitySelected($event, attribute)" class="selection-column">
|
||||
|
||||
@ -1,26 +1,34 @@
|
||||
import { Component, ElementRef, Injector, OnInit, ViewChild } from '@angular/core';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
ElementRef,
|
||||
Injector,
|
||||
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';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||
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';
|
||||
|
||||
@Component({
|
||||
templateUrl: './file-attributes-listing-screen.component.html',
|
||||
styleUrls: ['./file-attributes-listing-screen.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [FilterService, SearchService, ScreenStateService, SortingService]
|
||||
})
|
||||
export class FileAttributesListingScreenComponent extends BaseListingComponent<FileAttributeConfig> implements OnInit {
|
||||
protected readonly _searchKey = 'label';
|
||||
protected readonly _selectionKey = 'id';
|
||||
export class FileAttributesListingScreenComponent
|
||||
extends BaseListingComponent<FileAttributeConfig>
|
||||
implements OnInit
|
||||
{
|
||||
private _existingConfiguration: FileAttributesConfig;
|
||||
|
||||
@ViewChild('fileInput') private _fileInput: ElementRef;
|
||||
|
||||
constructor(
|
||||
@ -34,9 +42,9 @@ export class FileAttributesListingScreenComponent extends BaseListingComponent<F
|
||||
) {
|
||||
super(_injector);
|
||||
this._sortingService.setScreenName(ScreenNames.FILE_ATTRIBUTES_LISTING);
|
||||
this._appStateService.activateDossierTemplate(
|
||||
_activatedRoute.snapshot.params.dossierTemplateId
|
||||
);
|
||||
this._searchService.setSearchKey('label');
|
||||
this._screenStateService.setIdKey('id');
|
||||
_appStateService.activateDossierTemplate(_activatedRoute.snapshot.params.dossierTemplateId);
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
@ -67,7 +75,10 @@ export class FileAttributesListingScreenComponent extends BaseListingComponent<F
|
||||
.toPromise();
|
||||
} else {
|
||||
await this._fileAttributesService
|
||||
.deleteFileAttributes(this.selectedEntitiesIds, this._appStateService.activeDossierTemplateId)
|
||||
.deleteFileAttributes(
|
||||
this._screenStateService.selectedEntitiesIds,
|
||||
this._appStateService.activeDossierTemplateId
|
||||
)
|
||||
.toPromise();
|
||||
}
|
||||
await this._loadData();
|
||||
@ -86,9 +97,7 @@ export class FileAttributesListingScreenComponent extends BaseListingComponent<F
|
||||
dossierTemplateId: this._appStateService.activeDossierTemplateId,
|
||||
existingConfiguration: this._existingConfiguration
|
||||
},
|
||||
async () => {
|
||||
await this._loadData();
|
||||
}
|
||||
async () => await this._loadData()
|
||||
);
|
||||
}
|
||||
|
||||
@ -99,10 +108,10 @@ export class FileAttributesListingScreenComponent extends BaseListingComponent<F
|
||||
.getFileAttributesConfiguration(this._appStateService.activeDossierTemplateId)
|
||||
.toPromise();
|
||||
this._existingConfiguration = response;
|
||||
this.allEntities = response?.fileAttributeConfigs || [];
|
||||
this._screenStateService.setEntities(response?.fileAttributeConfigs || []);
|
||||
} catch (e) {
|
||||
} finally {
|
||||
this._executeSearchImmediately();
|
||||
this.filterService.filterEntities();
|
||||
this._loadingService.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@ -114,12 +114,6 @@
|
||||
>
|
||||
{{ entity.dossierName }}
|
||||
</div>
|
||||
<div class="small-label stats-subtitle">
|
||||
<div>
|
||||
<mat-icon svgIcon="red:template"></mat-icon>
|
||||
{{ getDossierTemplate(entity.dossierTemplateId).name }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="small-label stats-subtitle">
|
||||
<div>
|
||||
<mat-icon svgIcon="red:user"></mat-icon>
|
||||
@ -144,7 +138,7 @@
|
||||
</div>
|
||||
|
||||
<div class="small-label">
|
||||
{{ entity.softDeletedTime | date: 'd MMM. yyyy hh:mm' }}
|
||||
{{ entity.softDeletedTime | date: 'd MMM. yyyy, hh:mm a' }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
@ -30,7 +30,7 @@ redaction-table-col-name::ng-deep {
|
||||
}
|
||||
|
||||
> div {
|
||||
height: 90px;
|
||||
height: 80px;
|
||||
padding: 0 24px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { ChangeDetectionStrategy, Component, Injector, OnInit } from '@angular/core';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { Dossier, DossierTemplateModel } from '@redaction/red-ui-http';
|
||||
import { Dossier, DossierTemplateModel, StatusControllerService } from '@redaction/red-ui-http';
|
||||
import { LoadingService } from '../../../../services/loading.service';
|
||||
import { AppConfigKey, AppConfigService } from '../../../app-config/app-config.service';
|
||||
import * as moment from 'moment';
|
||||
@ -9,8 +9,9 @@ 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 { NewBaseListingComponent } from '../../../shared/base/new-base-listing.component';
|
||||
import { BaseListingComponent } from '../../../shared/base/base-listing.component';
|
||||
import { DossiersService } from '../../../dossier/services/dossiers.service';
|
||||
import { tap } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
templateUrl: './trash-screen.component.html',
|
||||
@ -18,7 +19,7 @@ import { DossiersService } from '../../../dossier/services/dossiers.service';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [FilterService, SearchService, ScreenStateService, SortingService, DossiersService]
|
||||
})
|
||||
export class TrashScreenComponent extends NewBaseListingComponent<Dossier> implements OnInit {
|
||||
export class TrashScreenComponent extends BaseListingComponent<Dossier> implements OnInit {
|
||||
readonly itemSize = 85;
|
||||
private readonly _deleteRetentionHours = this._appConfigService.getConfig(
|
||||
AppConfigKey.DELETE_RETENTION_HOURS
|
||||
@ -26,6 +27,7 @@ export class TrashScreenComponent extends NewBaseListingComponent<Dossier> imple
|
||||
|
||||
constructor(
|
||||
private readonly _appStateService: AppStateService,
|
||||
private readonly _statusControllerService: StatusControllerService,
|
||||
readonly permissionsService: PermissionsService,
|
||||
protected readonly _injector: Injector,
|
||||
private readonly _dossiersService: DossiersService,
|
||||
@ -50,10 +52,6 @@ export class TrashScreenComponent extends NewBaseListingComponent<Dossier> imple
|
||||
this._screenStateService.setEntities(await this._dossiersService.getDeletedDossiers());
|
||||
}
|
||||
|
||||
getDossierTemplate(dossierTemplateId: string): DossierTemplateModel {
|
||||
return this._appStateService.getDossierTemplateById(dossierTemplateId);
|
||||
}
|
||||
|
||||
getRestoreDate(softDeletedTime: string): string {
|
||||
return moment(softDeletedTime).add(this._deleteRetentionHours, 'hours').toISOString();
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ import { FilterService } from '../../../shared/services/filter.service';
|
||||
import { SearchService } from '../../../shared/services/search.service';
|
||||
import { ScreenStateService } from '../../../shared/services/screen-state.service';
|
||||
import { SortingService } from '../../../../services/sorting.service';
|
||||
import { NewBaseListingComponent } from '../../../shared/base/new-base-listing.component';
|
||||
import { BaseListingComponent } from '../../../shared/base/base-listing.component';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
@ -29,7 +29,7 @@ import { map } from 'rxjs/operators';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [FilterService, SearchService, ScreenStateService, SortingService]
|
||||
})
|
||||
export class UserListingScreenComponent extends NewBaseListingComponent<User> implements OnInit {
|
||||
export class UserListingScreenComponent extends BaseListingComponent<User> implements OnInit {
|
||||
collapsedDetails = false;
|
||||
chartData: DoughnutChartConfig[] = [];
|
||||
@ViewChildren(InitialsAvatarComponent)
|
||||
|
||||
@ -35,7 +35,7 @@ import { ButtonConfig } from '../../../shared/components/page-header/models/butt
|
||||
import { FilterService } from '../../../shared/services/filter.service';
|
||||
import { SearchService } from '../../../shared/services/search.service';
|
||||
import { ScreenStateService } from '../../../shared/services/screen-state.service';
|
||||
import { NewBaseListingComponent } from '../../../shared/base/new-base-listing.component';
|
||||
import { BaseListingComponent } from '../../../shared/base/base-listing.component';
|
||||
import { ScreenNames, SortingService } from '../../../../services/sorting.service';
|
||||
|
||||
@Component({
|
||||
@ -45,7 +45,7 @@ import { ScreenNames, SortingService } from '../../../../services/sorting.servic
|
||||
providers: [FilterService, SearchService, ScreenStateService, SortingService]
|
||||
})
|
||||
export class DossierListingScreenComponent
|
||||
extends NewBaseListingComponent<DossierWrapper>
|
||||
extends BaseListingComponent<DossierWrapper>
|
||||
implements OnInit, OnDestroy, OnAttach, OnDetach
|
||||
{
|
||||
dossiersChartData: DoughnutChartConfig[] = [];
|
||||
|
||||
@ -43,7 +43,7 @@ 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 { NewBaseListingComponent } from '../../../shared/base/new-base-listing.component';
|
||||
import { BaseListingComponent } from '../../../shared/base/base-listing.component';
|
||||
|
||||
@Component({
|
||||
templateUrl: './dossier-overview-screen.component.html',
|
||||
@ -51,7 +51,7 @@ import { NewBaseListingComponent } from '../../../shared/base/new-base-listing.c
|
||||
providers: [FilterService, SearchService, ScreenStateService, SortingService]
|
||||
})
|
||||
export class DossierOverviewScreenComponent
|
||||
extends NewBaseListingComponent<FileStatusWrapper>
|
||||
extends BaseListingComponent<FileStatusWrapper>
|
||||
implements OnInit, OnDestroy, OnDetach, OnAttach
|
||||
{
|
||||
collapsedDetails = false;
|
||||
|
||||
@ -1,177 +1,83 @@
|
||||
import { ChangeDetectorRef, Component, Injector, ViewChild } from '@angular/core';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { Component, Injector, ViewChild } from '@angular/core';
|
||||
import { SortingOption, SortingService } from '@services/sorting.service';
|
||||
import { FilterModel } from '../components/filters/popup-filter/model/filter.model';
|
||||
import { QuickFiltersComponent } from '../components/filters/quick-filters/quick-filters.component';
|
||||
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
||||
import { FilterService } from '../services/filter.service';
|
||||
import { SearchService } from '../services/search.service';
|
||||
import { ScreenStateService } from '../services/screen-state.service';
|
||||
import { getFilteredEntities } from '../components/filters/popup-filter/utils/filter-utils';
|
||||
import { debounce } from '../../../utils/debounce';
|
||||
import { FilterWrapper } from '../components/filters/popup-filter/model/filter-wrapper.model';
|
||||
|
||||
// Functionalities: Filter, search, select, sort
|
||||
|
||||
// Usage: overwrite necessary methods/members in your component
|
||||
import { Observable } from 'rxjs';
|
||||
import { FilterModel } from '../components/filters/popup-filter/model/filter.model';
|
||||
|
||||
@Component({ template: '' })
|
||||
export abstract class BaseListingComponent<T = any> {
|
||||
allEntities: T[] = [];
|
||||
filteredEntities: T[] = [];
|
||||
displayedEntities: T[] = [];
|
||||
selectedEntitiesIds: string[] = [];
|
||||
searchForm: FormGroup;
|
||||
showResetFilters = false;
|
||||
@ViewChild(CdkVirtualScrollViewport) scrollViewport: CdkVirtualScrollViewport;
|
||||
export abstract class BaseListingComponent<T> {
|
||||
@ViewChild(CdkVirtualScrollViewport)
|
||||
readonly scrollViewport: CdkVirtualScrollViewport;
|
||||
|
||||
protected readonly _formBuilder: FormBuilder;
|
||||
protected readonly _changeDetectorRef: ChangeDetectorRef;
|
||||
readonly filterService: FilterService<T>;
|
||||
protected readonly _sortingService: SortingService;
|
||||
protected readonly _filterService: FilterService<T>;
|
||||
protected readonly _searchService: SearchService<T>;
|
||||
protected readonly _screenStateService: ScreenStateService<T>;
|
||||
|
||||
// ----
|
||||
// Overwrite in child class:
|
||||
protected readonly _searchKey: string;
|
||||
protected readonly _selectionKey: string;
|
||||
// Overwrite this in ngOnInit
|
||||
@ViewChild(QuickFiltersComponent)
|
||||
protected _quickFilters: QuickFiltersComponent<T>;
|
||||
|
||||
private _searchValue = '';
|
||||
|
||||
protected constructor(protected readonly _injector: Injector) {
|
||||
this._formBuilder = this._injector.get<FormBuilder>(FormBuilder);
|
||||
this._changeDetectorRef = this._injector.get<ChangeDetectorRef>(ChangeDetectorRef);
|
||||
this.filterService = this._injector.get<FilterService<T>>(FilterService);
|
||||
this._sortingService = this._injector.get<SortingService>(SortingService);
|
||||
this._filterService = this._injector.get<FilterService<T>>(FilterService);
|
||||
this._searchService = this._injector.get<SearchService<T>>(SearchService);
|
||||
this._screenStateService = this._injector.get<ScreenStateService<T>>(ScreenStateService);
|
||||
}
|
||||
|
||||
get areAllEntitiesSelected() {
|
||||
return (
|
||||
this.displayedEntities.length !== 0 &&
|
||||
this.selectedEntitiesIds.length === this.displayedEntities.length
|
||||
);
|
||||
get selectedEntitiesIds$(): Observable<string[]> {
|
||||
return this._screenStateService.selectedEntitiesIds$;
|
||||
}
|
||||
|
||||
get areSomeEntitiesSelected() {
|
||||
return this.selectedEntitiesIds.length > 0;
|
||||
get displayedEntities$(): Observable<T[]> {
|
||||
return this._screenStateService.displayedEntities$;
|
||||
}
|
||||
|
||||
get allEntities$(): Observable<T[]> {
|
||||
return this._screenStateService.entities$;
|
||||
}
|
||||
|
||||
get allEntities(): T[] {
|
||||
return this._screenStateService.entities;
|
||||
}
|
||||
|
||||
get areAllEntitiesSelected() {
|
||||
return this._screenStateService.areAllEntitiesSelected;
|
||||
}
|
||||
|
||||
get areSomeEntitiesSelected$() {
|
||||
return this._screenStateService.areSomeEntitiesSelected$;
|
||||
}
|
||||
|
||||
get sortingOption(): SortingOption {
|
||||
return this._sortingService.getSortingOption();
|
||||
}
|
||||
|
||||
protected get _filters(): FilterWrapper[] {
|
||||
return [];
|
||||
getFilter$(slug: string): Observable<FilterModel[]> {
|
||||
return this.filterService.getFilter$(slug);
|
||||
}
|
||||
|
||||
// ----
|
||||
|
||||
private get _getSearchKey(): string {
|
||||
if (!this._searchKey) throw new Error('Not implemented');
|
||||
|
||||
return this._searchKey;
|
||||
}
|
||||
|
||||
// Search
|
||||
|
||||
private get _getSelectionKey(): string {
|
||||
if (!this._selectionKey) throw new Error('Not implemented');
|
||||
|
||||
return this._selectionKey;
|
||||
}
|
||||
|
||||
filtersChanged(filters?: { [key: string]: FilterModel[] } | FilterModel[]): void {
|
||||
if (filters instanceof Array) this.showResetFilters = !!filters.find(f => f.checked);
|
||||
else
|
||||
for (const key of Object.keys(filters ?? {})) {
|
||||
for (let idx = 0; idx < this[key]?.length; ++idx) {
|
||||
this[key][idx] = filters[key][idx];
|
||||
}
|
||||
}
|
||||
|
||||
this._filterEntities();
|
||||
get searchForm() {
|
||||
return this._searchService.searchForm;
|
||||
}
|
||||
|
||||
resetFilters() {
|
||||
this.showResetFilters = false;
|
||||
this.filtersChanged();
|
||||
}
|
||||
|
||||
// Filter
|
||||
toggleEntitySelected($event: MouseEvent, entity: T) {
|
||||
$event.stopPropagation();
|
||||
const idx = this.selectedEntitiesIds.indexOf(entity[this._getSelectionKey]);
|
||||
if (idx === -1) {
|
||||
this.selectedEntitiesIds.push(entity[this._getSelectionKey]);
|
||||
} else {
|
||||
this.selectedEntitiesIds.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
|
||||
toggleSelectAll() {
|
||||
if (this.areSomeEntitiesSelected) {
|
||||
this.selectedEntitiesIds = [];
|
||||
} else {
|
||||
this.selectedEntitiesIds = this.displayedEntities.map(
|
||||
entity => entity[this._getSelectionKey]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
isSelected(entity: T) {
|
||||
return this.selectedEntitiesIds.indexOf(entity[this._getSelectionKey]) !== -1;
|
||||
this.filterService.reset();
|
||||
}
|
||||
|
||||
toggleSort($event) {
|
||||
this._sortingService.toggleSort($event);
|
||||
}
|
||||
|
||||
// Selection
|
||||
|
||||
protected _preFilter() {
|
||||
return;
|
||||
toggleSelectAll() {
|
||||
return this._screenStateService.toggleSelectAll();
|
||||
}
|
||||
|
||||
protected _searchField(entity: T): string {
|
||||
return entity[this._getSearchKey];
|
||||
toggleEntitySelected(event: MouseEvent, entity: T) {
|
||||
event.stopPropagation();
|
||||
return this._screenStateService.toggleEntitySelected(entity);
|
||||
}
|
||||
|
||||
@debounce(200)
|
||||
executeSearch(value: string) {
|
||||
this._searchValue = value;
|
||||
this._executeSearchImmediately();
|
||||
}
|
||||
|
||||
protected _executeSearchImmediately() {
|
||||
this.displayedEntities = (
|
||||
this._filters.length ? this.filteredEntities : this.allEntities
|
||||
).filter(entity =>
|
||||
this._searchField(entity).toLowerCase().includes(this._searchValue.toLowerCase())
|
||||
);
|
||||
|
||||
this._updateSelection();
|
||||
}
|
||||
|
||||
protected _updateSelection() {
|
||||
if (this._selectionKey) {
|
||||
this.selectedEntitiesIds = this.displayedEntities
|
||||
.map(entity => entity[this._getSelectionKey])
|
||||
.filter(id => this.selectedEntitiesIds.includes(id));
|
||||
}
|
||||
}
|
||||
|
||||
// Sort
|
||||
|
||||
protected _filterEntities() {
|
||||
this._preFilter();
|
||||
this.filteredEntities = getFilteredEntities(this.allEntities, this._filters);
|
||||
this.executeSearch(this._searchValue);
|
||||
this._changeDetectorRef.detectChanges();
|
||||
isSelected(entity: T) {
|
||||
return this._screenStateService.isSelected(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,83 +0,0 @@
|
||||
import { Component, Injector, ViewChild } from '@angular/core';
|
||||
import { SortingOption, SortingService } from '@services/sorting.service';
|
||||
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
||||
import { FilterService } from '../services/filter.service';
|
||||
import { SearchService } from '../services/search.service';
|
||||
import { ScreenStateService } from '../services/screen-state.service';
|
||||
import { Observable } from 'rxjs';
|
||||
import { FilterModel } from '../components/filters/popup-filter/model/filter.model';
|
||||
|
||||
@Component({ template: '' })
|
||||
export abstract class NewBaseListingComponent<T> {
|
||||
@ViewChild(CdkVirtualScrollViewport)
|
||||
readonly scrollViewport: CdkVirtualScrollViewport;
|
||||
|
||||
readonly filterService: FilterService<T>;
|
||||
protected readonly _sortingService: SortingService;
|
||||
protected readonly _searchService: SearchService<T>;
|
||||
protected readonly _screenStateService: ScreenStateService<T>;
|
||||
|
||||
protected constructor(protected readonly _injector: Injector) {
|
||||
this.filterService = this._injector.get<FilterService<T>>(FilterService);
|
||||
this._sortingService = this._injector.get<SortingService>(SortingService);
|
||||
this._searchService = this._injector.get<SearchService<T>>(SearchService);
|
||||
this._screenStateService = this._injector.get<ScreenStateService<T>>(ScreenStateService);
|
||||
}
|
||||
|
||||
get selectedEntitiesIds$(): Observable<string[]> {
|
||||
return this._screenStateService.selectedEntitiesIds$;
|
||||
}
|
||||
|
||||
get displayedEntities$(): Observable<T[]> {
|
||||
return this._screenStateService.displayedEntities$;
|
||||
}
|
||||
|
||||
get allEntities$(): Observable<T[]> {
|
||||
return this._screenStateService.entities$;
|
||||
}
|
||||
|
||||
get allEntities(): T[] {
|
||||
return this._screenStateService.entities;
|
||||
}
|
||||
|
||||
get areAllEntitiesSelected() {
|
||||
return this._screenStateService.areAllEntitiesSelected;
|
||||
}
|
||||
|
||||
get areSomeEntitiesSelected$() {
|
||||
return this._screenStateService.areSomeEntitiesSelected$;
|
||||
}
|
||||
|
||||
get sortingOption(): SortingOption {
|
||||
return this._sortingService.getSortingOption();
|
||||
}
|
||||
|
||||
getFilter$(slug: string): Observable<FilterModel[]> {
|
||||
return this.filterService.getFilter$(slug);
|
||||
}
|
||||
|
||||
get searchForm() {
|
||||
return this._searchService.searchForm;
|
||||
}
|
||||
|
||||
resetFilters() {
|
||||
this.filterService.reset();
|
||||
}
|
||||
|
||||
toggleSort($event) {
|
||||
this._sortingService.toggleSort($event);
|
||||
}
|
||||
|
||||
toggleSelectAll() {
|
||||
return this._screenStateService.toggleSelectAll();
|
||||
}
|
||||
|
||||
toggleEntitySelected(event: MouseEvent, entity: T) {
|
||||
event.stopPropagation();
|
||||
return this._screenStateService.toggleEntitySelected(entity);
|
||||
}
|
||||
|
||||
isSelected(entity: T) {
|
||||
return this._screenStateService.isSelected(entity);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user