Skip to content

Commit

Permalink
feat(): next (#1384)
Browse files Browse the repository at this point in the history
* feat(NovoDataTable): updating data table logic and template to better facilitate custom filters (#1382)

* fix(NovoButton): disabling enter/space keypresses on disabled/loading buttons (#1375)

* fix(NovoSelect): Fix issue with hints not displaying within Novo Select controls (#1374)

fix(NovoSelect): Fix issue with hints not displaying within Novo Select controls.

Co-authored-by: Kevin Cable <[email protected]>

* chore(deps): addressing multiple high level security alerts (#1376)

* fix(): addressing multiple high level security updates

* adding back and updating htmlhint dep

* feat(NovoDataTable): updating data table logic and template to better facilitate custom filters

* fix(NovoDataTable): fixing scrollbar issue

* fixing typing issue

* stricter typing on filter header label

Co-authored-by: Vonterio Duncan <[email protected]>
Co-authored-by: Kevin Cable <[email protected]>

* fix(quickNote): Allow placeholder to hide when clicking in text field to write a note (#1386)

Allow placeholder to hide when clicking in text field to write a note

---------

Co-authored-by: Vonterio Duncan <[email protected]>
Co-authored-by: Kevin Cable <[email protected]>
Co-authored-by: EthanMcM <[email protected]>
  • Loading branch information
4 people authored Feb 2, 2023
1 parent b77d596 commit e2ef564
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 107 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output } from '@angular/core';
import { NovoLabelService } from '../../../services/novo-label-service';
import { Helpers } from '../../../utils';

@Component({
selector: 'novo-data-table-cell-filter-header',
template: `
<div class="header">
<novo-label>{{ label || labels.filters }}</novo-label>
<novo-button
theme="dialogue"
color="negative"
size="small"
icon="times"
(click)="clearFilter.emit()"
*ngIf="hasFilter"
data-automation-id="novo-data-table-filter-clear">
{{ labels.clear }}
</novo-button>
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class NovoDataTableCellFilterHeader {
@Input() label: string | number;

@Input()
set filter(filter: any) {
this._filter = filter;
this.hasFilter = !Helpers.isEmpty(filter);
}
get filter(): any {
return this._filter;
}
private _filter: any;

public hasFilter = false;

@Output() clearFilter: EventEmitter<void> = new EventEmitter<void>();

constructor(public changeDetectorRef: ChangeDetectorRef, public labels: NovoLabelService) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,90 +46,79 @@ import { DataTableState } from '../state/data-table-state.service';
[tooltip]="labels.sort"
[attr.data-feature-id]="'novo-data-table-sort-' + this.id"
(sortChange)="sort()"
[value]="sortValue"
></novo-sort-button>
[value]="sortValue"></novo-sort-button>
<novo-dropdown
*ngIf="config.filterable"
side="right"
parentScrollSelector=".novo-data-table-container"
containerClass="data-table-dropdown"
data-automation-id="novo-data-table-filter"
[multiple]="multiSelect"
>
[multiple]="multiSelect">
<novo-icon
dropdownTrigger
class="filter-button"
[class.filter-active]="filterActive"
[tooltip]="labels.filters"
tooltipPosition="right"
[attr.data-feature-id]="'novo-data-table-filter-' + this.id"
(click)="focusInput()"
>filter</novo-icon
>
<div class="header">
<novo-label>{{ labels.filters }}</novo-label>
<novo-button
theme="dialogue"
color="negative"
size="small"
icon="times"
(click)="clearFilter()"
*ngIf="filter !== null && filter !== undefined && filter !== ''"
data-automation-id="novo-data-table-filter-clear"
>
{{ labels.clear }}
</novo-button>
</div>
<div class="optgroup-container">
<ng-container [ngSwitch]="config.filterConfig.type">
<novo-optgroup *ngSwitchCase="'date'" (keydown.escape)="handleEscapeKeydown($event)">
<ng-container *ngIf="!showCustomRange">
(click)="focusInput()">filter</novo-icon>
<ng-container [ngSwitch]="config.filterConfig.type">
<ng-container *ngSwitchCase="'date'" (keydown.escape)="handleEscapeKeydown($event)">
<novo-data-table-cell-filter-header [filter]="filter" (clearFilter)="clearFilter()"></novo-data-table-cell-filter-header>
<div class="optgroup-container">
<novo-optgroup>
<ng-container *ngIf="!showCustomRange">
<novo-option
[class.active]="activeDateFilter === option.label"
*ngFor="let option of config.filterConfig.options"
(click)="filterData(option)"
[attr.data-automation-id]="'novo-data-table-filter-' + option.label">
<span>{{ option.label }}</span>
<novo-icon novoSuffix color="positive" *ngIf="activeDateFilter === option.label">check</novo-icon>
</novo-option>
</ng-container>
<novo-option
[class.active]="activeDateFilter === option.label"
[class.active]="labels.customDateRange === activeDateFilter"
(click)="toggleCustomRange($event, true)"
*ngIf="config.filterConfig.allowCustomRange && !showCustomRange">
<span>{{ labels.customDateRange }}</span>
<novo-icon novoSuffix color="positive" *ngIf="labels.customDateRange === activeDateFilter">check</novo-icon>
</novo-option>
<novo-option class="calendar-container" *ngIf="showCustomRange" keepOpen>
<novo-stack>
<div class="back-link" (click)="toggleCustomRange($event, false)">
<i class="bhi-previous"></i>
{{ labels.backToPresetFilters }}
</div>
<novo-date-picker
(onSelect)="filterData($event)"
[(ngModel)]="filter"
range="true"
(keydown.escape)="handleEscapeKeydown($event)"></novo-date-picker>
</novo-stack>
</novo-option>
</novo-optgroup>
</div>
</ng-container>
<ng-container *ngSwitchCase="'select'">
<novo-data-table-cell-filter-header [filter]="filter" (clearFilter)="clearFilter()"></novo-data-table-cell-filter-header>
<div class="optgroup-container">
<novo-optgroup>
<novo-option
[class.active]="filter === option"
*ngFor="let option of config.filterConfig.options"
(click)="filterData(option)"
[attr.data-automation-id]="'novo-data-table-filter-' + option.label"
>
<span>{{ option.label }}</span>
<novo-icon novoSuffix color="positive" *ngIf="activeDateFilter === option.label">check</novo-icon>
[attr.data-automation-id]="'novo-data-table-filter-' + (option?.label || option)">
<span>{{ option?.label || option }}</span>
<novo-icon novoSuffix color="positive" *ngIf="option.hasOwnProperty('value') ? filter === option.value : filter === option">
check</novo-icon>
</novo-option>
</ng-container>
<novo-option
[class.active]="labels.customDateRange === activeDateFilter"
(click)="toggleCustomRange($event, true)"
*ngIf="config.filterConfig.allowCustomRange && !showCustomRange"
>
<span>{{ labels.customDateRange }}</span>
<novo-icon novoSuffix color="positive" *ngIf="labels.customDateRange === activeDateFilter">check</novo-icon>
</novo-option>
<novo-option class="calendar-container" *ngIf="showCustomRange" keepOpen>
<novo-stack>
<div class="back-link" (click)="toggleCustomRange($event, false)">
<i class="bhi-previous"></i>{{ labels.backToPresetFilters }}
</div>
<novo-date-picker
(onSelect)="filterData($event)"
[(ngModel)]="filter"
range="true"
(keydown.escape)="handleEscapeKeydown($event)"
></novo-date-picker>
</novo-stack>
</novo-option>
</novo-optgroup>
<novo-optgroup *ngSwitchCase="'select'">
<novo-option
[class.active]="filter === option"
*ngFor="let option of config.filterConfig.options"
(click)="filterData(option)"
[attr.data-automation-id]="'novo-data-table-filter-' + (option?.label || option)"
>
<span>{{ option?.label || option }}</span>
<novo-icon novoSuffix color="positive" *ngIf="option.hasOwnProperty('value') ? filter === option.value : filter === option"
>check</novo-icon
>
</novo-option>
</novo-optgroup>
<ng-container *ngSwitchCase="'multi-select'">
</novo-optgroup>
</div>
</ng-container>
<ng-container *ngSwitchCase="'multi-select'">
<novo-data-table-cell-filter-header [filter]="filter" (clearFilter)="clearFilter()"></novo-data-table-cell-filter-header>
<div class="optgroup-container">
<novo-optgroup class="dropdown-list-filter" (keydown)="multiSelectOptionFilterHandleKeydown($event)">
<novo-option class="filter-search" novoInert>
<novo-field flex>
Expand All @@ -139,12 +128,11 @@ import { DataTableState } from '../state/data-table-state.service';
(ngModelChange)="multiSelectOptionFilter($event)"
#optionFilterInput
data-automation-id="novo-data-table-multi-select-option-filter-input"
(keydown.enter)="multiSelectOptionFilterHandleKeydown($event)"
/>
(keydown.enter)="multiSelectOptionFilterHandleKeydown($event)" />
<novo-icon novoSuffix>search</novo-icon>
<novo-error class="error-text" [hidden]="!error || !multiSelectHasVisibleOptions()">{{
labels.selectFilterOptions
}}</novo-error>
<novo-error class="error-text" [hidden]="!error || !multiSelectHasVisibleOptions()">
{{ labels.selectFilterOptions }}
</novo-error>
</novo-field>
</novo-option>
</novo-optgroup>
Expand All @@ -153,39 +141,45 @@ import { DataTableState } from '../state/data-table-state.service';
*ngFor="let option of config.filterConfig.options"
[hidden]="multiSelectOptionIsHidden(option)"
(click)="toggleSelection(option)"
[attr.data-automation-id]="'novo-data-table-filter-' + (option?.label || option)"
>
[attr.data-automation-id]="'novo-data-table-filter-' + (option?.label || option)">
<span>{{ option?.label || option }}</span>
<novo-icon novoSuffix color="positive">{{
isSelected(option, multiSelectedOptions) ? 'checkbox-filled' : 'checkbox-empty'
}}</novo-icon>
<novo-icon novoSuffix color="positive">
{{ isSelected(option, multiSelectedOptions) ? 'checkbox-filled' : 'checkbox-empty' }}
</novo-icon>
</novo-option>
</novo-optgroup>
<novo-option class="filter-null-results" [hidden]="multiSelectHasVisibleOptions()">{{ labels.pickerEmpty }}</novo-option>
</div>
</ng-container>
<ng-container *ngSwitchCase="'custom'">
<ng-container *ngIf="dropdown">
<novo-data-table-cell-filter-header *ngIf="!config.filterConfig?.useCustomHeader" [filter]="filter" (clearFilter)="clearFilter()"></novo-data-table-cell-filter-header>
<div class="optgroup-container">
<ng-container *ngTemplateOutlet="filterTemplate; context: { $implicit: config, column, dropdown, filter }"></ng-container>
</div>
</ng-container>
<novo-optgroup *ngSwitchCase="'custom'">
<novo-option class="filter-search" novoInert>
<ng-container *ngTemplateOutlet="filterTemplate; context: { $implicit: config }"></ng-container>
</novo-option>
</novo-optgroup>
<novo-optgroup *ngSwitchDefault (keydown.escape)="handleEscapeKeydown($event)">
<novo-option class="filter-search" novoInert>
<novo-field flex fullWidth>
<input
novoInput
[type]="config.filterConfig.type"
[(ngModel)]="filter"
(ngModelChange)="filterData($event)"
#filterInput
data-automation-id="novo-data-table-filter-input"
(keydown.escape)="handleEscapeKeydown($event)"
/>
<novo-icon novoSuffix>search</novo-icon>
</novo-field>
</novo-option>
</novo-optgroup>
</ng-container>
</div>
<ng-container *ngSwitchDefault (keydown.escape)="handleEscapeKeydown($event)">
<novo-data-table-cell-filter-header [filter]="filter" (clearFilter)="clearFilter()"></novo-data-table-cell-filter-header>
<div class="optgroup-container">
<novo-optgroup>
<novo-option class="filter-search" novoInert>
<novo-field flex fullWidth>
<input
novoInput
[type]="config.filterConfig.type"
[(ngModel)]="filter"
(ngModelChange)="filterData($event)"
#filterInput
data-automation-id="novo-data-table-filter-input"
(keydown.escape)="handleEscapeKeydown($event)" />
<novo-icon novoSuffix>search</novo-icon>
</novo-field>
</novo-option>
</novo-optgroup>
</div>
</ng-container>
</ng-container>
<div class="footer" *ngIf="multiSelect">
<novo-button theme="dialogue" color="dark" (click)="cancel()" data-automation-id="novo-data-table-multi-select-cancel">
{{ labels.cancel }}
Expand All @@ -194,8 +188,7 @@ import { DataTableState } from '../state/data-table-state.service';
theme="dialogue"
color="positive"
(click)="filterMultiSelect()"
data-automation-id="novo-data-table-multi-select-filter"
>
data-automation-id="novo-data-table-multi-select-filter">
{{ labels.filters }}
</novo-button>
</div>
Expand Down Expand Up @@ -266,6 +259,10 @@ export class NovoDataTableCellHeader<T> implements IDataTableSortFilter, OnInit,

this.config.transforms = transforms;
}
get column(): IDataTableColumn<T> {
return this._column;
}
private _column: IDataTableColumn<T>;

private _rerenderSubscription: Subscription;
private changeTimeout: any;
Expand Down Expand Up @@ -294,7 +291,6 @@ export class NovoDataTableCellHeader<T> implements IDataTableSortFilter, OnInit,
public optionFilter: string = '';
public error: boolean = false;
private subscriptions: Subscription[] = [];
private _column: IDataTableColumn<T>;

constructor(
public changeDetectorRef: ChangeDetectorRef,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from './data-table-checkbox-header-cell.component';
export * from './data-table-expand-header-cell.component';
export * from './data-table-header-cell.component';
export * from './data-table-header-cell.directive';
export * from './data-table-header-cell-filter-header.component';
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ novo-data-table-pagination {

.dropdown-container.data-table-dropdown {
min-width: 220px;
max-width: 230px;
max-width: 280px;
max-height: 500px;
overflow-x: hidden;
overflow-y: hidden;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ import { DataTableState } from './state/data-table-state.service';
<novo-data-table-header-cell
*cdkHeaderCellDef
[column]="column"
[filterTemplate]="templates['column-filter-' + column.id]"
[filterTemplate]="templates['column-filter-' + (column.filterable?.customTemplate || column.id)]"
[novo-data-table-cell-config]="column"
[resized]="resized"
[defaultSort]="defaultSort"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { NovoDataTableCheckboxHeaderCell } from './cell-headers/data-table-check
import { NovoDataTableExpandHeaderCell } from './cell-headers/data-table-expand-header-cell.component';
import { NovoDataTableCellHeader } from './cell-headers/data-table-header-cell.component';
import { NovoDataTableHeaderCell } from './cell-headers/data-table-header-cell.directive';
import { NovoDataTableCellFilterHeader } from './cell-headers/data-table-header-cell-filter-header.component';
import { NovoDataTableCell } from './cells/data-table-cell.component';
import { NovoDataTableCheckboxCell } from './cells/data-table-checkbox-cell.component';
import { NovoDataTableExpandCell } from './cells/data-table-expand-cell.component';
Expand Down Expand Up @@ -75,6 +76,7 @@ import { DataTableState } from './state/data-table-state.service';
NovoDataTableCellHeader,
NovoDataTableSortFilter,
NovoDataTableHeaderCell,
NovoDataTableCellFilterHeader,
NovoDataTableCell,
NovoDataTableHeaderRow,
NovoDataTableRow,
Expand All @@ -98,6 +100,7 @@ import { DataTableState } from './state/data-table-state.service';
DateTableNumberRendererPipe,
DateTableTimeRendererPipe,
DataTableBigDecimalRendererPipe,
NovoDataTableCellFilterHeader,
NovoDataTableClearButton,
NovoDataTableSortButton,
],
Expand Down
4 changes: 3 additions & 1 deletion projects/novo-elements/src/elements/data-table/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export interface IDataTableColumn<T> {
width: number;
};
rightAlignCellContent?: boolean;
configuration?: object; // intended to be implemented by each column type if and as needed
configuration?: any; // intended to be implemented by each column type if and as needed
}

export interface IDataTablePaginationOptions {
Expand All @@ -78,6 +78,8 @@ export interface IDataTableColumnSortConfig {

export interface IDataTableColumnFilterConfig {
type: 'text' | 'number' | 'date' | 'select' | 'multi-select' | 'custom';
customTemplate?: string;
useCustomHeader?: boolean;
options?: string[] | IDataTableColumnFilterOption[];
allowCustomRange?: boolean;
transform?: Function;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,7 @@ export class QuickNoteElement extends OutsideClick implements OnInit, OnDestroy,
this._placeholderElement = document.createElement('div');
this._placeholderElement.className = 'placeholder';
this._placeholderElement.style.cssText =
'margin: 20px; color: #AAAAAA; font-family: sans-serif; font-size: 13px; line-height: 20px; position: absolute; top: 0';
'margin: 20px; color: #AAAAAA; font-family: sans-serif; font-size: 13px; line-height: 20px; position: absolute; top: 0; pointer-events: none';
this._placeholderElement.textContent = this.placeholder;
}
return this._placeholderElement;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ <h6>Enable Selection Retention</h6>
</ng-template>
<!-- Custom Status Filter -->
<ng-template novoTemplate="column-filter-status">
<novo-tiles [options]="customStatusColumnOptions" (onChange)="filterList($event)"
<novo-tiles [options]="customStatusColumnOptions" (onChange)="filterList($event)" padding="md"
[(ngModel)]="customStatusColumnValue"></novo-tiles>
</ng-template>
</novo-data-table>
Expand Down

0 comments on commit e2ef564

Please sign in to comment.