wip page header component
This commit is contained in:
parent
5adf7379c9
commit
fe8bc8826d
@ -1,17 +1,7 @@
|
||||
<section>
|
||||
<div class="overlay-shadow"></div>
|
||||
|
||||
<div class="page-header">
|
||||
<div class="breadcrumb" translate="trash.label"></div>
|
||||
|
||||
<redaction-circle-button
|
||||
*ngIf="permissionsService.isUser()"
|
||||
icon="red:close"
|
||||
redactionNavigateLastDossiersScreen
|
||||
tooltip="common.close"
|
||||
tooltipPosition="below"
|
||||
></redaction-circle-button>
|
||||
</div>
|
||||
<redaction-page-header pageLabel="trash.label" [showCloseButton]="true"></redaction-page-header>
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="content-container">
|
||||
|
||||
@ -38,7 +38,3 @@ redaction-table-col-name::ng-deep {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.page-header .actions > *:not(:last-child) {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
@ -1,53 +1,11 @@
|
||||
<section>
|
||||
<div class="page-header">
|
||||
<div class="filters">
|
||||
<div translate="filters.filter-by"></div>
|
||||
<redaction-popup-filter
|
||||
(filtersChanged)="filtersChanged()"
|
||||
[filterLabel]="'filters.status'"
|
||||
[icon]="'red:status'"
|
||||
[primaryFilters]="statusFilters"
|
||||
></redaction-popup-filter>
|
||||
<redaction-popup-filter
|
||||
(filtersChanged)="filtersChanged()"
|
||||
[filterLabel]="'filters.people'"
|
||||
[icon]="'red:user'"
|
||||
[primaryFilters]="peopleFilters"
|
||||
></redaction-popup-filter>
|
||||
<redaction-popup-filter
|
||||
(filtersChanged)="filtersChanged()"
|
||||
[filterLabel]="'filters.needs-work'"
|
||||
[filterTemplate]="needsWorkTemplate"
|
||||
[icon]="'red:needs-work'"
|
||||
[primaryFilters]="needsWorkFilters"
|
||||
></redaction-popup-filter>
|
||||
<redaction-popup-filter
|
||||
(filtersChanged)="filtersChanged()"
|
||||
*ngIf="dossierTemplateFilters.length > 1"
|
||||
[filterLabel]="'filters.dossier-templates'"
|
||||
[icon]="'red:template'"
|
||||
[primaryFilters]="dossierTemplateFilters"
|
||||
></redaction-popup-filter>
|
||||
<redaction-input-with-action
|
||||
[form]="searchForm"
|
||||
placeholder="dossier-listing.search"
|
||||
type="search"
|
||||
></redaction-input-with-action>
|
||||
<div
|
||||
(click)="resetFilters()"
|
||||
*ngIf="hasActiveFilters"
|
||||
class="reset-filters"
|
||||
translate="reset-filters"
|
||||
></div>
|
||||
</div>
|
||||
<redaction-icon-button
|
||||
(action)="openAddDossierDialog()"
|
||||
*ngIf="permissionsService.isManager()"
|
||||
icon="red:plus"
|
||||
text="dossier-listing.add-new"
|
||||
type="primary"
|
||||
></redaction-icon-button>
|
||||
</div>
|
||||
<redaction-page-header
|
||||
(filtersChanged)="filtersChanged()"
|
||||
(searchChanged)="executeSearch($event)"
|
||||
[filterConfigs]="filterConfigs"
|
||||
[buttonConfigs]="buttonConfigs"
|
||||
[searchPlaceholder]="'dossier-listing.search'"
|
||||
></redaction-page-header>
|
||||
|
||||
<div class="overlay-shadow"></div>
|
||||
|
||||
@ -135,7 +93,7 @@
|
||||
<div class="small-label stats-subtitle">
|
||||
<div>
|
||||
<mat-icon svgIcon="red:document"></mat-icon>
|
||||
{{ documentCount(dw) }}
|
||||
{{ filesCount(dw) }}
|
||||
</div>
|
||||
<div>
|
||||
<mat-icon svgIcon="red:pages"></mat-icon>
|
||||
|
||||
@ -1,12 +1,4 @@
|
||||
import {
|
||||
Component,
|
||||
Injector,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
QueryList,
|
||||
ViewChild,
|
||||
ViewChildren
|
||||
} from '@angular/core';
|
||||
import { Component, Injector, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';
|
||||
import { Dossier, DossierTemplateModel } from '@redaction/red-ui-http';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { UserService } from '@services/user.service';
|
||||
@ -25,7 +17,6 @@ import { DossiersDialogService } from '../../services/dossiers-dialog.service';
|
||||
import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||
import { OnAttach, OnDetach } from '@utils/custom-route-reuse.strategy';
|
||||
import { FilterModel } from '@shared/components/filters/popup-filter/model/filter.model';
|
||||
import { PopupFilterComponent } from '@shared/components/filters/popup-filter/popup-filter.component';
|
||||
import {
|
||||
annotationFilterChecker,
|
||||
dossierMemberChecker,
|
||||
@ -33,11 +24,11 @@ import {
|
||||
dossierTemplateChecker,
|
||||
processFilters
|
||||
} from '@shared/components/filters/popup-filter/utils/filter-utils';
|
||||
import { QuickFiltersComponent } from '../../../shared/components/filters/quick-filters/quick-filters.component';
|
||||
import { QuickFiltersComponent } from '@shared/components/filters/quick-filters/quick-filters.component';
|
||||
import { UserPreferenceService } from '../../../../services/user-preference.service';
|
||||
import { ButtonConfig, FilterConfig } from '@shared/components/page-header/page-header.component';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-dossier-listing-screen',
|
||||
templateUrl: './dossier-listing-screen.component.html',
|
||||
styleUrls: ['./dossier-listing-screen.component.scss']
|
||||
})
|
||||
@ -58,6 +49,16 @@ export class DossierListingScreenComponent
|
||||
};
|
||||
quickFilters: FilterModel[];
|
||||
readonly itemSize = 85;
|
||||
filterConfigs: FilterConfig[];
|
||||
buttonConfigs: ButtonConfig[] = [
|
||||
{
|
||||
label: 'dossier-listing.add-new',
|
||||
action: () => this.openAddDossierDialog(),
|
||||
hide: !this.permissionsService.isManager(),
|
||||
icon: 'red:plus',
|
||||
type: 'primary'
|
||||
}
|
||||
];
|
||||
|
||||
protected readonly _searchKey = 'name';
|
||||
protected readonly _sortKey = 'dossier-listing';
|
||||
@ -67,10 +68,10 @@ export class DossierListingScreenComponent
|
||||
private _routerEventsScrollPositionSub: Subscription;
|
||||
private _fileChangedSub: Subscription;
|
||||
|
||||
@ViewChildren(PopupFilterComponent)
|
||||
private readonly _filterList: QueryList<PopupFilterComponent>;
|
||||
@ViewChild(QuickFiltersComponent)
|
||||
protected readonly _quickFiltersComponent: QuickFiltersComponent;
|
||||
@ViewChild('needsWorkTemplate', { read: TemplateRef, static: true })
|
||||
private readonly _needsWorkTemplate: TemplateRef<any>;
|
||||
|
||||
constructor(
|
||||
readonly permissionsService: PermissionsService,
|
||||
@ -155,7 +156,7 @@ export class DossierListingScreenComponent
|
||||
this._lastScrollPosition = this.scrollViewport.measureScrollOffset('top');
|
||||
}
|
||||
});
|
||||
this._filterComponents = [...this._filterList.toArray(), this._quickFiltersComponent];
|
||||
this._filterComponents = [this._quickFiltersComponent];
|
||||
}
|
||||
|
||||
ngOnAttach() {
|
||||
@ -175,7 +176,7 @@ export class DossierListingScreenComponent
|
||||
this._fileChangedSub.unsubscribe();
|
||||
}
|
||||
|
||||
documentCount(dossier: DossierWrapper) {
|
||||
filesCount(dossier: DossierWrapper) {
|
||||
return dossier.files.length;
|
||||
}
|
||||
|
||||
@ -248,12 +249,9 @@ export class DossierListingScreenComponent
|
||||
const allDistinctDossierTemplates = new Set<string>();
|
||||
this.allEntities.forEach(entry => {
|
||||
// all people
|
||||
entry.dossier.memberIds.forEach(memberId => allDistinctPeople.add(memberId));
|
||||
entry.dossier.memberIds.forEach(f => allDistinctPeople.add(f));
|
||||
// file statuses
|
||||
entry.files.forEach(file => {
|
||||
allDistinctFileStatus.add(file.status);
|
||||
});
|
||||
|
||||
entry.files.forEach(f => allDistinctFileStatus.add(f.status));
|
||||
// Needs work
|
||||
entry.files.forEach(file => {
|
||||
if (this.permissionsService.fileRequiresReanalysis(file))
|
||||
@ -312,7 +310,39 @@ export class DossierListingScreenComponent
|
||||
dossierTemplateFilters
|
||||
);
|
||||
|
||||
this.quickFilters = [
|
||||
this._createFilterConfigs();
|
||||
this._createQuickFilters();
|
||||
}
|
||||
|
||||
private _createFilterConfigs() {
|
||||
this.filterConfigs = [
|
||||
{
|
||||
label: 'filters.status',
|
||||
primaryFilters: this.statusFilters,
|
||||
icon: 'red:status'
|
||||
},
|
||||
{
|
||||
label: 'filters.people',
|
||||
primaryFilters: this.peopleFilters,
|
||||
icon: 'red:user'
|
||||
},
|
||||
{
|
||||
label: 'filters.needs-work',
|
||||
primaryFilters: this.needsWorkFilters,
|
||||
icon: 'red:needs-work',
|
||||
filterTemplate: this._needsWorkTemplate
|
||||
},
|
||||
{
|
||||
label: 'filters.dossier-templates',
|
||||
primaryFilters: this.dossierTemplateFilters,
|
||||
icon: 'red:template',
|
||||
hide: this.dossierTemplateFilters.length <= 1
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
private _createQuickFilters() {
|
||||
const filters = [
|
||||
{
|
||||
key: this.user.id,
|
||||
label: 'dossier-listing.quick-filters.my-dossiers',
|
||||
@ -333,7 +363,9 @@ export class DossierListingScreenComponent
|
||||
label: 'dossier-listing.quick-filters.other',
|
||||
checker: (dw: DossierWrapper) => !dw.memberIds.includes(this.user.id)
|
||||
}
|
||||
].filter(
|
||||
];
|
||||
|
||||
this.quickFilters = filters.filter(
|
||||
f =>
|
||||
f.label === 'dossier-listing.quick-filters.my-dossiers' ||
|
||||
this._userPreferenceService.areDevFeaturesEnabled
|
||||
|
||||
@ -1,84 +1,91 @@
|
||||
<section *ngIf="!!activeDossier">
|
||||
<div class="page-header">
|
||||
<div class="filters">
|
||||
<div translate="filters.filter-by"></div>
|
||||
<redaction-popup-filter
|
||||
(filtersChanged)="filtersChanged()"
|
||||
[filterLabel]="'filters.status'"
|
||||
[icon]="'red:status'"
|
||||
[primaryFilters]="statusFilters"
|
||||
></redaction-popup-filter>
|
||||
<redaction-popup-filter
|
||||
(filtersChanged)="filtersChanged()"
|
||||
[filterLabel]="'filters.assigned-people'"
|
||||
[icon]="'red:user'"
|
||||
[primaryFilters]="peopleFilters"
|
||||
></redaction-popup-filter>
|
||||
<redaction-popup-filter
|
||||
(filtersChanged)="filtersChanged()"
|
||||
[filterLabel]="'filters.needs-work'"
|
||||
[filterTemplate]="needsWorkTemplate"
|
||||
[icon]="'red:needs-work'"
|
||||
[primaryFilters]="needsWorkFilters"
|
||||
></redaction-popup-filter>
|
||||
<redaction-page-header
|
||||
(filtersChanged)="filtersChanged()"
|
||||
(searchChanged)="executeSearch($event)"
|
||||
[filterConfigs]="filterConfigs"
|
||||
[actionConfigs]="actionConfigs"
|
||||
[searchPlaceholder]="'dossier-overview.search'"
|
||||
></redaction-page-header>
|
||||
<!-- <div class="page-header">-->
|
||||
<!-- <div class="filters">-->
|
||||
<!-- <div translate="filters.filter-by"></div>-->
|
||||
<!-- <redaction-popup-filter-->
|
||||
<!-- (filtersChanged)="filtersChanged()"-->
|
||||
<!-- [filterLabel]="'filters.status'"-->
|
||||
<!-- [icon]="'red:status'"-->
|
||||
<!-- [primaryFilters]="statusFilters"-->
|
||||
<!-- ></redaction-popup-filter>-->
|
||||
<!-- <redaction-popup-filter-->
|
||||
<!-- (filtersChanged)="filtersChanged()"-->
|
||||
<!-- [filterLabel]="'filters.assigned-people'"-->
|
||||
<!-- [icon]="'red:user'"-->
|
||||
<!-- [primaryFilters]="peopleFilters"-->
|
||||
<!-- ></redaction-popup-filter>-->
|
||||
<!-- <redaction-popup-filter-->
|
||||
<!-- (filtersChanged)="filtersChanged()"-->
|
||||
<!-- [filterLabel]="'filters.needs-work'"-->
|
||||
<!-- [filterTemplate]="needsWorkTemplate"-->
|
||||
<!-- [icon]="'red:needs-work'"-->
|
||||
<!-- [primaryFilters]="needsWorkFilters"-->
|
||||
<!-- ></redaction-popup-filter>-->
|
||||
|
||||
<redaction-input-with-action
|
||||
[form]="searchForm"
|
||||
placeholder="dossier-overview.search"
|
||||
type="search"
|
||||
></redaction-input-with-action>
|
||||
<!-- <redaction-input-with-action-->
|
||||
<!-- [form]="searchForm"-->
|
||||
<!-- [placeholder]="'dossier-overview.search'"-->
|
||||
<!-- type="search"-->
|
||||
<!-- ></redaction-input-with-action>-->
|
||||
|
||||
<div
|
||||
(click)="resetFilters()"
|
||||
*ngIf="hasActiveFilters"
|
||||
class="reset-filters"
|
||||
translate="reset-filters"
|
||||
></div>
|
||||
</div>
|
||||
<!-- <div-->
|
||||
<!-- (click)="resetFilters()"-->
|
||||
<!-- *ngIf="hasActiveFilters"-->
|
||||
<!-- class="reset-filters"-->
|
||||
<!-- translate="reset-filters"-->
|
||||
<!-- ></div>-->
|
||||
<!-- </div>-->
|
||||
|
||||
<div class="actions">
|
||||
<redaction-circle-button
|
||||
(action)="openEditDossierDialog($event)"
|
||||
*ngIf="permissionsService.isManager()"
|
||||
icon="red:edit"
|
||||
tooltip="dossier-overview.header-actions.edit"
|
||||
tooltipPosition="below"
|
||||
></redaction-circle-button>
|
||||
<!-- <div class="actions">-->
|
||||
<!-- <redaction-circle-button-->
|
||||
<!-- (action)="openEditDossierDialog($event)"-->
|
||||
<!-- *ngIf="permissionsService.isManager()"-->
|
||||
<!-- icon="red:edit"-->
|
||||
<!-- tooltip="dossier-overview.header-actions.edit"-->
|
||||
<!-- tooltipPosition="below"-->
|
||||
<!-- ></redaction-circle-button>-->
|
||||
|
||||
<redaction-file-download-btn
|
||||
[disabled]="areSomeEntitiesSelected"
|
||||
[dossier]="activeDossier"
|
||||
[file]="allEntities"
|
||||
tooltipPosition="below"
|
||||
></redaction-file-download-btn>
|
||||
<!-- <redaction-file-download-btn-->
|
||||
<!-- [disabled]="areSomeEntitiesSelected"-->
|
||||
<!-- [dossier]="activeDossier"-->
|
||||
<!-- [file]="allEntities"-->
|
||||
<!-- tooltipPosition="below"-->
|
||||
<!-- ></redaction-file-download-btn>-->
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="reanalyseDossier()"
|
||||
*ngIf="permissionsService.displayReanalyseBtn()"
|
||||
[disabled]="areSomeEntitiesSelected"
|
||||
[tooltipClass]="'small ' + (areSomeEntitiesSelected ? '' : 'warn')"
|
||||
[tooltip]="'dossier-overview.new-rule.toast.actions.reanalyse-all'"
|
||||
icon="red:refresh"
|
||||
tooltipPosition="below"
|
||||
type="warn"
|
||||
></redaction-circle-button>
|
||||
<redaction-circle-button
|
||||
(action)="fileInput.click()"
|
||||
class="ml-14"
|
||||
icon="red:upload"
|
||||
tooltip="dossier-overview.header-actions.upload-document"
|
||||
tooltipPosition="below"
|
||||
type="primary"
|
||||
></redaction-circle-button>
|
||||
<redaction-circle-button
|
||||
[routerLink]="['/main/dossiers/']"
|
||||
class="ml-6"
|
||||
icon="red:close"
|
||||
tooltip="common.close"
|
||||
tooltipPosition="below"
|
||||
></redaction-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <redaction-circle-button-->
|
||||
<!-- (action)="reanalyseDossier()"-->
|
||||
<!-- *ngIf="permissionsService.displayReanalyseBtn()"-->
|
||||
<!-- [disabled]="areSomeEntitiesSelected"-->
|
||||
<!-- [tooltipClass]="'small ' + (areSomeEntitiesSelected ? '' : 'warn')"-->
|
||||
<!-- [tooltip]="'dossier-overview.new-rule.toast.actions.reanalyse-all'"-->
|
||||
<!-- icon="red:refresh"-->
|
||||
<!-- tooltipPosition="below"-->
|
||||
<!-- type="warn"-->
|
||||
<!-- ></redaction-circle-button>-->
|
||||
<!-- <redaction-circle-button-->
|
||||
<!-- (action)="fileInput.click()"-->
|
||||
<!-- class="ml-14"-->
|
||||
<!-- icon="red:upload"-->
|
||||
<!-- tooltip="dossier-overview.header-actions.upload-document"-->
|
||||
<!-- tooltipPosition="below"-->
|
||||
<!-- type="primary"-->
|
||||
<!-- ></redaction-circle-button>-->
|
||||
<!-- <redaction-circle-button-->
|
||||
<!-- [routerLink]="['/main/dossiers/']"-->
|
||||
<!-- class="ml-6"-->
|
||||
<!-- icon="red:close"-->
|
||||
<!-- tooltip="common.close"-->
|
||||
<!-- tooltipPosition="below"-->
|
||||
<!-- ></redaction-circle-button>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
|
||||
<div class="overlay-shadow"></div>
|
||||
|
||||
|
||||
@ -5,9 +5,8 @@ import {
|
||||
Injector,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
QueryList,
|
||||
ViewChild,
|
||||
ViewChildren
|
||||
TemplateRef,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import { NavigationStart, Router } from '@angular/router';
|
||||
import { NotificationService, NotificationType } from '@services/notification.service';
|
||||
@ -38,9 +37,12 @@ import {
|
||||
processFilters
|
||||
} from '@shared/components/filters/popup-filter/utils/filter-utils';
|
||||
import { FilterModel } from '@shared/components/filters/popup-filter/model/filter.model';
|
||||
import { PopupFilterComponent } from '@shared/components/filters/popup-filter/popup-filter.component';
|
||||
import { QuickFiltersComponent } from '../../../shared/components/filters/quick-filters/quick-filters.component';
|
||||
import { AppConfigService } from '../../../app-config/app-config.service';
|
||||
import {
|
||||
ActionConfig,
|
||||
FilterConfig
|
||||
} from '../../../shared/components/page-header/page-header.component';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-dossier-overview-screen',
|
||||
@ -61,6 +63,8 @@ export class DossierOverviewScreenComponent
|
||||
} = { needsWorkFilters: [], statusFilters: [] };
|
||||
readonly itemSize = 80;
|
||||
quickFilters: FilterModel[];
|
||||
filterConfigs: FilterConfig[];
|
||||
actionConfigs: ActionConfig[];
|
||||
|
||||
protected readonly _searchKey = 'searchField';
|
||||
protected readonly _selectionKey = 'fileId';
|
||||
@ -74,11 +78,10 @@ export class DossierOverviewScreenComponent
|
||||
private _lastScrollPosition: number;
|
||||
private _lastOpenedFileId = '';
|
||||
|
||||
@ViewChildren(PopupFilterComponent)
|
||||
private readonly _filterList: QueryList<PopupFilterComponent>;
|
||||
@ViewChild(QuickFiltersComponent)
|
||||
protected readonly _quickFiltersComponent: QuickFiltersComponent;
|
||||
|
||||
@ViewChild('needsWorkTemplate', { read: TemplateRef, static: true })
|
||||
private readonly _needsWorkTemplate: TemplateRef<any>;
|
||||
@ViewChild('fileInput') private _fileInput: ElementRef;
|
||||
|
||||
constructor(
|
||||
@ -182,7 +185,7 @@ export class DossierOverviewScreenComponent
|
||||
}
|
||||
});
|
||||
|
||||
this._filterComponents = [...this._filterList.toArray(), this._quickFiltersComponent];
|
||||
this._filterComponents = [this._quickFiltersComponent];
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
@ -393,10 +396,12 @@ export class DossierOverviewScreenComponent
|
||||
);
|
||||
this.needsWorkFilters = processFilters(this.needsWorkFilters, needsWorkFilters);
|
||||
|
||||
this._computeQuickFilters();
|
||||
this._createQuickFilters();
|
||||
this._createFilterConfigs();
|
||||
this._createActionConfigs();
|
||||
}
|
||||
|
||||
private _computeQuickFilters() {
|
||||
private _createQuickFilters() {
|
||||
if (this.allEntities.filter(this.recentlyModifiedChecker).length > 0) {
|
||||
const recentPeriodInHours = this._appConfigService.getConfig('RECENT_PERIOD_IN_HOURS');
|
||||
this.quickFilters = [
|
||||
@ -432,4 +437,42 @@ export class DossierOverviewScreenComponent
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
private _createFilterConfigs() {
|
||||
this.filterConfigs = [
|
||||
{
|
||||
label: 'filters.status',
|
||||
primaryFilters: this.statusFilters,
|
||||
icon: 'red:status'
|
||||
},
|
||||
{
|
||||
label: 'filters.assigned-people',
|
||||
primaryFilters: this.peopleFilters,
|
||||
icon: 'red:user'
|
||||
},
|
||||
{
|
||||
label: 'filters.needs-work',
|
||||
primaryFilters: this.needsWorkFilters,
|
||||
icon: 'red:needs-work',
|
||||
filterTemplate: this._needsWorkTemplate
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
private _createActionConfigs() {
|
||||
this.actionConfigs = [
|
||||
{
|
||||
label: 'dossier-overview.header-actions.edit',
|
||||
action: $event => this.openEditDossierDialog($event),
|
||||
icon: 'red:edit',
|
||||
hide: !this.permissionsService.isManager()
|
||||
},
|
||||
{
|
||||
label: 'dossier-overview.header-actions.edit',
|
||||
action: $event => this.openEditDossierDialog($event),
|
||||
icon: 'red:edit',
|
||||
hide: !this.permissionsService.isManager()
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,20 +33,12 @@ export abstract class BaseListingComponent<T = any> {
|
||||
// Overwrite this in ngOnInit
|
||||
protected _filterComponents: (PopupFilterComponent | QuickFiltersComponent)[] = [];
|
||||
|
||||
private _searchValue = '';
|
||||
|
||||
protected constructor(protected readonly _injector: Injector) {
|
||||
this._formBuilder = this._injector.get<FormBuilder>(FormBuilder);
|
||||
this._changeDetectorRef = this._injector.get<ChangeDetectorRef>(ChangeDetectorRef);
|
||||
this._sortingService = this._injector.get<SortingService>(SortingService);
|
||||
this._initSearch();
|
||||
}
|
||||
|
||||
get hasActiveFilters() {
|
||||
return (
|
||||
this._filterComponents
|
||||
?.filter(f => !!f)
|
||||
.reduce((prev, component) => prev || component?.hasActiveFilters, false) ||
|
||||
this.searchForm.get('query').value
|
||||
);
|
||||
}
|
||||
|
||||
get areAllEntitiesSelected() {
|
||||
@ -108,10 +100,9 @@ export abstract class BaseListingComponent<T = any> {
|
||||
|
||||
resetFilters() {
|
||||
for (const filterComponent of this._filterComponents.filter(f => !!f)) {
|
||||
filterComponent.deactivateAllFilters();
|
||||
filterComponent.deactivateFilters();
|
||||
}
|
||||
this.filtersChanged();
|
||||
this.searchForm.reset({ query: '' });
|
||||
}
|
||||
|
||||
// Filter
|
||||
@ -155,7 +146,8 @@ export abstract class BaseListingComponent<T = any> {
|
||||
}
|
||||
|
||||
@debounce(200)
|
||||
protected _executeSearch() {
|
||||
executeSearch(value: string) {
|
||||
this._searchValue = value;
|
||||
this._executeSearchImmediately();
|
||||
}
|
||||
|
||||
@ -163,10 +155,9 @@ export abstract class BaseListingComponent<T = any> {
|
||||
this.displayedEntities = (
|
||||
this._filters.length ? this.filteredEntities : this.allEntities
|
||||
).filter(entity =>
|
||||
this._searchField(entity)
|
||||
.toLowerCase()
|
||||
.includes(this.searchForm.get('query').value.toLowerCase())
|
||||
this._searchField(entity).toLowerCase().includes(this._searchValue.toLowerCase())
|
||||
);
|
||||
|
||||
this._updateSelection();
|
||||
}
|
||||
|
||||
@ -183,15 +174,7 @@ export abstract class BaseListingComponent<T = any> {
|
||||
protected _filterEntities() {
|
||||
this._preFilter();
|
||||
this.filteredEntities = getFilteredEntities(this.allEntities, this._filters);
|
||||
this._executeSearch();
|
||||
this.executeSearch(this._searchValue);
|
||||
this._changeDetectorRef.detectChanges();
|
||||
}
|
||||
|
||||
private _initSearch() {
|
||||
this.searchForm = this._formBuilder.group({
|
||||
query: ['']
|
||||
});
|
||||
|
||||
this.searchForm.valueChanges.subscribe(() => this._executeSearch());
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,10 +16,10 @@
|
||||
<mat-menu
|
||||
#filterMenu="matMenu"
|
||||
(closed)="applyFilters()"
|
||||
[class]="secondaryFilters?.length > 0 ? 'padding-bottom-0' : ''"
|
||||
[class.padding-bottom-0]="secondaryFilters?.length > 0"
|
||||
xPosition="before"
|
||||
>
|
||||
<div (mouseenter)="filterMouseEnter()" (mouseleave)="filterMouseLeave()">
|
||||
<ng-template matMenuContent>
|
||||
<div class="filter-menu-header">
|
||||
<div class="all-caps-label" translate="filter-menu.filter-types"></div>
|
||||
<div class="actions">
|
||||
@ -35,30 +35,33 @@
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngFor="let filter of primaryFilters">
|
||||
<ng-template
|
||||
<ng-container
|
||||
[ngTemplateOutlet]="defaultFilterTemplate"
|
||||
[ngTemplateOutletContext]="{
|
||||
filter: filter,
|
||||
atLeastOneIsExpandable: atLeastOneFilterIsExpandable
|
||||
}"
|
||||
[ngTemplateOutlet]="defaultFilterTemplate"
|
||||
></ng-template>
|
||||
></ng-container>
|
||||
</div>
|
||||
|
||||
<div *ngIf="secondaryFilters?.length > 0" class="filter-options">
|
||||
<div class="filter-menu-options">
|
||||
<div class="all-caps-label" translate="filter-menu.filter-options"></div>
|
||||
</div>
|
||||
|
||||
<div *ngFor="let filter of secondaryFilters">
|
||||
<ng-template
|
||||
<ng-container
|
||||
[ngTemplateOutlet]="defaultFilterTemplate"
|
||||
[ngTemplateOutletContext]="{
|
||||
filter: filter,
|
||||
atLeastOneIsExpandable: atLeastOneSecondaryFilterIsExpandable
|
||||
}"
|
||||
[ngTemplateOutlet]="defaultFilterTemplate"
|
||||
></ng-template>
|
||||
></ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</mat-menu>
|
||||
|
||||
<ng-template #defaultFilterLabelTemplate let-filter="filter">
|
||||
@ -88,16 +91,17 @@
|
||||
[indeterminate]="_(filter).indeterminate"
|
||||
class="filter-menu-checkbox"
|
||||
>
|
||||
<ng-template
|
||||
<ng-container
|
||||
[ngTemplateOutlet]="filterTemplate ?? defaultFilterLabelTemplate"
|
||||
[ngTemplateOutletContext]="{ filter: filter }"
|
||||
[ngTemplateOutlet]="filterTemplate ? filterTemplate : defaultFilterLabelTemplate"
|
||||
></ng-template>
|
||||
></ng-container>
|
||||
</mat-checkbox>
|
||||
<ng-template
|
||||
<ng-container
|
||||
[ngTemplateOutlet]="actionsTemplate ?? null"
|
||||
[ngTemplateOutletContext]="{ filter: filter }"
|
||||
[ngTemplateOutlet]="actionsTemplate ? actionsTemplate : null"
|
||||
></ng-template>
|
||||
></ng-container>
|
||||
</div>
|
||||
|
||||
<div *ngIf="_(filter).filters?.length && _(filter).expanded">
|
||||
<div
|
||||
(click)="$event.stopPropagation()"
|
||||
@ -108,17 +112,16 @@
|
||||
(click)="filterCheckboxClicked($event, subFilter, filter)"
|
||||
[checked]="subFilter.checked"
|
||||
>
|
||||
<ng-template
|
||||
<ng-container
|
||||
[ngTemplateOutlet]="filterTemplate ?? defaultFilterLabelTemplate"
|
||||
[ngTemplateOutletContext]="{ filter: subFilter }"
|
||||
[ngTemplateOutlet]="
|
||||
filterTemplate ? filterTemplate : defaultFilterLabelTemplate
|
||||
"
|
||||
></ng-template>
|
||||
></ng-container>
|
||||
</mat-checkbox>
|
||||
<ng-template
|
||||
|
||||
<ng-container
|
||||
[ngTemplateOutlet]="actionsTemplate ?? null"
|
||||
[ngTemplateOutletContext]="{ filter: subFilter }"
|
||||
[ngTemplateOutlet]="actionsTemplate ? actionsTemplate : null"
|
||||
></ng-template>
|
||||
></ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
EventEmitter,
|
||||
@ -15,6 +16,7 @@ import { MAT_CHECKBOX_DEFAULT_OPTIONS } from '@angular/material/checkbox';
|
||||
selector: 'redaction-popup-filter',
|
||||
templateUrl: './popup-filter.component.html',
|
||||
styleUrls: ['./popup-filter.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [
|
||||
{
|
||||
provide: MAT_CHECKBOX_DEFAULT_OPTIONS,
|
||||
@ -38,9 +40,6 @@ export class PopupFilterComponent implements OnChanges {
|
||||
@Input() icon: string;
|
||||
@Input() chevron = false;
|
||||
|
||||
mouseOver = true;
|
||||
mouseOverTimeout: number;
|
||||
|
||||
atLeastOneFilterIsExpandable = false;
|
||||
atLeastOneSecondaryFilterIsExpandable = false;
|
||||
|
||||
@ -60,44 +59,38 @@ export class PopupFilterComponent implements OnChanges {
|
||||
}
|
||||
|
||||
ngOnChanges(): void {
|
||||
this.atLeastOneFilterIsExpandable = false;
|
||||
this.atLeastOneSecondaryFilterIsExpandable = false;
|
||||
this.primaryFilters?.forEach(f => {
|
||||
this.atLeastOneFilterIsExpandable =
|
||||
this.atLeastOneFilterIsExpandable || this.isExpandable(f);
|
||||
});
|
||||
this.secondaryFilters?.forEach(f => {
|
||||
this.atLeastOneSecondaryFilterIsExpandable =
|
||||
this.atLeastOneSecondaryFilterIsExpandable || this.isExpandable(f);
|
||||
});
|
||||
this.atLeastOneFilterIsExpandable = !!this.primaryFilters?.find(f => this.isExpandable(f));
|
||||
this.atLeastOneSecondaryFilterIsExpandable = !!this.secondaryFilters?.find(f =>
|
||||
this.isExpandable(f)
|
||||
);
|
||||
}
|
||||
|
||||
filterCheckboxClicked($event: any, filter: FilterModel, parent?: FilterModel) {
|
||||
$event.stopPropagation();
|
||||
|
||||
filter.checked = !filter.checked;
|
||||
|
||||
if (parent) {
|
||||
handleCheckedValue(parent);
|
||||
} else {
|
||||
if (filter.indeterminate) {
|
||||
filter.checked = false;
|
||||
}
|
||||
if (filter.indeterminate) filter.checked = false;
|
||||
filter.indeterminate = false;
|
||||
filter.filters?.forEach(f => (f.checked = filter.checked));
|
||||
}
|
||||
this._changeDetectorRef.detectChanges();
|
||||
|
||||
this.applyFilters();
|
||||
}
|
||||
|
||||
activateAllFilters() {
|
||||
this._setAllFilters(true);
|
||||
activatePrimaryFilters() {
|
||||
this._setFilters(true);
|
||||
}
|
||||
|
||||
deactivateAllFilters() {
|
||||
this._setAllFilters(false);
|
||||
deactivateFilters() {
|
||||
this._setFilters();
|
||||
}
|
||||
|
||||
applyFilters() {
|
||||
this._changeDetectorRef.detectChanges();
|
||||
this.filtersChanged.emit({
|
||||
primary: this.primaryFilters,
|
||||
secondary: this.secondaryFilters
|
||||
@ -109,20 +102,6 @@ export class PopupFilterComponent implements OnChanges {
|
||||
filter.expanded = !filter.expanded;
|
||||
}
|
||||
|
||||
filterMouseEnter() {
|
||||
this.mouseOver = true;
|
||||
if (this.mouseOverTimeout) {
|
||||
clearTimeout(this.mouseOverTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
filterMouseLeave() {
|
||||
this.mouseOver = false;
|
||||
this.mouseOverTimeout = setTimeout(() => {
|
||||
// this.trigger.closeMenu();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
isExpandable(filter: FilterModel) {
|
||||
return filter.filters && filter.filters.length > 0;
|
||||
}
|
||||
@ -131,14 +110,13 @@ export class PopupFilterComponent implements OnChanges {
|
||||
return obj as FilterModel;
|
||||
}
|
||||
|
||||
private _setAllFilters(value: boolean) {
|
||||
const filters = value ? this.primaryFilters : this._allFilters;
|
||||
private _setFilters(onlyPrimaryFilters = false) {
|
||||
const filters = onlyPrimaryFilters ? this.primaryFilters : this._allFilters;
|
||||
filters.forEach(f => {
|
||||
f.checked = value;
|
||||
f.checked = onlyPrimaryFilters;
|
||||
f.indeterminate = false;
|
||||
f.filters?.forEach(ff => {
|
||||
ff.checked = value;
|
||||
});
|
||||
f.filters?.forEach(ff => (ff.checked = onlyPrimaryFilters));
|
||||
});
|
||||
this.applyFilters();
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,16 +10,12 @@ export class QuickFiltersComponent {
|
||||
@Output() filtersChanged = new EventEmitter<FilterModel[]>();
|
||||
@Input() filters: FilterModel[];
|
||||
|
||||
constructor() {}
|
||||
|
||||
get hasActiveFilters(): boolean {
|
||||
return this.filters.filter(f => f.checked).length > 0;
|
||||
}
|
||||
|
||||
deactivateAllFilters() {
|
||||
for (const filter of this.filters) {
|
||||
filter.checked = false;
|
||||
}
|
||||
deactivateFilters() {
|
||||
for (const filter of this.filters) filter.checked = false;
|
||||
}
|
||||
|
||||
toggle(filter: FilterModel) {
|
||||
|
||||
@ -0,0 +1,61 @@
|
||||
<div class="page-header">
|
||||
<div *ngIf="pageLabel" class="breadcrumb" translate>{{ pageLabel }}</div>
|
||||
|
||||
<div class="filters" *ngIf="filterConfigs">
|
||||
<div translate="filters.filter-by"></div>
|
||||
|
||||
<ng-container *ngFor="let config of filterConfigs; trackBy: trackByLabel">
|
||||
<redaction-popup-filter
|
||||
(filtersChanged)="filtersChanged.emit($event)"
|
||||
*ngIf="!config.hide"
|
||||
[filterLabel]="config.label"
|
||||
[icon]="config.icon"
|
||||
[primaryFilters]="config.primaryFilters"
|
||||
[filterTemplate]="config.filterTemplate"
|
||||
></redaction-popup-filter>
|
||||
</ng-container>
|
||||
|
||||
<redaction-input-with-action
|
||||
[form]="searchForm"
|
||||
[placeholder]="searchPlaceholder"
|
||||
type="search"
|
||||
></redaction-input-with-action>
|
||||
|
||||
<div
|
||||
(click)="resetFilters()"
|
||||
*ngIf="hasActiveFilters"
|
||||
class="reset-filters"
|
||||
translate="reset-filters"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<div class="actions" *ngIf="actionConfigs">
|
||||
<ng-container *ngFor="let config of actionConfigs; trackBy: trackByLabel">
|
||||
<redaction-circle-button
|
||||
(action)="config.action($event)"
|
||||
*ngIf="!config.hide"
|
||||
[icon]="config.icon"
|
||||
[tooltip]="config.label"
|
||||
tooltipPosition="below"
|
||||
></redaction-circle-button>
|
||||
</ng-container>
|
||||
</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>
|
||||
|
||||
<redaction-circle-button
|
||||
*ngIf="showCloseButton && permissionsService.isUser()"
|
||||
icon="red:close"
|
||||
redactionNavigateLastDossiersScreen
|
||||
tooltip="common.close"
|
||||
tooltipPosition="below"
|
||||
></redaction-circle-button>
|
||||
</div>
|
||||
@ -0,0 +1,3 @@
|
||||
.page-header .actions > *:not(:last-child) {
|
||||
margin-right: 16px;
|
||||
}
|
||||
@ -0,0 +1,92 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
Output,
|
||||
QueryList,
|
||||
TemplateRef,
|
||||
ViewChildren
|
||||
} from '@angular/core';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { FilterModel } from '@shared/components/filters/popup-filter/model/filter.model';
|
||||
import { PopupFilterComponent } from '@shared/components/filters/popup-filter/popup-filter.component';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
|
||||
interface BaseHeaderConfig {
|
||||
label: string;
|
||||
icon?: string;
|
||||
hide?: boolean;
|
||||
}
|
||||
|
||||
export interface FilterConfig extends BaseHeaderConfig {
|
||||
primaryFilters: FilterModel[];
|
||||
filterTemplate?: TemplateRef<any>;
|
||||
}
|
||||
|
||||
export interface ActionConfig extends BaseHeaderConfig {
|
||||
action: ($event) => void;
|
||||
}
|
||||
|
||||
export interface ButtonConfig extends BaseHeaderConfig {
|
||||
action: ($event) => void;
|
||||
type?: 'default' | 'show-bg' | 'primary';
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-page-header',
|
||||
templateUrl: './page-header.component.html',
|
||||
styleUrls: ['./page-header.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class PageHeaderComponent {
|
||||
@Input() pageLabel: string;
|
||||
@Input() showCloseButton: boolean;
|
||||
@Input() filterConfigs: FilterConfig[];
|
||||
@Input() actionConfigs: ActionConfig[];
|
||||
@Input() buttonConfigs: ButtonConfig[];
|
||||
@Input() searchPlaceholder: string;
|
||||
@Output() filtersChanged = new EventEmitter<any>();
|
||||
@Output() searchChanged = new EventEmitter<string>();
|
||||
|
||||
searchForm: FormGroup;
|
||||
|
||||
@ViewChildren(PopupFilterComponent)
|
||||
private readonly _filterComponents: QueryList<PopupFilterComponent>;
|
||||
|
||||
constructor(
|
||||
readonly permissionsService: PermissionsService,
|
||||
private readonly _formBuilder: FormBuilder
|
||||
) {
|
||||
this._initSearch();
|
||||
}
|
||||
|
||||
get hasActiveFilters() {
|
||||
return (
|
||||
this._filterComponents
|
||||
?.filter(f => !!f)
|
||||
.reduce((prev, component) => prev || component?.hasActiveFilters, false) ||
|
||||
this.searchForm.get('query').value
|
||||
);
|
||||
}
|
||||
|
||||
resetFilters() {
|
||||
for (const filterComponent of this._filterComponents.filter(f => !!f)) {
|
||||
filterComponent.deactivateFilters();
|
||||
}
|
||||
this.filtersChanged.emit();
|
||||
this.searchForm.reset({ query: '' });
|
||||
}
|
||||
|
||||
private _initSearch() {
|
||||
this.searchForm = this._formBuilder.group({
|
||||
query: ['']
|
||||
});
|
||||
|
||||
this.searchForm.valueChanges.subscribe(value => this.searchChanged.emit(value.query));
|
||||
}
|
||||
|
||||
trackByLabel(index: number, item: BaseHeaderConfig) {
|
||||
return item.label;
|
||||
}
|
||||
}
|
||||
@ -37,6 +37,7 @@ import { QuickFiltersComponent } from './components/filters/quick-filters/quick-
|
||||
import { PopupFilterComponent } from '@shared/components/filters/popup-filter/popup-filter.component';
|
||||
import { AssignUserDropdownComponent } from './components/assign-user-dropdown/assign-user-dropdown.component';
|
||||
import { InputWithActionComponent } from '@shared/components/input-with-action/input-with-action.component';
|
||||
import { PageHeaderComponent } from './components/page-header/page-header.component';
|
||||
|
||||
const buttons = [
|
||||
ChevronButtonComponent,
|
||||
@ -67,6 +68,7 @@ const components = [
|
||||
DictionaryManagerComponent,
|
||||
QuickFiltersComponent,
|
||||
AssignUserDropdownComponent,
|
||||
PageHeaderComponent,
|
||||
|
||||
...buttons
|
||||
];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user