move popup filter to common lib

This commit is contained in:
Dan Percic 2021-08-19 17:27:10 +03:00
parent 4816d97d4a
commit 3bebc49d96
12 changed files with 8 additions and 266 deletions

View File

@ -9,11 +9,11 @@
class="all-caps-label primary pointer"
translate="file-preview.tabs.annotations.select"
></div>
<redaction-popup-filter
<iqser-popup-filter
[actionsTemplate]="annotationFilterActionTemplate"
[primaryFiltersSlug]="'primaryFilters'"
[secondaryFiltersSlug]="'secondaryFilters'"
></redaction-popup-filter>
></iqser-popup-filter>
</div>
</div>

View File

@ -20,12 +20,7 @@ import { DefaultListingServices, ListingComponent, NestedFilter, TableColumnConf
import { workloadTranslations } from '../../translations/workload-translations';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { fileStatusTranslations } from '../../translations/file-status-translations';
import {
annotationFilterChecker,
dossierMemberChecker,
dossierStatusChecker,
dossierTemplateChecker
} from '@shared/components/filters/popup-filter/utils/filter-utils';
import { annotationFilterChecker, dossierMemberChecker, dossierStatusChecker, dossierTemplateChecker } from '@utils/filter-utils';
import { PermissionsService } from '@services/permissions.service';
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';

View File

@ -38,7 +38,7 @@ import { UserPreferenceService } from '@services/user-preference.service';
import { workloadTranslations } from '../../translations/workload-translations';
import { fileStatusTranslations } from '../../translations/file-status-translations';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { annotationFilterChecker } from '@shared/components/filters/popup-filter/utils/filter-utils';
import { annotationFilterChecker } from '@utils/filter-utils';
import { PermissionsService } from '@services/permissions.service';
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
import { FileAttributeConfig } from '@redaction/red-ui-http';

View File

@ -34,7 +34,7 @@ import { LoadingService } from '@services/loading.service';
import { clearStamps, stampPDFPage } from '@utils/page-stamper';
import { TranslateService } from '@ngx-translate/core';
import { fileStatusTranslations } from '../../translations/file-status-translations';
import { handleFilterDelta } from '@shared/components/filters/popup-filter/utils/filter-utils';
import { handleFilterDelta } from '@utils/filter-utils';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
const ALL_HOTKEY_ARRAY = ['Escape', 'F', 'f'];

View File

@ -1,109 +0,0 @@
<ng-container *ngIf="primaryFilterGroup$ | async as primaryGroup">
<iqser-icon-button
*ngIf="primaryGroup.icon"
[icon]="primaryGroup.icon"
[label]="primaryGroup.label || ('filter-menu.label' | translate)"
[matMenuTriggerFor]="filterMenu"
[showDot]="hasActiveFilters$ | async"
[attr.aria-expanded]="expanded$ | async"
></iqser-icon-button>
<iqser-chevron-button
*ngIf="!primaryGroup.icon"
[label]="primaryGroup.label || ('filter-menu.label' | translate)"
[matMenuTriggerFor]="filterMenu"
[showDot]="hasActiveFilters$ | async"
[attr.aria-expanded]="expanded$ | async"
></iqser-chevron-button>
<mat-menu
#filterMenu="matMenu"
(close)="expanded.next(false)"
[class]="(secondaryFilterGroup$ | async)?.filters.length > 0 ? 'padding-bottom-0' : ''"
xPosition="before"
>
<ng-template matMenuContent>
<div class="filter-menu-header">
<div class="all-caps-label" translate="filter-menu.filter-types"></div>
<div class="actions">
<div
(click)="activatePrimaryFilters(); $event.stopPropagation()"
class="all-caps-label primary pointer"
translate="actions.all"
></div>
<div
(click)="deactivateFilters(); $event.stopPropagation()"
class="all-caps-label primary pointer"
translate="actions.none"
></div>
</div>
</div>
<div class="filter-content">
<ng-container
*ngFor="let filter of primaryGroup.filters"
[ngTemplateOutletContext]="{
filter: filter,
atLeastOneIsExpandable: atLeastOneFilterIsExpandable$ | async
}"
[ngTemplateOutlet]="defaultFilterTemplate"
></ng-container>
</div>
<div *ngIf="secondaryFilterGroup$ | async as secondaryGroup" 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 secondaryGroup.filters">
<ng-container
[ngTemplateOutletContext]="{
filter: filter,
atLeastOneIsExpandable: atLeastOneSecondaryFilterIsExpandable$ | async
}"
[ngTemplateOutlet]="defaultFilterTemplate"
></ng-container>
</div>
</div>
</ng-template>
</mat-menu>
<ng-template #defaultFilterLabelTemplate let-filter="filter">
{{ filter?.label }}
</ng-template>
<ng-template #defaultFilterTemplate let-atLeastOneIsExpandable="atLeastOneIsExpandable" let-filter="filter">
<div (click)="toggleFilterExpanded($event, filter)" class="mat-menu-item flex">
<div *ngIf="filter.children?.length > 0" class="arrow-wrapper">
<mat-icon *ngIf="filter.expanded" color="accent" svgIcon="iqser:arrow-down"></mat-icon>
<mat-icon *ngIf="!filter.expanded" color="accent" svgIcon="red:arrow-right"></mat-icon>
</div>
<div *ngIf="atLeastOneIsExpandable && filter.children?.length === 0" class="arrow-wrapper spacer">&nbsp;</div>
<mat-checkbox
(click)="filterCheckboxClicked($event, filter)"
[checked]="filter.checked"
[indeterminate]="filter.indeterminate"
class="filter-menu-checkbox"
>
<ng-container
[ngTemplateOutletContext]="{ filter: filter }"
[ngTemplateOutlet]="primaryGroup.filterTemplate ?? defaultFilterLabelTemplate"
></ng-container>
</mat-checkbox>
<ng-container [ngTemplateOutletContext]="{ filter: filter }" [ngTemplateOutlet]="actionsTemplate"></ng-container>
</div>
<div *ngIf="filter.children?.length && filter.expanded">
<div (click)="$event.stopPropagation()" *ngFor="let child of filter.children" class="padding-left mat-menu-item">
<mat-checkbox (click)="filterCheckboxClicked($event, child, filter)" [checked]="child.checked">
<ng-container
[ngTemplateOutletContext]="{ filter: child }"
[ngTemplateOutlet]="primaryGroup.filterTemplate ?? defaultFilterLabelTemplate"
></ng-container>
</mat-checkbox>
<ng-container [ngTemplateOutletContext]="{ filter: child }" [ngTemplateOutlet]="actionsTemplate"></ng-container>
</div>
</div>
</ng-template>
</ng-container>

