UNPKG

novo-elements

Version:

1 lines 118 kB
{"version":3,"file":"novo-elements-elements-simple-table.mjs","sources":["../../../projects/novo-elements/src/elements/simple-table/activity-table-renderers.ts","../../../projects/novo-elements/src/elements/simple-table/state.ts","../../../projects/novo-elements/src/elements/simple-table/sort.ts","../../../projects/novo-elements/src/elements/simple-table/cell.ts","../../../projects/novo-elements/src/elements/simple-table/cell-header.ts","../../../projects/novo-elements/src/elements/simple-table/pagination.ts","../../../projects/novo-elements/src/elements/simple-table/PaginationOld.ts","../../../projects/novo-elements/src/elements/simple-table/row.ts","../../../projects/novo-elements/src/elements/simple-table/table-source.ts","../../../projects/novo-elements/src/elements/simple-table/table.ts","../../../projects/novo-elements/src/elements/simple-table/simple-table.module.ts","../../../projects/novo-elements/src/elements/simple-table/novo-elements-elements-simple-table.ts"],"sourcesContent":["export class ActivityTableRenderers {\n static propertyRenderer<T>(prop: string): Function {\n const ret = (data: T): string => {\n // TODO - allow for dots and sub props\n return data[prop];\n };\n return ret;\n }\n\n static dateRenderer<T>(prop: string): Function {\n const ret = (data: T): string => {\n return data[prop] ? new Date(data[prop]).toLocaleDateString() : '';\n };\n return ret;\n }\n}\n","import { EventEmitter, Injectable } from '@angular/core';\nimport { NovoSimpleTableChange } from './interfaces';\n\n@Injectable()\nexport class NovoActivityTableState {\n id: number = Math.random();\n sort: { id: string; value: string } = undefined;\n filter: { id: string; value: string } = undefined;\n page: number = 0;\n pageSize: number = undefined;\n globalSearch: string = undefined;\n selectedRows: Map<string, object> = new Map<string, object>();\n outsideFilter: any;\n\n updates: EventEmitter<NovoSimpleTableChange> = new EventEmitter<NovoSimpleTableChange>();\n onReset: EventEmitter<boolean> = new EventEmitter<boolean>();\n\n get userFiltered(): boolean {\n return !!(this.filter || this.sort || this.globalSearch || this.outsideFilter);\n }\n\n public reset(fireUpdate: boolean = true, persistUserFilters?: boolean): void {\n if (!persistUserFilters) {\n this.sort = undefined;\n this.globalSearch = undefined;\n this.filter = undefined;\n }\n this.page = 0;\n this.selectedRows.clear();\n this.onReset.emit(true);\n if (fireUpdate) {\n this.updates.emit({\n sort: this.sort,\n filter: this.filter,\n globalSearch: this.globalSearch,\n });\n }\n }\n}\n","import { Directive, EventEmitter, OnDestroy, Output } from '@angular/core';\nimport { Helpers } from 'novo-elements/utils';\nimport { NovoActivityTableState } from './state';\n\n@Directive({\n selector: '[novoSortFilter]',\n standalone: false,\n})\nexport class NovoSortFilter {\n constructor(private state: NovoActivityTableState) {}\n\n public filter(id: string, value: any, transform: Function): void {\n let filter;\n if (!Helpers.isBlank(value)) {\n filter = { id, value, transform };\n } else {\n filter = undefined;\n }\n this.state.filter = filter;\n this.state.reset(false, true);\n this.state.updates.next({ filter, sort: this.state.sort });\n }\n\n public sort(id: string, value: string, transform: Function): void {\n const sort = { id, value, transform };\n this.state.sort = sort;\n this.state.reset(false, true);\n this.state.updates.next({ sort, filter: this.state.filter });\n }\n}\n\n@Directive({\n selector: '[novoSelection]',\n standalone: false,\n})\nexport class NovoSelection implements OnDestroy {\n @Output()\n public novoSelectAllToggle = new EventEmitter<boolean>();\n\n public allRows = new Map<string, object>();\n private throttleTimeout: any;\n\n constructor(public state: NovoActivityTableState) {}\n\n public register(id, row): void {\n this.allRows.set(id, row);\n }\n\n public deregister(id): void {\n this.allRows.delete(id);\n this.state.selectedRows.delete(id);\n clearTimeout(this.throttleTimeout);\n this.throttleTimeout = setTimeout(() => {\n if (this.state.selectedRows.size === 0) {\n this.novoSelectAllToggle.emit(false);\n }\n });\n }\n\n public ngOnDestroy(): void {\n this.allRows.clear();\n this.state.selectedRows.clear();\n }\n\n public toggle(id: string, selected: boolean, row: any): void {\n if (selected) {\n this.state.selectedRows.set(id, row);\n } else {\n this.state.selectedRows.delete(id);\n }\n }\n\n public selectAll(value: boolean): void {\n if (value) {\n this.state.selectedRows = new Map<string, object>(this.allRows);\n } else {\n this.state.selectedRows.clear();\n }\n this.novoSelectAllToggle.emit(value);\n }\n}\n","import { CdkCell, CdkCellDef, CdkColumnDef, CdkHeaderCell, CdkHeaderCellDef } from '@angular/cdk/table';\nimport {\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n Directive,\n ElementRef,\n HostBinding,\n Input,\n OnDestroy,\n OnInit,\n Optional,\n Renderer2,\n} from '@angular/core';\nimport { Subscription } from 'rxjs';\nimport { NovoLabelService } from 'novo-elements/services';\nimport { Helpers } from 'novo-elements/utils';\nimport { SimpleTableActionColumn, SimpleTableActionColumnOption, SimpleTableColumn } from './interfaces';\nimport { NovoSelection } from './sort';\n\n/** Workaround for https://github.com/angular/angular/issues/17849 */\nexport const _NovoCellDef = CdkCellDef;\nexport const _NovoHeaderCellDef = CdkHeaderCellDef;\nexport const _NovoColumnDef = CdkColumnDef;\nexport const _NovoHeaderCell = CdkHeaderCell;\nexport const _NovoCell = CdkCell;\n\n@Directive({\n selector: '[novoSimpleCellDef]',\n providers: [{ provide: CdkCellDef, useExisting: NovoSimpleCellDef }],\n standalone: false,\n})\nexport class NovoSimpleCellDef extends _NovoCellDef {\n // TODO: add explicit constructor\n}\n\n@Directive({\n selector: '[novoSimpleHeaderCellDef]',\n providers: [{ provide: CdkHeaderCellDef, useExisting: NovoSimpleHeaderCellDef }],\n standalone: false,\n})\nexport class NovoSimpleHeaderCellDef extends _NovoHeaderCellDef {\n // TODO: add explicit constructor\n}\n\n@Directive({\n selector: '[novoSimpleColumnDef]',\n providers: [{ provide: CdkColumnDef, useExisting: NovoSimpleColumnDef }],\n standalone: false,\n})\nexport class NovoSimpleColumnDef extends _NovoColumnDef {\n @Input('novoSimpleColumnDef')\n get name(): string {\n return this._name;\n }\n set name(name: string) {\n this._setNameInput(name);\n }\n /**\n * This has been extracted to a util because of TS 4 and VE.\n * View Engine doesn't support property rename inheritance.\n * TS 4.0 doesn't allow properties to override accessors or vice-versa.\n * @docs-private\n */\n protected _setNameInput(value: string) {\n // If the directive is set without a name (updated programatically), then this setter will\n // trigger with an empty string and should not overwrite the programatically set value.\n if (value) {\n this._name = value;\n this.cssClassFriendlyName = value.replace(/[^a-z0-9_-]/gi, '-');\n this._updateColumnCssClassName();\n }\n }\n}\n\n@Directive({\n selector: 'novo-simple-header-cell',\n standalone: false,\n})\nexport class NovoSimpleHeaderCell<T> extends _NovoHeaderCell implements OnInit {\n @HostBinding('attr.role')\n public role = 'columnheader';\n\n @Input()\n public column: SimpleTableColumn<T>;\n\n constructor(columnDef: CdkColumnDef, private elementRef: ElementRef, private renderer: Renderer2) {\n super(columnDef, elementRef);\n renderer.setAttribute(elementRef.nativeElement, 'data-automation-id', `novo-column-header-${columnDef.cssClassFriendlyName}`);\n renderer.addClass(elementRef.nativeElement, `novo-column-${columnDef.cssClassFriendlyName}`);\n renderer.addClass(elementRef.nativeElement, 'novo-simple-header-cell');\n }\n\n public ngOnInit(): void {\n if (this.column.width) {\n this.renderer.setStyle(this.elementRef.nativeElement, 'min-width', `${this.column.width}px`);\n this.renderer.setStyle(this.elementRef.nativeElement, 'max-width', `${this.column.width}px`);\n this.renderer.setStyle(this.elementRef.nativeElement, 'width', `${this.column.width}px`);\n }\n }\n}\n\n@Directive({\n selector: 'novo-simple-empty-header-cell',\n standalone: false,\n})\nexport class NovoSimpleEmptyHeaderCell extends _NovoHeaderCell {\n @HostBinding('attr.role')\n public role = 'columnheader';\n\n constructor(columnDef: CdkColumnDef, elementRef: ElementRef, renderer: Renderer2) {\n super(columnDef, elementRef);\n renderer.setAttribute(elementRef.nativeElement, 'data-automation-id', `novo-column-header-${columnDef.cssClassFriendlyName}`);\n renderer.addClass(elementRef.nativeElement, `novo-column-${columnDef.cssClassFriendlyName}`);\n renderer.addClass(elementRef.nativeElement, 'novo-simple-empty-header-cell');\n }\n}\n\n@Component({\n selector: 'novo-simple-checkbox-header-cell',\n template: '<novo-checkbox [(ngModel)]=\"selectAll\" (ngModelChange)=\"toggle($event)\"></novo-checkbox>',\n standalone: false,\n})\nexport class NovoSimpleCheckboxHeaderCell extends _NovoHeaderCell implements OnDestroy {\n @HostBinding('attr.role')\n public role = 'columnheader';\n\n public selectAll: boolean = false;\n private selectAllSubscription: Subscription;\n\n constructor(\n columnDef: CdkColumnDef,\n elementRef: ElementRef,\n renderer: Renderer2,\n ref: ChangeDetectorRef,\n @Optional() private _selection: NovoSelection,\n ) {\n super(columnDef, elementRef);\n renderer.setAttribute(elementRef.nativeElement, 'data-automation-id', `novo-checkbox-column-header-${columnDef.cssClassFriendlyName}`);\n renderer.addClass(elementRef.nativeElement, `novo-checkbox-column-${columnDef.cssClassFriendlyName}`);\n renderer.addClass(elementRef.nativeElement, 'novo-simple-checkbox-header-cell');\n\n this.selectAllSubscription = _selection.novoSelectAllToggle.subscribe((value: boolean) => {\n this.selectAll = value;\n ref.markForCheck();\n });\n }\n\n public ngOnDestroy(): void {\n this.selectAllSubscription.unsubscribe();\n }\n\n public toggle(value: boolean): void {\n this._selection.selectAll(value);\n }\n}\n\n@Component({\n selector: 'novo-simple-cell',\n template: ' <span [class.clickable]=\"!!column.onClick\" (click)=\"onClick($event)\" #span>{{ column.renderer(row) }}</span> ',\n changeDetection: ChangeDetectionStrategy.OnPush,\n standalone: false,\n})\nexport class NovoSimpleCell<T> extends _NovoCell implements OnInit {\n @HostBinding('attr.role')\n public role = 'gridcell';\n\n @Input()\n public row: any;\n @Input()\n public column: SimpleTableColumn<T>;\n\n constructor(columnDef: CdkColumnDef, private elementRef: ElementRef, private renderer: Renderer2) {\n super(columnDef, elementRef);\n renderer.setAttribute(elementRef.nativeElement, 'data-automation-id', `novo-column-${columnDef.cssClassFriendlyName}`);\n renderer.addClass(elementRef.nativeElement, `novo-column-${columnDef.cssClassFriendlyName}`);\n renderer.addClass(elementRef.nativeElement, 'novo-simple-cell');\n }\n\n public ngOnInit(): void {\n if (this.column.customClass) {\n this.renderer.addClass(this.elementRef.nativeElement, this.column.customClass(this.row));\n }\n if (this.column.width) {\n this.renderer.setStyle(this.elementRef.nativeElement, 'min-width', `${this.column.width}px`);\n this.renderer.setStyle(this.elementRef.nativeElement, 'max-width', `${this.column.width}px`);\n this.renderer.setStyle(this.elementRef.nativeElement, 'width', `${this.column.width}px`);\n }\n }\n\n public onClick(event: MouseEvent): void {\n Helpers.swallowEvent(event);\n if (this.column.onClick) {\n this.column.onClick(this.row);\n }\n return;\n }\n}\n\n@Component({\n selector: 'novo-simple-checkbox-cell',\n template: ' <novo-checkbox [ngModel]=\"selected\" (ngModelChange)=\"toggle($event)\"></novo-checkbox> ',\n standalone: false,\n})\nexport class NovoSimpleCheckboxCell extends _NovoCell implements OnDestroy, OnInit {\n @HostBinding('attr.role')\n public role = 'gridcell';\n\n @Input()\n public row: any;\n @Input()\n public index: any;\n\n public selected: boolean = false;\n private selectAllSubscription: Subscription;\n\n constructor(public columnDef: CdkColumnDef, elementRef: ElementRef, renderer: Renderer2, @Optional() public _selection: NovoSelection) {\n super(columnDef, elementRef);\n renderer.setAttribute(elementRef.nativeElement, 'data-automation-id', `novo-checkbox-column-${columnDef.cssClassFriendlyName}`);\n renderer.addClass(elementRef.nativeElement, `novo-checkbox-column-${columnDef.cssClassFriendlyName}`);\n renderer.addClass(elementRef.nativeElement, 'novo-simple-checkbox-cell');\n\n this.selectAllSubscription = _selection.novoSelectAllToggle.subscribe((value: boolean) => {\n this.selected = value;\n });\n }\n\n public ngOnInit(): void {\n this._selection.register(this.row.id || this.index, this.row);\n this.selected = this._selection.state.selectedRows.has(this.row.id || this.index);\n }\n\n public ngOnDestroy(): void {\n this._selection.deregister(this.row.id || this.index);\n this.selectAllSubscription.unsubscribe();\n }\n\n public toggle(value: boolean): void {\n this._selection.toggle(this.row.id || this.index, value, this.row);\n }\n}\n\n@Component({\n selector: 'novo-simple-action-cell',\n template: `\n <ng-container *ngIf=\"!column.options\">\n <novo-button theme=\"icon\" [icon]=\"column.icon\" (click)=\"column.onClick(row)\" [disabled]=\"isDisabled(column, row)\"></novo-button>\n </ng-container>\n <ng-container *ngIf=\"column.options\">\n <novo-dropdown parentScrollSelector=\".novo-simple-table\" containerClass=\"novo-table-dropdown-cell\">\n <novo-button type=\"button\" theme=\"dialogue\" icon=\"collapse\" inverse>{{ column.label || labels.actions }}</novo-button>\n <list>\n <item *ngFor=\"let option of column.options\" (action)=\"option.onClick(row)\" [disabled]=\"isDisabled(option, row)\">\n <span [attr.data-automation-id]=\"option.label\">{{ option.label }}</span>\n </item>\n </list>\n </novo-dropdown>\n </ng-container>\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n standalone: false,\n})\nexport class NovoSimpleActionCell<T> extends _NovoCell implements OnInit {\n @HostBinding('attr.role')\n public role = 'gridcell';\n\n @Input()\n public row: T;\n @Input()\n public column: SimpleTableActionColumn<T>;\n\n constructor(columnDef: CdkColumnDef, private elementRef: ElementRef, private renderer: Renderer2, public labels: NovoLabelService) {\n super(columnDef, elementRef);\n renderer.setAttribute(elementRef.nativeElement, 'data-automation-id', `novo-action-column-${columnDef.cssClassFriendlyName}`);\n }\n\n public ngOnInit(): void {\n if (this.column.options) {\n this.renderer.addClass(this.elementRef.nativeElement, 'novo-simple-dropdown-cell');\n } else {\n this.renderer.addClass(this.elementRef.nativeElement, 'novo-simple-button-cell');\n }\n }\n\n public isDisabled(check: SimpleTableActionColumn<T> | SimpleTableActionColumnOption<T>, row: T): boolean {\n if (check.disabled === true) {\n return true;\n }\n if (check.disabledCheck) {\n return check.disabledCheck(row);\n }\n return false;\n }\n}\n","import { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { CdkColumnDef } from '@angular/cdk/table';\nimport {\n AfterViewInit,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n Directive,\n ElementRef,\n Input,\n OnDestroy,\n OnInit,\n Optional,\n ViewChild,\n ViewEncapsulation,\n} from '@angular/core';\nimport { startOfToday, startOfTomorrow } from 'date-fns';\nimport { Subscription } from 'rxjs';\nimport { NovoLabelService } from 'novo-elements/services';\nimport { DateUtil, Helpers } from 'novo-elements/utils';\nimport { NovoDropdownElement } from 'novo-elements/elements/dropdown';\nimport { NovoSimpleSortFilter, NovoSimpleTableChange, SimpleTableColumnFilterConfig, SimpleTableColumnFilterOption } from './interfaces';\nimport { NovoSortFilter } from './sort';\nimport { NovoActivityTableState } from './state';\n\n@Directive({\n selector: '[novoSimpleFilterFocus]',\n standalone: false,\n})\nexport class NovoSimpleFilterFocus implements AfterViewInit {\n constructor(private element: ElementRef) {}\n\n ngAfterViewInit() {\n this.element.nativeElement.focus();\n }\n}\n\n@Component({\n selector: '[novo-simple-cell-config]',\n template: `\n <label (click)=\"sort()\" data-automation-id=\"novo-activity-table-label\" [class.sort-disabled]=\"!config.sortable\">\n <ng-content></ng-content>\n </label>\n <div>\n <novo-button\n *ngIf=\"config.sortable\"\n theme=\"icon\"\n [icon]=\"icon\"\n (click)=\"sort()\"\n [class.active]=\"sortActive\"\n data-automation-id=\"novo-activity-table-sort\"\n ></novo-button>\n <novo-dropdown\n *ngIf=\"config.filterable\"\n side=\"right\"\n parentScrollSelector=\".novo-simple-table\"\n containerClass=\"simple-table-dropdown\"\n data-automation-id=\"novo-activity-table-filter\"\n >\n <novo-button type=\"button\" theme=\"icon\" icon=\"filter\" [class.active]=\"filterActive\"></novo-button>\n <div class=\"header\">\n <span>{{ labels.filters }}</span>\n <novo-button\n theme=\"dialogue\"\n color=\"negative\"\n icon=\"times\"\n (click)=\"clearFilter()\"\n *ngIf=\"filter\"\n data-automation-id=\"novo-activity-table-filter-clear\"\n >\n {{ labels.clear }}\n </novo-button>\n </div>\n <ng-container [ngSwitch]=\"config.filterConfig.type\">\n <novo-optgroup *ngSwitchCase=\"'date'\">\n <ng-container *ngIf=\"!showCustomRange\">\n <novo-option\n [class.active]=\"activeDateFilter === option.label\"\n *ngFor=\"let option of config.filterConfig.options\"\n (click)=\"filterData(option)\"\n [attr.data-automation-id]=\"'novo-activity-table-filter-' + option.label\"\n >\n {{ option.label }} <i class=\"bhi-check\" *ngIf=\"activeDateFilter === option.label\"></i>\n </novo-option>\n </ng-container>\n <novo-option\n [class.active]=\"labels.customDateRange === activeDateFilter\"\n (click)=\"toggleCustomRange($event, true)\"\n *ngIf=\"config.filterConfig.allowCustomRange && !showCustomRange\"\n [keepOpen]=\"true\"\n >\n {{ labels.customDateRange }} <i class=\"bhi-check\" *ngIf=\"labels.customDateRange === activeDateFilter\"></i>\n </novo-option>\n <div class=\"calendar-container\" *ngIf=\"showCustomRange\">\n <div (click)=\"toggleCustomRange($event, false)\"><i class=\"bhi-previous\"></i>{{ labels.backToPresetFilters }}</div>\n <novo-date-picker (onSelect)=\"filterData($event)\" [(ngModel)]=\"filter\" range=\"true\"></novo-date-picker>\n </div>\n </novo-optgroup>\n <novo-optgroup *ngSwitchCase=\"'select'\">\n <novo-option\n [class.active]=\"filter === option\"\n *ngFor=\"let option of config.filterConfig.options\"\n (click)=\"filterData(option)\"\n [attr.data-automation-id]=\"'novo-activity-table-filter-' + (option?.label || option)\"\n >\n <span>{{ option?.label || option }}</span>\n <i class=\"bhi-check\" *ngIf=\"option.hasOwnProperty('value') ? filter === option.value : filter === option\"></i>\n </novo-option>\n </novo-optgroup>\n <novo-optgroup *ngSwitchDefault>\n <novo-option class=\"filter-search\" keepOpen>\n <input\n type=\"text\"\n [(ngModel)]=\"filter\"\n (ngModelChange)=\"filterData($event)\"\n novoSimpleFilterFocus\n data-automation-id=\"novo-activity-table-filter-input\"\n />\n </novo-option>\n </novo-optgroup>\n </ng-container>\n </novo-dropdown>\n </div>\n `,\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n standalone: false,\n})\nexport class NovoSimpleCellHeader implements NovoSimpleSortFilter, OnInit, OnDestroy {\n @ViewChild(NovoDropdownElement)\n dropdown: NovoDropdownElement;\n\n @Input()\n defaultSort: { id: string; value: string };\n\n @Input('novo-simple-cell-config')\n get config() {\n return this._config;\n }\n\n set config(v) {\n if (!v) {\n this._config = {\n sortable: false,\n filterable: false,\n filterConfig: {\n type: 'text',\n },\n };\n } else {\n this._config = {\n sortable: coerceBooleanProperty(v.sortable),\n filterable: coerceBooleanProperty(v.filterable),\n transforms: v.transforms || {},\n filterConfig: v.filterConfig || {\n type: 'text',\n },\n };\n\n if (this._config.filterConfig.type === 'date' && !this._config.filterConfig.options) {\n this._config.filterConfig.options = this.getDefaultDateFilterOptions();\n }\n }\n }\n\n private _config: {\n sortable: boolean;\n filterable: boolean;\n transforms?: { filter?: Function; sort?: Function };\n filterConfig: SimpleTableColumnFilterConfig;\n };\n\n private _rerenderSubscription: Subscription;\n private changeTimeout: any;\n\n public icon: string = 'sortable';\n public id: string;\n public filter: string | boolean;\n public direction: string;\n public filterActive: boolean = false;\n public sortActive: boolean = false;\n public showCustomRange: boolean = false;\n public activeDateFilter: string;\n\n constructor(\n private changeDetectorRef: ChangeDetectorRef,\n public labels: NovoLabelService,\n private state: NovoActivityTableState,\n @Optional() public _sort: NovoSortFilter,\n @Optional() public _cdkColumnDef: CdkColumnDef,\n ) {\n this._rerenderSubscription = state.updates.subscribe((change: NovoSimpleTableChange) => {\n if (change.sort && change.sort.id === this.id) {\n this.icon = `sort-${change.sort.value}`;\n this.sortActive = true;\n } else {\n this.icon = 'sortable';\n this.sortActive = false;\n }\n if (change.filter && change.filter.id === this.id) {\n this.filterActive = true;\n this.filter = change.filter.value;\n } else {\n this.filterActive = false;\n this.filter = undefined;\n }\n changeDetectorRef.markForCheck();\n });\n }\n\n public ngOnInit(): void {\n if (this._cdkColumnDef) {\n this.id = this._cdkColumnDef.name;\n }\n if (this.defaultSort && this.id === this.defaultSort.id) {\n this.icon = `sort-${this.defaultSort.value}`;\n this.sortActive = true;\n this.changeDetectorRef.markForCheck();\n }\n }\n\n public ngOnDestroy(): void {\n this._rerenderSubscription.unsubscribe();\n }\n\n public sort(): void {\n if (this.changeTimeout) {\n clearTimeout(this.changeTimeout);\n }\n this.changeTimeout = setTimeout(() => {\n this.direction = this.getNextSortDirection(this.direction);\n this._sort.sort(this.id, this.direction, this._config.transforms.sort);\n this.changeDetectorRef.markForCheck();\n }, 300);\n }\n\n public toggleCustomRange(event: Event, value: boolean): void {\n Helpers.swallowEvent(event);\n this.showCustomRange = value;\n this.changeDetectorRef.markForCheck();\n this.dropdown.openPanel(); // Ensures that the panel correctly updates to the dynamic size of the dropdown\n }\n\n public filterData(filter?: any): void {\n let actualFilter = filter;\n if (this.config.filterConfig.type === 'date' && filter) {\n this.activeDateFilter = filter.label || this.labels.customDateRange;\n if (filter.startDate && filter.endDate) {\n actualFilter = {\n min: DateUtil.startOfDay(filter.startDate.date),\n max: DateUtil.startOfDay(DateUtil.addDays(DateUtil.startOfDay(filter.endDate.date), 1)),\n };\n } else {\n actualFilter = {\n min: filter.min ? DateUtil.addDays(startOfToday(), filter.min) : startOfToday(),\n max: filter.max ? DateUtil.addDays(startOfTomorrow(), filter.max) : startOfTomorrow(),\n };\n }\n }\n\n if (actualFilter && actualFilter.hasOwnProperty('value')) {\n actualFilter = filter.value;\n }\n\n if (this.changeTimeout) {\n clearTimeout(this.changeTimeout);\n }\n\n this.changeTimeout = setTimeout(() => {\n if (actualFilter === '') {\n actualFilter = undefined;\n }\n this._sort.filter(this.id, actualFilter, this.config.transforms.filter);\n this.changeDetectorRef.markForCheck();\n }, 300);\n }\n\n public clearFilter(): void {\n this.filter = undefined;\n this.activeDateFilter = undefined;\n this.filterData();\n }\n\n private getNextSortDirection(direction: string): string {\n if (!direction) {\n return 'asc';\n }\n if (direction === 'asc') {\n return 'desc';\n }\n return 'asc';\n }\n\n private getDefaultDateFilterOptions(): SimpleTableColumnFilterOption[] {\n const opts: SimpleTableColumnFilterOption[] = [\n { label: this.labels.past1Day, min: -1, max: 0 },\n { label: this.labels.past7Days, min: -7, max: 0 },\n { label: this.labels.past30Days, min: -30, max: 0 },\n { label: this.labels.past90Days, min: -90, max: 0 },\n { label: this.labels.past1Year, min: -366, max: 0 },\n { label: this.labels.next1Day, min: 0, max: 1 },\n { label: this.labels.next7Days, min: 0, max: 7 },\n { label: this.labels.next30Days, min: 0, max: 30 },\n { label: this.labels.next90Days, min: 0, max: 90 },\n { label: this.labels.next1Year, min: 0, max: 366 },\n ];\n return opts;\n }\n}\n","import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';\nimport { Subscription } from 'rxjs';\nimport { NovoLabelService } from 'novo-elements/services';\nimport { NovoSimplePaginationEvent } from './interfaces';\nimport { NovoActivityTableState } from './state';\n\nconst DEFAULT_PAGE_SIZE = 50;\n\n@Component({\n selector: 'novo-simple-table-pagination',\n template: `\n <div class=\"novo-simple-table-pagination-size\">\n <novo-tiles\n *ngIf=\"displayedPageSizeOptions.length > 1\"\n [(ngModel)]=\"pageSize\"\n [options]=\"displayedPageSizeOptions\"\n (onChange)=\"changePageSize($event)\"\n data-automation-id=\"novo-simple-table-pagination-tiles\"\n >\n </novo-tiles>\n <div *ngIf=\"displayedPageSizeOptions.length <= 1\">{{ pageSize }}</div>\n </div>\n\n <div class=\"novo-simple-table-range-label-long\" data-automation-id=\"novo-simple-table-pagination-range-label-long\">\n {{ longRangeLabel }}\n </div>\n <div class=\"novo-simple-table-range-label-short\" data-automation-id=\"novo-simple-table-pagination-range-label-short\">\n {{ shortRangeLabel }}\n </div>\n\n <novo-button\n theme=\"dialogue\"\n type=\"button\"\n class=\"novo-simple-table-pagination-navigation-previous\"\n (click)=\"previousPage()\"\n icon=\"previous\"\n side=\"left\"\n [disabled]=\"!hasPreviousPage()\"\n data-automation-id=\"novo-simple-table-pagination-previous\"\n >\n <span>{{ labels.previous }}</span>\n </novo-button>\n <novo-button\n theme=\"dialogue\"\n type=\"button\"\n class=\"novo-simple-table-pagination-navigation-next\"\n (click)=\"nextPage()\"\n icon=\"next\"\n side=\"right\"\n [disabled]=\"!hasNextPage()\"\n data-automation-id=\"novo-simple-table-pagination-next\"\n >\n <span>{{ labels.next }}</span>\n </novo-button>\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n standalone: false,\n})\nexport class NovoSimpleTablePagination implements OnInit, OnDestroy {\n private _initialized: boolean;\n\n @Input()\n get page(): number {\n return this._page;\n }\n set page(page: number) {\n this._page = page;\n this.changeDetectorRef.markForCheck();\n this.longRangeLabel = this.labels.getRangeText(this.page, this.pageSize, this.length, false);\n this.shortRangeLabel = this.labels.getRangeText(this.page, this.pageSize, this.length, true);\n this.state.page = this._page;\n }\n _page: number = 0;\n\n @Input()\n get length(): number {\n return this._length;\n }\n set length(length: number) {\n this._length = length;\n this.changeDetectorRef.markForCheck();\n this.longRangeLabel = this.labels.getRangeText(this.page, this.pageSize, this.length, false);\n this.shortRangeLabel = this.labels.getRangeText(this.page, this.pageSize, this.length, true);\n }\n _length: number = 0;\n\n @Input()\n get pageSize(): number {\n return this._pageSize;\n }\n set pageSize(pageSize: number) {\n this._pageSize = pageSize;\n this.updateDisplayedPageSizeOptions();\n this.state.pageSize = this._pageSize;\n }\n private _pageSize: number;\n\n @Input()\n get pageSizeOptions(): number[] {\n return this._pageSizeOptions;\n }\n set pageSizeOptions(pageSizeOptions: number[]) {\n this._pageSizeOptions = pageSizeOptions;\n this.updateDisplayedPageSizeOptions();\n }\n private _pageSizeOptions: number[] = [];\n\n @Output()\n pageChange = new EventEmitter<NovoSimplePaginationEvent>();\n\n public displayedPageSizeOptions: number[];\n public longRangeLabel: string;\n public shortRangeLabel: string;\n\n private resetSubscription: Subscription;\n\n constructor(private changeDetectorRef: ChangeDetectorRef, public labels: NovoLabelService, private state: NovoActivityTableState) {\n if (state && state.onReset) {\n this.resetSubscription = this.state.onReset.subscribe((clear: boolean) => {\n if (clear) {\n this.page = 0;\n this.changeDetectorRef.markForCheck();\n }\n });\n }\n }\n\n public ngOnInit(): void {\n this._initialized = true;\n this.updateDisplayedPageSizeOptions();\n }\n\n public ngOnDestroy(): void {\n this.resetSubscription.unsubscribe();\n }\n\n public nextPage(): void {\n if (!this.hasNextPage()) {\n return;\n }\n this.page++;\n this.emitPageEvent();\n }\n\n public previousPage(): void {\n if (!this.hasPreviousPage()) {\n return;\n }\n this.page--;\n this.emitPageEvent();\n }\n\n public hasPreviousPage(): boolean {\n return this.page >= 1 && this.pageSize !== 0;\n }\n\n public hasNextPage(): boolean {\n const numberOfPages = Math.ceil(this.length / this.pageSize) - 1;\n return this.page < numberOfPages && this.pageSize !== 0;\n }\n\n public changePageSize(pageSize: number): void {\n this.page = 0;\n this.pageSize = pageSize;\n this.emitPageEvent();\n }\n\n private updateDisplayedPageSizeOptions(): void {\n if (!this._initialized) {\n return;\n }\n if (!this.pageSize) {\n this._pageSize = this.pageSizeOptions.length !== 0 ? this.pageSizeOptions[0] : DEFAULT_PAGE_SIZE;\n }\n this.displayedPageSizeOptions = this.pageSizeOptions.slice();\n if (this.displayedPageSizeOptions.indexOf(this.pageSize) === -1) {\n this.displayedPageSizeOptions.push(this.pageSize);\n }\n this.displayedPageSizeOptions.sort((a, b) => a - b);\n this.changeDetectorRef.markForCheck();\n this.longRangeLabel = this.labels.getRangeText(this.page, this.pageSize, this.length, false);\n this.shortRangeLabel = this.labels.getRangeText(this.page, this.pageSize, this.length, true);\n }\n\n private emitPageEvent(): void {\n const event = {\n page: this.page,\n pageSize: this.pageSize,\n length: this.length,\n };\n this.pageChange.next(event);\n this.state.page = this.page;\n this.state.pageSize = this.pageSize;\n this.longRangeLabel = this.labels.getRangeText(this.page, this.pageSize, this.length, false);\n this.shortRangeLabel = this.labels.getRangeText(this.page, this.pageSize, this.length, true);\n this.state.updates.next(event);\n }\n}\n","// NG2\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewEncapsulation } from '@angular/core';\n// APP\nimport { NovoLabelService } from 'novo-elements/services';\n\ninterface Page {\n num: number;\n text: string;\n active: boolean;\n}\n@Component({\n selector: 'novo-pagination',\n template: `\n <ng-container *ngIf=\"rowOptions.length > 1\">\n <h5 class=\"rows\">{{ label }}</h5>\n <novo-select\n class=\"table-pagination-select\"\n [options]=\"rowOptions\"\n [placeholder]=\"labels.select\"\n [(ngModel)]=\"itemsPerPage\"\n (onSelect)=\"onPageSizeChanged($event)\"\n data-automation-id=\"pager-select\"\n ></novo-select>\n <span class=\"spacer\"></span>\n </ng-container>\n <ul class=\"pager\" data-automation-id=\"pager\">\n <li class=\"page\" (click)=\"selectPage(page - 1)\" [ngClass]=\"{ disabled: noPrevious() }\">\n <i class=\"bhi-previous\" data-automation-id=\"pager-previous\"></i>\n </li>\n <li\n class=\"page\"\n [ngClass]=\"{ active: p.active }\"\n [class.disabled]=\"disablePageSelection\"\n *ngFor=\"let p of pages\"\n (click)=\"selectPage(p.num, $event)\"\n >\n {{ p.text }}\n </li>\n <li class=\"page\" (click)=\"selectPage(page + 1)\" [ngClass]=\"{ disabled: noNext() }\">\n <i class=\"bhi-next\" data-automation-id=\"pager-next\"></i>\n </li>\n </ul>\n `,\n styleUrls: ['./PaginationOld.scss'],\n encapsulation: ViewEncapsulation.None,\n standalone: false,\n})\nexport class Pagination implements OnInit, OnChanges {\n @Input()\n page: number;\n @Input()\n totalItems: number;\n @Input()\n itemsPerPage = 10;\n @Input()\n rowOptions;\n @Input()\n label: string;\n @Input()\n get disablePageSelection(): boolean {\n return this.pageSelectDisabled;\n }\n set disablePageSelection(val: boolean) {\n this.pageSelectDisabled = coerceBooleanProperty(val);\n }\n @Output()\n pageChange = new EventEmitter();\n @Output()\n itemsPerPageChange = new EventEmitter();\n @Output()\n onPageChange = new EventEmitter();\n\n public pageSelectDisabled: boolean;\n maxPagesDisplayed = 5;\n totalPages: number;\n pages: Array<Page>;\n\n constructor(public labels: NovoLabelService) {}\n\n ngOnInit() {\n this.label = this.label || this.labels.itemsPerPage;\n this.rowOptions = this.rowOptions || this.getDefaultRowOptions();\n }\n\n ngOnChanges(changes?: SimpleChanges) {\n this.page = this.page || 1;\n this.totalPages = this.calculateTotalPages();\n this.pages = this.getPages(this.page, this.totalPages);\n }\n\n getDefaultRowOptions() {\n return [\n { value: 10, label: '10' },\n { value: 25, label: '25' },\n { value: 50, label: '50' },\n { value: 100, label: '100' },\n ];\n }\n\n onPageSizeChanged(event) {\n this.page = 1;\n this.itemsPerPage = event.selected;\n this.totalPages = this.calculateTotalPages();\n this.pages = this.getPages(this.page, this.totalPages);\n this.pageChange.emit(this.page);\n this.itemsPerPageChange.emit(this.itemsPerPage);\n this.onPageChange.emit({\n page: this.page,\n itemsPerPage: this.itemsPerPage,\n });\n }\n\n selectPage(page: number, event?: MouseEvent) {\n if (event) {\n event.preventDefault();\n }\n\n this.page = page;\n this.pages = this.getPages(this.page, this.totalPages);\n this.pageChange.emit(this.page);\n this.onPageChange.emit({\n page: this.page,\n itemsPerPage: this.itemsPerPage,\n });\n }\n\n noPrevious() {\n return this.page === 1;\n }\n\n noNext() {\n return this.page === this.totalPages;\n }\n\n // Create page object used in template\n makePage(num: number, text: string, isActive: boolean) {\n return { num, text, active: isActive } as Page;\n }\n\n getPages(currentPage: number, totalPages: number) {\n const pages: Array<Page> = [];\n // Default page limits\n let startPage = 1;\n let endPage = totalPages;\n const isMaxSized = this.maxPagesDisplayed < totalPages;\n\n // recompute if maxPagesDisplayed\n if (isMaxSized) {\n // Current page is displayed in the middle of the visible ones\n startPage = Math.max(currentPage - Math.floor(this.maxPagesDisplayed / 2), 1);\n endPage = startPage + this.maxPagesDisplayed - 1;\n\n // Adjust if limit is exceeded\n if (endPage > totalPages) {\n endPage = totalPages;\n startPage = endPage - this.maxPagesDisplayed + 1;\n }\n }\n\n // Add page number links\n for (let num = startPage; num <= endPage; num++) {\n const page = this.makePage(num, num.toString(), num === currentPage);\n pages.push(page);\n }\n return pages;\n }\n\n calculateTotalPages() {\n const totalPages = this.itemsPerPage < 1 ? 1 : Math.ceil(this.totalItems / this.itemsPerPage);\n return Math.max(totalPages || 0, 1);\n }\n}\n","import { CdkHeaderRow, CdkHeaderRowDef, CdkRow, CdkRowDef, CDK_ROW_TEMPLATE } from '@angular/cdk/table';\nimport { ChangeDetectionStrategy, Component, Directive, HostBinding, Input } from '@angular/core';\n\n/** Workaround for https://github.com/angular/angular/issues/17849 */\nexport const _NovoHeaderRowDef = CdkHeaderRowDef;\nexport const _NovoCdkRowDef = CdkRowDef;\nexport const _NovoHeaderRow = CdkHeaderRow;\nexport const _NovoRow = CdkRow;\n\n@Directive({\n selector: '[novoSimpleHeaderRowDef]',\n providers: [{ provide: CdkHeaderRowDef, useExisting: NovoSimpleHeaderRowDef }],\n standalone: false,\n})\nexport class NovoSimpleHeaderRowDef extends _NovoHeaderRowDef {\n // TODO: add explicit constructor\n\n @Input('novoSimpleHeaderRowDef')\n columns;\n}\n\n@Directive({\n selector: '[novoSimpleRowDef]',\n providers: [{ provide: CdkRowDef, useExisting: NovoSimpleRowDef }],\n standalone: false,\n})\nexport class NovoSimpleRowDef<T> extends _NovoCdkRowDef<T> {\n // TODO: add explicit constructor\n\n @Input('novoSimpleRowDefColumns')\n columns;\n}\n\n@Component({\n selector: 'novo-simple-header-row',\n template: CDK_ROW_TEMPLATE,\n changeDetection: ChangeDetectionStrategy.OnPush,\n standalone: false,\n})\nexport class NovoSimpleHeaderRow extends _NovoHeaderRow {\n @HostBinding('class')\n public rowClass = 'novo-simple-header-row';\n @HostBinding('attr.role')\n public role = 'row';\n}\n\n@Component({\n selector: 'novo-simple-row',\n template: CDK_ROW_TEMPLATE,\n changeDetection: ChangeDetectionStrategy.OnPush,\n standalone: false,\n})\nexport class NovoSimpleRow extends _NovoRow {\n @HostBinding('class')\n public rowClass = 'novo-simple-row';\n @HostBinding('attr.role')\n public role = 'row';\n}\n","import { DataSource } from '@angular/cdk/table';\nimport { ChangeDetectorRef } from '@angular/core';\nimport { merge, Observable, of } from 'rxjs';\nimport { catchError, map, startWith, switchMap } from 'rxjs/operators';\nimport { Helpers } from 'novo-elements/utils';\nimport { NovoActivityTableState } from './state';\n\nexport interface ActivityTableService<T> {\n getTableResults(\n sort: { id: string; value: string; transform?: Function },\n filter: { id: string; value: string; transform?: Function },\n page: number,\n pageSize: number,\n globalSearch?: string,\n outsideFilter?: any,\n ): Observable<{ results: T[]; total: number }>;\n}\n\nexport abstract class RemoteActivityTableService<T> implements ActivityTableService<T> {\n abstract getTableResults(\n sort: { id: string; value: string; transform?: Function },\n filter: { id: string; value: string; transform?: Function },\n page: number,\n pageSize: number,\n globalSearch?: string,\n outsideFilter?: any,\n ): Observable<{ results: T[]; total: number }>;\n}\n\nexport class StaticActivityTableService<T> implements ActivityTableService<T> {\n constructor(private data: T[] = []) {}\n\n public getTableResults(\n sort: { id: string; value: string; transform?: Function },\n filter: { id: string; value: string; transform?: Function },\n page: number = 0,\n pageSize: number,\n globalSearch?: string,\n outsideFilter?: any,\n ): Observable<{ results: T[]; total: number }> {\n let ret: T[] = Helpers.deepClone(this.data);\n if (ret.length !== 0) {\n if (globalSearch) {\n ret = ret.filter((item) => Object.keys(item).some((key) => `${item[key]}`.toLowerCase().includes(globalSearch.toLowerCase())));\n }\n if (filter) {\n const value = Helpers.isString(filter.value) ? filter.value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&') : filter.value;\n ret = ret.filter(Helpers.filterByField(filter.id, value));\n }\n if (sort) {\n ret = ret.sort(Helpers.sortByField(sort.id, sort.value === 'desc'));\n }\n if (!Helpers.isBlank(page) && !Helpers.isBlank(pageSize)) {\n ret = ret.slice(page * pageSize, (page + 1) * pageSize);\n }\n }\n return of({ results: ret, total: this.data.length });\n }\n}\n\nexport class ActivityTableDataSource<T> extends DataSource<T> {\n public total = 0;\n public current = 0;\n public loading = false;\n public pristine = true;\n\n get totallyEmpty(): boolean {\n return this.total === 0;\n }\n\n get currentlyEmpty(): boolean {\n return this.current === 0;\n }\n\n constructor(private tableService: ActivityTableService<T>, private state: NovoActivityTableState, private ref: ChangeDetectorRef) {\n super();\n }\n\n public connect(): Observable<any[]> {\n const displayDataChanges: any = [this.state.updates];\n return merge(...displayDataChanges).pipe(\n startWith(null),\n switchMap(() => {\n this.pristine = false;\n this.loading = true;\n return this.tableService.getTableResults(\n this.state.sort,\n this.state.filter,\n this.state.page,\n this.state.pageSize,\n this.state.globalSearch,\n this.state.outsideFilter,\n );\n }),\n map((data: { results: T[]; total: number }) => {\n this.loading = false;\n this.total = data.total;\n this.current = data.results.length;\n setTimeout(() => {\n this.ref.markForCheck();\n });\n return data.results;\n }),\n catchError((error) => {\n console.error(error);\n this.loading = false;\n return of(null);\n }),\n );\n }\n\n public disconnect(): void {}\n}\n","import { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { _VIEW_REPEATER_STRATEGY, _DisposeViewRepeaterStrategy } from '@angular/cdk/collections';\nimport { CdkTable, CDK_TABLE } from '@angular/cdk/table';\nimport {\n AfterContentInit,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n Directive,\n EventEmitter,\n HostBinding,\n Input,\n OnChanges,\n OnDestroy,\n SimpleChanges,\n ViewEncapsulation,\n} from '@angular/core';\nimport { Subscription } from 'rxjs';\nimport { NovoLabelService } from 'novo-elements/services';\nimport { notify } from 'novo-elements/utils';\nimport { SimpleTableActionColumn, SimpleTableColumn, SimpleTablePaginationOptions, SimpleTableSearchOptions } from './interfaces';\nimport { NovoActivityTableState } from './state';\nimport { ActivityTableDataSource, ActivityTableService } from './table-source';\n\n@Component({\n selector: 'novo-simple-table',\n template: `\n <table role=\"table\">\n <caption></caption>\n <colgroup></colgroup>\n <thead role=\"rowgroup\">\n <ng-container headerRowOutlet></ng-container>\n </thead>\n <tbody role=\"rowgroup\">\n <ng-container rowOutlet></ng-container>\n <ng-container noDataRowOutlet></ng-container>\n </tbody>\n <tfoot role=\"rowgroup\">\n <ng-container footerRowOutlet></ng-container>\n </tfoot>\n </table>`,\n styleUrls: ['./table.scss'],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [{ provide: CDK_TABLE, useExisting: NovoTable }],\n standalone: false,\n})\nexport class NovoTable<T> extends CdkTable<T> {\n // TODO: add explicit constructor\n}\n\n@Directive({\n selector: 'novo-activity-table-actions',\n standalone: false,\n})\nexport class NovoActivityTableActions {}\n\n@Directive({\n selector: 'novo-activity-table-custom-header',\n standalone: false,\n})\nexport class NovoActivityTableCustomHeader {}\n\n@Directive({\n selector: 'novo-activity-table-custom-filter',\n standalone: false,\n})\nexport class NovoActivityTableCustomFilter {}\n\n@Directive({\n selector: 'novo-activity-table-empty-message',\n standalone: false,\n})\nexport class NovoActivityTableEmptyMessage {}\n\n@Directive({\n selector: 'novo-activity-table-no-results-message',\n standalone: false,\n})\nexport class NovoActivityTableNoResultsMessage {}\n\n@Component({\n selector: 'novo-activity-table',\n template: `\n <div *ngIf=\"debug\">\n <p>Total: {{ dataSource?.total }}</p>\n <p>Current: {{ dataSource?.current }}</p>\n <p>Totally Empty: {{ dataSource?.totallyEmpty }}</p>\n <p>Currently Empty: {{ dataSource?.currentlyEmpty }}</p>\n <p>Loading (DataSource): {{ dataSource?.loading }}</p>\n <p>User Filtered: {{ state.userFiltered }}</p>\n <p>Loading (Table): {{ loading }}</p>\n </div>\n <header *ngIf=\"(!(dataSource?.totallyEmpty && !state.userFiltered) && !loading) || forceShowHeader\">\n <ng-content select=\"[novo-activity-table-custom-header]\"></ng-content>\n <novo-search\n [alwaysOpen]=true\n (searchChanged)=\"onSearchChange($event)\"\n [(ngModel)]=\"state.globalSearch\"\n *ngIf=\"!hideGlobalSearch\"\n [placeholder]=\"searchOptions?.placeholder\"\n [hint]=\"searchOptions?.tooltip\"\n >\n </novo-search>\n <novo-simple-table-pagination\n *ngIf=\"paginationOptions\"\n [length]=\"dataSource?.total\"\n [page]=\"paginationOptions.page\"\n [pageSize]=\"paginationOptions.pageSize\"\n [pageSizeOptions]=\"paginationOptions.pageSizeOptions\"\n >\n </novo-simple-table-pagination>\n <div class=\"novo-activity-table-actions\">\n <ng-content select=\"[novo-activity-table-actions]\"></ng-content>\n </div>\n </header>\n <div class=\"novo-activity-table-loading-mask\" *ngIf=\"dataSource?.loading || loading\" data-automation-id=\"novo-activity-table-loading\">\n <novo-loading></novo-loading>\n </div>\n <div class=\"novo-activity-table-filter-container\">\n <div class=\"novo-activity-table-custom-filter\" *ngIf=\"customFilter\">\n <ng-content select=\"[novo-activity-table-custom-filter]\"></ng-content>\n </div>\n <div class=\"novo-activity-table-container\">\n <novo-simple-table\n *ngIf=\"columns?.length > 0\"\n [dataSource]=\"dataSource\"\n novoSortFilter\n novoSelection\n [class.empty]=\"dataSource?.currentlyEmpty && state.userFiltered\"\n [hidden]=\"dataSource?.totallyEmpty && !state.userFiltered\">\n <ng-content></ng-content>\n <ng-container novoSimpleColumnDef=\"selection\">\n <novo-simple-checkbox-header-cell *novoSimpleHeaderCellDef></novo-simple-checkbox-header-cell>\n <novo-simple-checkbox-cell *novoSimpleCellDef=\"let row; let i = index\" [row]=\"row\" [index]=\"i\"></novo-simple-checkbox-cell>\n </ng-container>\n <ng-container *ngFor=\"let column of actionColumns\" [novoSimpleColumnDef]=\"column.id\">\n <novo-simple-empty-header-cell\n [class.button-header-cell]=\"!column.options\"\n [class.dropdown-header-cell]=\"column.options\"\n *novoSimpleHeaderCellDef\n ></novo-simple-empty-header-cell>\n <novo-simple-action-cell *novoSimpleCellDef=\"let row; let i = index\" [row]=\"row\" [column]=\"column\"></novo-simple-action-cell>\n </ng-container>\n <ng-container *ngFor=\"let column of columns\" [novoSimpleColumnDef]=\"column.id\">\n <novo-simple-header-cell\n *novoSimpleHeaderCellDef\n [column]=\"column\"\n [novo-simple-cell-config]=\"column.config\"\n [defaultSort]=\"defaultSort\"\n >{{ column.label }}</novo-simple-header-cell>\n <novo-simple-cell *novoSimpleCellDef=\"let row\" [column]=\"column\" [row]=\"row\"></novo-simple-cell>\n </ng-container>\n <novo-simple-header-row *novoSimpleHeaderRowDef=\"displayedColumns\"></novo-simple-header-row>\n <novo-simple-row *novoSimpleRowDef=\"let row; columns: displayedColumns\"></novo-simple-row>\n