Adds custom filter predicates for native object data
Supports properties like motion submitter and more. Does at the moment "not" support tunneled properties, i.e filters that need to go over a repository (i.w workflow-state-label) Fixes some small issues
This commit is contained in:
parent
582be687eb
commit
2758441552
@ -148,6 +148,9 @@ export class ListViewTableComponent<V extends BaseViewModel, M extends BaseModel
|
||||
@Input()
|
||||
public columns: PblColumnDefinition[] = [];
|
||||
|
||||
@Input()
|
||||
public filterProps: string[];
|
||||
|
||||
/**
|
||||
* Key to restore scroll position after navigating
|
||||
*/
|
||||
@ -299,12 +302,13 @@ export class ListViewTableComponent<V extends BaseViewModel, M extends BaseModel
|
||||
})
|
||||
.create();
|
||||
|
||||
const filterPredicate = (item: any): boolean => {
|
||||
const filterPredicate = (item: V): boolean => {
|
||||
if (!this.inputValue) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.inputValue) {
|
||||
// filter by ID
|
||||
const trimmedInput = this.inputValue.trim().toLowerCase();
|
||||
const idString = '' + item.id;
|
||||
const foundId =
|
||||
@ -316,24 +320,25 @@ export class ListViewTableComponent<V extends BaseViewModel, M extends BaseModel
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const column of this.columns) {
|
||||
const col = this.dataSource.hostGrid.columnApi.findColumn(column.prop);
|
||||
const value = col.getValue(item);
|
||||
// custom filter predicates
|
||||
if (this.filterProps && this.filterProps.length) {
|
||||
for (const prop of this.filterProps) {
|
||||
const propertyAsString = '' + item[prop];
|
||||
|
||||
if (!!value) {
|
||||
const valueAsString = '' + value;
|
||||
const foundValue =
|
||||
valueAsString
|
||||
if (!!propertyAsString) {
|
||||
const foundProp =
|
||||
propertyAsString
|
||||
.trim()
|
||||
.toLocaleLowerCase()
|
||||
.toLowerCase()
|
||||
.indexOf(trimmedInput) !== -1;
|
||||
|
||||
if (foundValue) {
|
||||
if (foundProp) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.dataSource.setFilter(filterPredicate);
|
||||
|
@ -18,7 +18,9 @@
|
||||
[filterService]="filterService"
|
||||
[columns]="tableColumnDefinition"
|
||||
[multiSelect]="isMultiSelect"
|
||||
[restricted]="restrictedColumns"
|
||||
[hiddenInMobile]="['info']"
|
||||
[filterProps]="filterProps"
|
||||
scrollKey="agenda"
|
||||
[(selectedRows)]="selectedRows"
|
||||
(dataSourceChange)="onDataSourceChange($event)"
|
||||
|
@ -6,10 +6,12 @@ import { Title } from '@angular/platform-browser';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { PblColumnDefinition } from '@pebula/ngrid';
|
||||
|
||||
import { _ } from 'app/core/translate/translation-marker';
|
||||
import { AgendaCsvExportService } from '../../services/agenda-csv-export.service';
|
||||
import { AgendaFilterListService } from '../../services/agenda-filter-list.service';
|
||||
import { AgendaPdfService } from '../../services/agenda-pdf.service';
|
||||
import { ConfigService } from 'app/core/ui-services/config.service';
|
||||
import { ColumnRestriction } from 'app/shared/components/list-view-table/list-view-table.component';
|
||||
import { DurationService } from 'app/core/ui-services/duration.service';
|
||||
import { ItemInfoDialogComponent } from '../item-info-dialog/item-info-dialog.component';
|
||||
import { ItemRepositoryService } from 'app/core/repositories/agenda/item-repository.service';
|
||||
@ -20,11 +22,10 @@ import { ProjectorElementBuildDeskriptor } from 'app/site/base/projectable';
|
||||
import { PromptService } from 'app/core/ui-services/prompt.service';
|
||||
import { PdfDocumentService } from 'app/core/ui-services/pdf-document.service';
|
||||
import { StorageService } from 'app/core/core-services/storage.service';
|
||||
import { TopicRepositoryService } from 'app/core/repositories/topics/topic-repository.service';
|
||||
import { ViewportService } from 'app/core/ui-services/viewport.service';
|
||||
import { ViewItem } from '../../models/view-item';
|
||||
import { ViewListOfSpeakers } from '../../models/view-list-of-speakers';
|
||||
import { _ } from 'app/core/translate/translation-marker';
|
||||
import { TopicRepositoryService } from 'app/core/repositories/topics/topic-repository.service';
|
||||
import { ViewTopic } from '../../models/view-topic';
|
||||
|
||||
/**
|
||||
@ -80,7 +81,7 @@ export class AgendaListComponent extends ListViewBaseComponent<ViewItem> impleme
|
||||
},
|
||||
{
|
||||
prop: 'speaker',
|
||||
width: this.singleButtonWidth
|
||||
width: this.badgeButtonWidth
|
||||
},
|
||||
{
|
||||
prop: 'menu',
|
||||
@ -88,6 +89,22 @@ export class AgendaListComponent extends ListViewBaseComponent<ViewItem> impleme
|
||||
}
|
||||
];
|
||||
|
||||
public restrictedColumns: ColumnRestriction[] = [
|
||||
{
|
||||
columnName: 'menu',
|
||||
permission: 'agenda.can_manage'
|
||||
},
|
||||
{
|
||||
columnName: 'speaker',
|
||||
permission: 'agenda.can_see_list_of_speakers'
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* Define extra filter properties
|
||||
*/
|
||||
public filterProps = ['itemNumber', 'comment'];
|
||||
|
||||
/**
|
||||
* The usual constructor for components
|
||||
* @param titleService Setting the browser tab title
|
||||
@ -322,26 +339,4 @@ export class AgendaListComponent extends ListViewBaseComponent<ViewItem> impleme
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrites the dataSource's string filter with a case-insensitive search
|
||||
* in the item number and title
|
||||
*
|
||||
* TODO: Filter predicates will be missed :(
|
||||
*/
|
||||
// private setFulltextFilter(): void {
|
||||
// this.dataSource.filterPredicate = (data, filter) => {
|
||||
// if (!data) {
|
||||
// return false;
|
||||
// }
|
||||
// filter = filter ? filter.toLowerCase() : '';
|
||||
// return (
|
||||
// data.itemNumber.toLowerCase().includes(filter) ||
|
||||
// data
|
||||
// .getListTitle()
|
||||
// .toLowerCase()
|
||||
// .includes(filter)
|
||||
// );
|
||||
// };
|
||||
// }
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
[filterService]="filterService"
|
||||
[sortService]="sortService"
|
||||
[columns]="tableColumnDefinition"
|
||||
[filterProps]="filterProps"
|
||||
[multiSelect]="isMultiSelect"
|
||||
scrollKey="assignments"
|
||||
[(selectedRows)]="selectedRows"
|
||||
|
@ -49,6 +49,11 @@ export class AssignmentListComponent extends ListViewBaseComponent<ViewAssignmen
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* Define extra filter properties
|
||||
*/
|
||||
public filterProps = ['title', 'candidates', 'assignmentRelatedUsers', 'tags', 'candidateAmount'];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
|
@ -43,6 +43,11 @@ export abstract class ListViewBaseComponent<V extends BaseViewModel> extends Bas
|
||||
*/
|
||||
public singleButtonWidth = '40px';
|
||||
|
||||
/**
|
||||
* NGrid column width for single buttons with badge
|
||||
*/
|
||||
public badgeButtonWidth = '45px';
|
||||
|
||||
/**
|
||||
* @param titleService the title service
|
||||
* @param translate the translate service
|
||||
|
@ -24,6 +24,8 @@
|
||||
[sortService]="sortService"
|
||||
[columns]="tableColumnDefinition"
|
||||
[multiSelect]="isMultiSelect"
|
||||
[restricted]="restrictedColumns"
|
||||
[filterProps]="filterProps"
|
||||
scrollKey="user"
|
||||
[(selectedRows)]="selectedRows"
|
||||
(dataSourceChange)="onDataSourceChange($event)"
|
||||
|
@ -1,22 +1,23 @@
|
||||
import { Component, OnInit, ViewChild, TemplateRef } from '@angular/core';
|
||||
import { Router, ActivatedRoute } from '@angular/router';
|
||||
import { FormGroup, Validators, FormBuilder } from '@angular/forms';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { MatSnackBar, MatDialog } from '@angular/material';
|
||||
import { Router, ActivatedRoute } from '@angular/router';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { PblColumnDefinition } from '@pebula/ngrid';
|
||||
|
||||
import { ListViewBaseComponent } from '../../../base/list-view-base';
|
||||
import { ViewMediafile } from '../../models/view-mediafile';
|
||||
import { ColumnRestriction } from 'app/shared/components/list-view-table/list-view-table.component';
|
||||
import { ListViewBaseComponent } from 'app/site/base/list-view-base';
|
||||
import { MediafileRepositoryService } from 'app/core/repositories/mediafiles/mediafile-repository.service';
|
||||
import { MediaManageService } from 'app/core/ui-services/media-manage.service';
|
||||
import { PromptService } from 'app/core/ui-services/prompt.service';
|
||||
import { MediafileFilterListService } from '../../services/mediafile-filter.service';
|
||||
import { MediafilesSortListService } from '../../services/mediafiles-sort-list.service';
|
||||
import { ViewportService } from 'app/core/ui-services/viewport.service';
|
||||
import { OperatorService } from 'app/core/core-services/operator.service';
|
||||
import { PromptService } from 'app/core/ui-services/prompt.service';
|
||||
import { StorageService } from 'app/core/core-services/storage.service';
|
||||
import { ViewportService } from 'app/core/ui-services/viewport.service';
|
||||
import { ViewMediafile } from '../../models/view-mediafile';
|
||||
|
||||
/**
|
||||
* Lists all the uploaded files.
|
||||
@ -95,6 +96,25 @@ export class MediafileListComponent extends ListViewBaseComponent<ViewMediafile>
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* Restricted Columns
|
||||
*/
|
||||
public restrictedColumns: ColumnRestriction[] = [
|
||||
{
|
||||
columnName: 'indicator',
|
||||
permission: 'mediafiles.can_manage'
|
||||
},
|
||||
{
|
||||
columnName: 'menu',
|
||||
permission: 'mediafiles.can_manage'
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* Define extra filter properties
|
||||
*/
|
||||
public filterProps = ['title', 'type'];
|
||||
|
||||
/**
|
||||
* Constructs the component
|
||||
*
|
||||
@ -301,20 +321,4 @@ export class MediafileListComponent extends ListViewBaseComponent<ViewMediafile>
|
||||
this.editFile = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrites the dataSource's string filter with a case-insensitive search
|
||||
* in the file name property
|
||||
*
|
||||
* TODO: Filter predicates will be missed :(
|
||||
*/
|
||||
// private setFulltextFilter(): void {
|
||||
// this.dataSource.filterPredicate = (data, filter) => {
|
||||
// if (!data || !data.title) {
|
||||
// return false;
|
||||
// }
|
||||
// filter = filter ? filter.toLowerCase() : '';
|
||||
// return data.title.toLowerCase().indexOf(filter) >= 0;
|
||||
// };
|
||||
// }
|
||||
}
|
||||
|
@ -48,6 +48,7 @@
|
||||
[columns]="tableColumnDefinition"
|
||||
[multiSelect]="isMultiSelect"
|
||||
[restricted]="restrictedColumns"
|
||||
[filterProps]="filterProps"
|
||||
[hiddenInMobile]="['state']"
|
||||
scrollKey="motion"
|
||||
[(selectedRows)]="selectedRows"
|
||||
|
@ -107,7 +107,8 @@ export class MotionListComponent extends ListViewBaseComponent<ViewMotion> imple
|
||||
minWidth: 160
|
||||
},
|
||||
{
|
||||
prop: 'speaker'
|
||||
prop: 'speaker',
|
||||
width: this.badgeButtonWidth
|
||||
}
|
||||
];
|
||||
|
||||
@ -129,13 +130,23 @@ export class MotionListComponent extends ListViewBaseComponent<ViewMotion> imple
|
||||
public categories: ViewCategory[] = [];
|
||||
public motionBlocks: ViewMotionBlock[] = [];
|
||||
|
||||
/**
|
||||
* Columns that demand certain permissions
|
||||
*/
|
||||
public restrictedColumns: ColumnRestriction[] = [
|
||||
{
|
||||
columnName: 'speaker',
|
||||
permission: 'agenda.can_see'
|
||||
permission: 'agenda.can_see_list_of_speakers'
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* Define extra filter properties
|
||||
*
|
||||
* TODO: repo.getExtendedStateLabel(), repo.getExtendedRecommendationLabel()
|
||||
*/
|
||||
public filterProps = ['submitters', 'motion_block', 'title', 'identifier'];
|
||||
|
||||
/**
|
||||
* List of `TileCategoryInformation`.
|
||||
* Necessary to not iterate over the values of the map below.
|
||||
@ -394,58 +405,6 @@ export class MotionListComponent extends ListViewBaseComponent<ViewMotion> imple
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrites the dataSource's string filter with a case-insensitive search
|
||||
* in the identifier, title, state, recommendations, submitters, motion blocks and id
|
||||
*
|
||||
* TODO: Does currently not work with virtual scrolling tables. Filter predicates will be missed :(
|
||||
*/
|
||||
// private setFulltextFilter(): void {
|
||||
// this.dataSource.filterPredicate = (data, filter) => {
|
||||
// if (!data) {
|
||||
// return false;
|
||||
// }
|
||||
// filter = filter ? filter.toLowerCase() : '';
|
||||
// if (data.submitters.length && data.submitters.find(user => user.full_name.toLowerCase().includes(filter))) {
|
||||
// return true;
|
||||
// }
|
||||
// if (data.motion_block && data.motion_block.title.toLowerCase().includes(filter)) {
|
||||
// return true;
|
||||
// }
|
||||
// if (data.title.toLowerCase().includes(filter)) {
|
||||
// return true;
|
||||
// }
|
||||
// if (data.identifier && data.identifier.toLowerCase().includes(filter)) {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// if (
|
||||
// this.getStateLabel(data) &&
|
||||
// this.getStateLabel(data)
|
||||
// .toLocaleLowerCase()
|
||||
// .includes(filter)
|
||||
// ) {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// if (
|
||||
// this.getRecommendationLabel(data) &&
|
||||
// this.getRecommendationLabel(data)
|
||||
// .toLocaleLowerCase()
|
||||
// .includes(filter)
|
||||
// ) {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// const dataid = '' + data.id;
|
||||
// if (dataid.includes(filter)) {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// return false;
|
||||
// };
|
||||
// }
|
||||
|
||||
/**
|
||||
* This function saves the selected view by changes.
|
||||
*
|
||||
@ -478,7 +437,7 @@ export class MotionListComponent extends ListViewBaseComponent<ViewMotion> imple
|
||||
* @param ev a MouseEvent.
|
||||
*/
|
||||
public async openEditInfo(motion: ViewMotion): Promise<void> {
|
||||
if (!this.isMultiSelect) {
|
||||
if (!this.isMultiSelect && this.perms.isAllowed('change_metadata')) {
|
||||
// The interface holding the current information from motion.
|
||||
this.infoDialog = {
|
||||
title: motion.title,
|
||||
|
@ -19,6 +19,7 @@
|
||||
[filterService]="filterService"
|
||||
[sortService]="sortService"
|
||||
[columns]="tableColumnDefinition"
|
||||
[filterProps]="filterProps"
|
||||
[multiSelect]="isMultiSelect"
|
||||
[hiddenInMobile]="['group']"
|
||||
scrollKey="user"
|
||||
@ -35,11 +36,11 @@
|
||||
matTooltip="{{ getUserTooltip(user) | translate }}"
|
||||
></a>
|
||||
<div>
|
||||
<span *ngIf="user.is_active">
|
||||
<span *ngIf="user.is_active !== false">
|
||||
{{ name }}
|
||||
</span>
|
||||
|
||||
<span *ngIf="!user.is_active">
|
||||
<span *ngIf="user.is_active === false">
|
||||
<os-icon-container icon="block" swap="true">
|
||||
{{ name }}
|
||||
</os-icon-container>
|
||||
@ -96,7 +97,7 @@
|
||||
class="checkbox-ripple-padding"
|
||||
(change)="setPresent(user)"
|
||||
[checked]="user.is_present"
|
||||
[disabled]="isMultiSelect"
|
||||
[disabled]="isMultiSelect || !this.operator.hasPerms('users.can_manage')"
|
||||
>
|
||||
<span translate>Present</span>
|
||||
</mat-checkbox>
|
||||
|
@ -126,6 +126,11 @@ export class UserListComponent extends ListViewBaseComponent<ViewUser> implement
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* Define extra filter properties
|
||||
*/
|
||||
public filterProps = ['full_name', 'groups', 'structure_level', 'number'];
|
||||
|
||||
/**
|
||||
* The usual constructor for components
|
||||
* @param titleService Serivce for setting the title
|
||||
@ -413,20 +418,4 @@ export class UserListComponent extends ListViewBaseComponent<ViewUser> implement
|
||||
viewUser.user.is_present = !viewUser.user.is_present;
|
||||
await this.repo.update(viewUser.user, viewUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrites the dataSource's string filter with a case-insensitive search
|
||||
* in the full_name property
|
||||
*
|
||||
* TODO: Filter predicates will be missed :(
|
||||
*/
|
||||
// private setFulltextFilter(): void {
|
||||
// this.dataSource.filterPredicate = (data, filter) => {
|
||||
// if (!data || !data.full_name) {
|
||||
// return false;
|
||||
// }
|
||||
// filter = filter ? filter.toLowerCase() : '';
|
||||
// return data.full_name.toLowerCase().indexOf(filter) >= 0;
|
||||
// };
|
||||
// }
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user