View File

@ -1,41 +0,0 @@
@import '../../../../../../assets/styles/variables';
.filter-menu-options,
.filter-menu-header {
display: flex;
justify-content: space-between;
padding: 8px 16px 16px 16px;
width: 350px;
.actions {
display: flex;
> *:not(:last-child) {
margin-right: 8px;
}
}
}
.filter-content {
max-height: 570px;
overflow: auto;
}
.filter-menu-options {
margin-top: 8px;
padding: 16px 16px 3px;
}
.filter-options {
background-color: $grey-2;
padding-bottom: 8px;
}
::ng-deep .filter-menu-checkbox {
width: 100%;
label {
width: 100%;
height: 100%;
}
}

View File

@ -1,102 +0,0 @@
import { ChangeDetectionStrategy, Component, Input, OnInit, TemplateRef } from '@angular/core';
import { FilterGroup, FilterService, handleCheckedValue, NestedFilter } from '@iqser/common-ui';
import { MAT_CHECKBOX_DEFAULT_OPTIONS } from '@angular/material/checkbox';
import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
import { delay, distinctUntilChanged, map, shareReplay } from 'rxjs/operators';
@Component({
selector: 'redaction-popup-filter',
templateUrl: './popup-filter.component.html',
styleUrls: ['./popup-filter.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [
{
provide: MAT_CHECKBOX_DEFAULT_OPTIONS,
useValue: {
clickAction: 'noop',
color: 'primary'
}
}
]
})
export class PopupFilterComponent implements OnInit {
@Input() actionsTemplate: TemplateRef<unknown>;
@Input() primaryFiltersSlug: string;
@Input() secondaryFiltersSlug: string;
atLeastOneFilterIsExpandable$?: Observable<boolean>;
atLeastOneSecondaryFilterIsExpandable$?: Observable<boolean>;
hasActiveFilters$?: Observable<boolean>;
readonly expanded = new BehaviorSubject<boolean>(null);
readonly expanded$ = this.expanded.asObservable().pipe(delay(200));
primaryFilterGroup$?: Observable<FilterGroup>;
secondaryFilterGroup$?: Observable<FilterGroup>;
constructor(readonly filterService: FilterService) {}
ngOnInit(): void {
this.primaryFilterGroup$ = this.filterService.getGroup$(this.primaryFiltersSlug);
this.secondaryFilterGroup$ = this.filterService.getGroup$(this.secondaryFiltersSlug);
this.hasActiveFilters$ = combineLatest([this.primaryFilterGroup$, this.secondaryFilterGroup$]).pipe(
map(([primary, secondary]) => [...primary.filters, ...(secondary?.filters || [])]),
map(filters => filters.some(f => f.checked || f.indeterminate)),
distinctUntilChanged()
);
this.atLeastOneFilterIsExpandable$ = this.primaryFilterGroup$.pipe(
map(group => group.filters.some(f => this.isExpandable(f))),
distinctUntilChanged(),
shareReplay()
);
this.atLeastOneSecondaryFilterIsExpandable$ = this.secondaryFilterGroup$.pipe(
map(group => group?.filters.some(f => this.isExpandable(f))),
distinctUntilChanged(),
shareReplay()
);
}
filterCheckboxClicked($event: MouseEvent, nestedFilter: NestedFilter, parent?: NestedFilter): void {
$event.stopPropagation();
nestedFilter.checked = !nestedFilter.checked;
if (parent) {
handleCheckedValue(parent);
} else {
if (nestedFilter.indeterminate) nestedFilter.checked = false;
nestedFilter.indeterminate = false;
nestedFilter.children?.forEach(f => (f.checked = nestedFilter.checked));
}
this.filterService.refresh();
}
activatePrimaryFilters(): void {
this._setFilters(this.primaryFiltersSlug, true);
}
deactivateFilters(): void {
this._setFilters(this.primaryFiltersSlug);
if (this.secondaryFiltersSlug) this._setFilters(this.secondaryFiltersSlug);
}
toggleFilterExpanded($event: MouseEvent, nestedFilter: NestedFilter): void {
$event.stopPropagation();
nestedFilter.expanded = !nestedFilter.expanded;
this.filterService.refresh();
}
isExpandable(nestedFilter: NestedFilter): boolean {
return nestedFilter?.children?.length > 0;
}
private _setFilters(filterGroup: string, checked = false) {
const filters = this.filterService.getGroup(filterGroup).filters;
filters.forEach(f => {
f.checked = checked;
f.indeterminate = false;
f.children?.forEach(ff => (ff.checked = checked));
});
this.filterService.refresh();
}
}

