From 2372408e4c1c9561068180065aea6ceb05dba7b2 Mon Sep 17 00:00:00 2001 From: Sean Engelhardt Date: Fri, 19 Jul 2019 14:35:24 +0200 Subject: [PATCH] Implement NGrids filter function - Implements NGrids new "filteredData" function, to restore old filter behavior. Export a quick-filtered list is now possible. - More controll about List-View-Table UI - Use NGrid target-events for better mutli-select behavior - Changes the behavior of hidden headers to ignore paddings-changes - filters are more resistant to errors and storage loss --- .../ui-services/base-filter-list.service.ts | 36 ++++++++++--------- .../list-view-table.component.html | 13 ++++--- .../list-view-table.component.scss | 14 ++++++++ .../list-view-table.component.ts | 28 ++++++++++++--- client/src/app/shared/shared.module.ts | 5 ++- .../agenda-list/agenda-list.component.ts | 4 +-- client/src/app/site/base/base-list-view.ts | 2 +- .../mediafile-list.component.html | 2 +- .../mediafile-list.component.scss | 9 +---- .../motion-block-list.component.html | 1 + .../motion-block-list.component.scss | 10 +++++- .../motion-block-list.component.ts | 5 +-- .../motion-list/motion-list.component.ts | 2 +- .../user-list/user-list.component.ts | 6 ++-- client/src/styles.scss | 12 +++---- 15 files changed, 96 insertions(+), 53 deletions(-) diff --git a/client/src/app/core/ui-services/base-filter-list.service.ts b/client/src/app/core/ui-services/base-filter-list.service.ts index e467bf520..f89c88214 100644 --- a/client/src/app/core/ui-services/base-filter-list.service.ts +++ b/client/src/app/core/ui-services/base-filter-list.service.ts @@ -226,27 +226,29 @@ export abstract class BaseFilterListService { const newDefinitions = this.getFilterDefinitions(); this.store.get('filter_' + this.name).then(storedFilter => { - for (const newDef of newDefinitions) { - let count = 0; - const matchingExistingFilter = storedFilter.find(oldDef => oldDef.property === newDef.property); - for (const option of newDef.options) { - if (typeof option === 'object') { - if (matchingExistingFilter && matchingExistingFilter.options) { - const existingOption = matchingExistingFilter.options.find( - o => - typeof o !== 'string' && - JSON.stringify(o.condition) === JSON.stringify(option.condition) - ) as OsFilterOption; - if (existingOption) { - option.isActive = existingOption.isActive; - } - if (option.isActive) { - count++; + if (!!storedFilter) { + for (const newDef of newDefinitions) { + let count = 0; + const matchingExistingFilter = storedFilter.find(oldDef => oldDef.property === newDef.property); + for (const option of newDef.options) { + if (typeof option === 'object') { + if (matchingExistingFilter && matchingExistingFilter.options) { + const existingOption = matchingExistingFilter.options.find( + o => + typeof o !== 'string' && + JSON.stringify(o.condition) === JSON.stringify(option.condition) + ) as OsFilterOption; + if (existingOption) { + option.isActive = existingOption.isActive; + } + if (option.isActive) { + count++; + } } } } + newDef.count = count; } - newDef.count = count; } this.filterDefinitions = newDefinitions; diff --git a/client/src/app/shared/components/list-view-table/list-view-table.component.html b/client/src/app/shared/components/list-view-table/list-view-table.component.html index f389d9de7..088057749 100644 --- a/client/src/app/shared/components/list-view-table/list-view-table.component.html +++ b/client/src/app/shared/components/list-view-table/list-view-table.component.html @@ -11,25 +11,30 @@ -
+
- + diff --git a/client/src/app/shared/components/list-view-table/list-view-table.component.scss b/client/src/app/shared/components/list-view-table/list-view-table.component.scss index a98acac70..a8b20da9c 100644 --- a/client/src/app/shared/components/list-view-table/list-view-table.component.scss +++ b/client/src/app/shared/components/list-view-table/list-view-table.component.scss @@ -3,3 +3,17 @@ .projector-button { margin: auto; } + +.pbl-ngrid-row { + height: 110px; +} + +.pbl-ngrid-cell { + height: inherit; +} + +.multiselect { + .pbl-ngrid-cell { + cursor: pointer; + } +} diff --git a/client/src/app/shared/components/list-view-table/list-view-table.component.ts b/client/src/app/shared/components/list-view-table/list-view-table.component.ts index 3a0f8eac9..d1a6cb1ef 100644 --- a/client/src/app/shared/components/list-view-table/list-view-table.component.ts +++ b/client/src/app/shared/components/list-view-table/list-view-table.component.ts @@ -9,17 +9,19 @@ import { ViewEncapsulation, ChangeDetectorRef } from '@angular/core'; +import { Observable } from 'rxjs'; + +import { PblDataSource, columnFactory, PblNgridComponent, createDS } from '@pebula/ngrid'; +import { PblColumnDefinition, PblNgridColumnSet } from '@pebula/ngrid/lib/table'; +import { PblNgridDataMatrixRow } from '@pebula/ngrid/target-events'; import { BaseViewModel } from 'app/site/base/base-view-model'; import { BaseProjectableViewModel } from 'app/site/base/base-projectable-view-model'; import { BaseSortListService } from 'app/core/ui-services/base-sort-list.service'; import { BaseViewModelWithContentObject } from 'app/site/base/base-view-model-with-content-object'; -import { PblDataSource, columnFactory, PblNgridComponent, createDS } from '@pebula/ngrid'; import { BaseFilterListService } from 'app/core/ui-services/base-filter-list.service'; -import { Observable } from 'rxjs'; import { BaseRepository } from 'app/core/repositories/base-repository'; import { BaseModel } from 'app/shared/models/base/base-model'; -import { PblColumnDefinition, PblNgridColumnSet } from '@pebula/ngrid/lib/table'; import { Permission, OperatorService } from 'app/core/core-services/operator.service'; import { StorageService } from 'app/core/core-services/storage.service'; import { ViewportService } from 'app/core/ui-services/viewport.service'; @@ -221,7 +223,7 @@ export class ListViewTableComponent): void { + if (this.multiSelect) { + const clickedModel: V = event.row; + const alreadySelected = this.dataSource.selection.isSelected(clickedModel); + if (alreadySelected) { + this.dataSource.selection.deselect(clickedModel); + } else { + this.dataSource.selection.select(clickedModel); + } + } + } + /** * Depending on the view, the view model in the row can either be a * `BaseViewModelWithContentObject` or a `BaseViewModelWithContentObject`. diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts index 7944c729a..6e7928cac 100644 --- a/client/src/app/shared/shared.module.ts +++ b/client/src/app/shared/shared.module.ts @@ -58,6 +58,7 @@ import { AutofocusDirective } from './directives/autofocus.directive'; // PblNgrid. Cleanup Required. import { PblNgridModule } from '@pebula/ngrid'; import { PblNgridMaterialModule } from '@pebula/ngrid-material'; +import { PblNgridTargetEventsModule } from '@pebula/ngrid/target-events'; // components import { HeadBarComponent } from './components/head-bar/head-bar.component'; @@ -152,7 +153,8 @@ import { AttachmentControlComponent } from './components/attachment-control/atta CdkTreeModule, ScrollingModule, PblNgridModule, - PblNgridMaterialModule + PblNgridMaterialModule, + PblNgridTargetEventsModule ], exports: [ FormsModule, @@ -226,6 +228,7 @@ import { AttachmentControlComponent } from './components/attachment-control/atta SpeakerButtonComponent, PblNgridModule, PblNgridMaterialModule, + PblNgridTargetEventsModule, ListViewTableComponent, AgendaContentObjectFormComponent, ExtensionFieldComponent diff --git a/client/src/app/site/agenda/components/agenda-list/agenda-list.component.ts b/client/src/app/site/agenda/components/agenda-list/agenda-list.component.ts index 6bb2b9d1d..bf896ff94 100644 --- a/client/src/app/site/agenda/components/agenda-list/agenda-list.component.ts +++ b/client/src/app/site/agenda/components/agenda-list/agenda-list.component.ts @@ -303,7 +303,7 @@ export class AgendaListComponent extends BaseListViewComponent impleme * Export all items as CSV */ public csvExportItemList(): void { - this.csvExport.exportItemList(this.dataSource.source); + this.csvExport.exportItemList(this.dataSource.filteredData); } /** @@ -312,7 +312,7 @@ export class AgendaListComponent extends BaseListViewComponent impleme */ public onDownloadPdf(): void { const filename = this.translate.instant('Agenda'); - this.pdfService.download(this.agendaPdfService.agendaListToDocDef(this.dataSource.source), filename); + this.pdfService.download(this.agendaPdfService.agendaListToDocDef(this.dataSource.filteredData), filename); } /** diff --git a/client/src/app/site/base/base-list-view.ts b/client/src/app/site/base/base-list-view.ts index 0dbccf20b..f1f6bf687 100644 --- a/client/src/app/site/base/base-list-view.ts +++ b/client/src/app/site/base/base-list-view.ts @@ -89,7 +89,7 @@ export abstract class BaseListViewComponent extends Bas * Select all files in the current data source */ public selectAll(): void { - this.dataSource.selection.select(...this.dataSource.source); + this.dataSource.selection.select(...this.dataSource.filteredData); } /** diff --git a/client/src/app/site/mediafiles/components/mediafile-list/mediafile-list.component.html b/client/src/app/site/mediafiles/components/mediafile-list/mediafile-list.component.html index c9fbd6b4a..fdd9da0c4 100644 --- a/client/src/app/site/mediafiles/components/mediafile-list/mediafile-list.component.html +++ b/client/src/app/site/mediafiles/components/mediafile-list/mediafile-list.component.html @@ -66,7 +66,7 @@
- +
diff --git a/client/src/app/site/mediafiles/components/mediafile-list/mediafile-list.component.scss b/client/src/app/site/mediafiles/components/mediafile-list/mediafile-list.component.scss index 660d06028..730676629 100644 --- a/client/src/app/site/mediafiles/components/mediafile-list/mediafile-list.component.scss +++ b/client/src/app/site/mediafiles/components/mediafile-list/mediafile-list.component.scss @@ -57,7 +57,7 @@ font-size: 90%; } - height: calc(100vh - 170px); + height: calc(100vh - 105px); .pbl-ngrid-row { $size: 60px; @@ -67,11 +67,4 @@ height: $size !important; } } - - // For some reason, hiding the table header adds an empty meta bar. - .pbl-ngrid-container { - > div { - display: none; - } - } } diff --git a/client/src/app/site/motions/modules/motion-block/components/motion-block-list/motion-block-list.component.html b/client/src/app/site/motions/modules/motion-block/components/motion-block-list/motion-block-list.component.html index 933b16df6..1ffecbfdb 100644 --- a/client/src/app/site/motions/modules/motion-block/components/motion-block-list/motion-block-list.component.html +++ b/client/src/app/site/motions/modules/motion-block/components/motion-block-list/motion-block-list.component.html @@ -38,6 +38,7 @@ implements OnInit { /** diff --git a/client/src/app/site/motions/modules/motion-list/components/motion-list/motion-list.component.ts b/client/src/app/site/motions/modules/motion-list/components/motion-list/motion-list.component.ts index 9f3700779..9ba5f279c 100644 --- a/client/src/app/site/motions/modules/motion-list/components/motion-list/motion-list.component.ts +++ b/client/src/app/site/motions/modules/motion-list/components/motion-list/motion-list.component.ts @@ -308,7 +308,7 @@ export class MotionListComponent extends BaseListViewComponent imple exportDialogRef.afterClosed().subscribe((exportInfo: ExportFormData) => { if (exportInfo && exportInfo.format) { - const data = this.isMultiSelect ? this.selectedRows : this.dataSource.source; + const data = this.isMultiSelect ? this.selectedRows : this.dataSource.filteredData; if (exportInfo.format === FileFormat.PDF) { try { this.pdfExport.exportMotionCatalog(data, exportInfo); diff --git a/client/src/app/site/users/components/user-list/user-list.component.ts b/client/src/app/site/users/components/user-list/user-list.component.ts index 17d0be7a5..4530e3de2 100644 --- a/client/src/app/site/users/components/user-list/user-list.component.ts +++ b/client/src/app/site/users/components/user-list/user-list.component.ts @@ -245,7 +245,7 @@ export class UserListComponent extends BaseListViewComponent implement */ public csvExportUserList(): void { this.csvExport.export( - this.dataSource.source, + this.dataSource.filteredData, [ { property: 'title' }, { property: 'first_name', label: 'Given name' }, @@ -270,7 +270,7 @@ export class UserListComponent extends BaseListViewComponent implement * (access information, including personal information such as initial passwords) */ public onDownloadAccessPdf(): void { - this.userPdf.exportMultipleUserAccessPDF(this.dataSource.source); + this.userPdf.exportMultipleUserAccessPDF(this.dataSource.filteredData); } /** @@ -278,7 +278,7 @@ export class UserListComponent extends BaseListViewComponent implement * with all users currently matching the filter */ public pdfExportUserList(): void { - this.userPdf.exportUserList(this.dataSource.source); + this.userPdf.exportUserList(this.dataSource.filteredData); } /** diff --git a/client/src/styles.scss b/client/src/styles.scss index e2c5725da..c55fe4d71 100644 --- a/client/src/styles.scss +++ b/client/src/styles.scss @@ -191,11 +191,6 @@ } } -.ngrid-lg { - height: 110px; - min-height: 90px; -} - /** Define the general style-rules */ * { font-family: OSFont, Fira Sans, Roboto, Arial, Helvetica, sans-serif; @@ -629,6 +624,7 @@ button.mat-menu-item.selected { * Depending in mobile-mode and desktop mode we need to subtract different values * from 100vh */ +// no os-sort-filter-bar .virtual-scroll-full-page { height: calc(100vh - 64px); } @@ -638,14 +634,16 @@ button.mat-menu-item.selected { display: inline-block; line-height: 150%; } - +// with os-sort-filter-bar .virtual-scroll-with-head-bar { height: calc(100vh - 125px); +} +.ngrid-hide-head { // For some reason, hiding the table header adds an empty meta bar. .pbl-ngrid-container { > div { - display: none; + height: 0; } } }