View File

@ -7,7 +7,7 @@
<ng-container *ngIf="searchPosition === searchPositions.beforeFilters" [ngTemplateOutlet]="searchBar"></ng-container>
<ng-container *ngFor="let config of filters; trackBy: trackByLabel">
<redaction-popup-filter *ngIf="!config.hide" [primaryFiltersSlug]="config.slug"></redaction-popup-filter>
<iqser-popup-filter *ngIf="!config.hide" [primaryFiltersSlug]="config.slug"></iqser-popup-filter>
</ng-container>
<ng-container *ngIf="searchPosition === searchPositions.afterFilters" [ngTemplateOutlet]="searchBar"></ng-container>

View File

@ -24,7 +24,6 @@ import { NavigateLastDossiersScreenDirective } from './directives/navigate-last-
import { DictionaryManagerComponent } from './components/dictionary-manager/dictionary-manager.component';
import { SideNavComponent } from '@shared/components/side-nav/side-nav.component';
import { MonacoEditorModule } from '@materia-ui/ngx-monaco-editor';
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';
@ -42,7 +41,6 @@ const components = [
SimpleDoughnutChartComponent,
DictionaryAnnotationIconComponent,
HiddenActionComponent,
PopupFilterComponent,
ConfirmationDialogComponent,
EmptyStateComponent,
SelectComponent,

View File

@ -36,6 +36,7 @@ $dark: $black;
$btn-bg-hover: $grey-4;
$btn-bg: $grey-6;
$filter-bg: $grey-2;
$quick-filter-border: $grey-5;
$separator: rgba(226, 228, 233, 0.9);

@ -1 +1 @@
Subproject commit d31b702c22ac1a9e925db673ef83f56c7137071b
Subproject commit c20bac823277e659c1c9797bdd034a9f5b2fc539