Skip to content

Commit a2c9164

Browse files
committed
SPIKE Adv table filter bar filtering
1 parent 86dea34 commit a2c9164

File tree

20 files changed

+1064
-120
lines changed

20 files changed

+1064
-120
lines changed

packages/components/package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,12 @@
145145
"./components/hds/accordion/item/button.js": "./dist/_app_/components/hds/accordion/item/button.js",
146146
"./components/hds/accordion/item.js": "./dist/_app_/components/hds/accordion/item.js",
147147
"./components/hds/advanced-table/expandable-tr-group.js": "./dist/_app_/components/hds/advanced-table/expandable-tr-group.js",
148+
"./components/hds/advanced-table/filter-bar/checkbox.js": "./dist/_app_/components/hds/advanced-table/filter-bar/checkbox.js",
149+
"./components/hds/advanced-table/filter-bar/dropdown.js": "./dist/_app_/components/hds/advanced-table/filter-bar/dropdown.js",
150+
"./components/hds/advanced-table/filter-bar/filters-checkbox.js": "./dist/_app_/components/hds/advanced-table/filter-bar/filters-checkbox.js",
151+
"./components/hds/advanced-table/filter-bar/filters-dropdown.js": "./dist/_app_/components/hds/advanced-table/filter-bar/filters-dropdown.js",
152+
"./components/hds/advanced-table/filter-bar.js": "./dist/_app_/components/hds/advanced-table/filter-bar.js",
153+
"./components/hds/advanced-table/filter-bar/radio.js": "./dist/_app_/components/hds/advanced-table/filter-bar/radio.js",
148154
"./components/hds/advanced-table.js": "./dist/_app_/components/hds/advanced-table.js",
149155
"./components/hds/advanced-table/models/column.js": "./dist/_app_/components/hds/advanced-table/models/column.js",
150156
"./components/hds/advanced-table/models/row.js": "./dist/_app_/components/hds/advanced-table/models/row.js",
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{{#let @checkbox as |Checkbox|}}
2+
<Checkbox checked={{this.isChecked}} @value={{@value}} {{on "change" this.onChange}}>
3+
{{yield}}
4+
</Checkbox>
5+
{{/let}}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* Copyright (c) HashiCorp, Inc.
3+
* SPDX-License-Identifier: MPL-2.0
4+
*/
5+
6+
import Component from '@glimmer/component';
7+
import { action } from '@ember/object';
8+
import type { WithBoundArgs } from '@glint/template';
9+
10+
import type { HdsAdvancedTableFilter } from '../types.ts';
11+
12+
import HdsDropdownListItemCheckbox from '../../dropdown/list-item/checkbox.ts';
13+
14+
import type { HdsDropdownSignature } from '../../dropdown/index.ts';
15+
16+
export interface HdsAdvancedTableFilterBarCheckboxSignature {
17+
Args: HdsDropdownSignature['Args'] & {
18+
checkbox?: WithBoundArgs<typeof HdsDropdownListItemCheckbox, never>;
19+
value?: string;
20+
keyFilter: HdsAdvancedTableFilter[] | HdsAdvancedTableFilter | undefined;
21+
onChange?: (event: Event) => void;
22+
};
23+
Blocks: {
24+
default: [];
25+
};
26+
Element: HTMLDivElement;
27+
}
28+
29+
export default class HdsAdvancedTableFilterBarCheckbox extends Component<HdsAdvancedTableFilterBarCheckboxSignature> {
30+
@action
31+
onChange(event: Event): void {
32+
const { onChange } = this.args;
33+
if (onChange && typeof onChange === 'function') {
34+
onChange(event);
35+
}
36+
}
37+
38+
get isChecked(): boolean {
39+
const { keyFilter, value } = this.args;
40+
if (Array.isArray(keyFilter)) {
41+
return keyFilter.some((filter) => filter.value === value);
42+
} else if (keyFilter && value) {
43+
return keyFilter.value === value;
44+
}
45+
return false;
46+
}
47+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{{! @glint-nocheck }}
2+
<Hds::Dropdown
3+
@listPosition="bottom-left"
4+
@height="180px"
5+
class={{this.classNames}}
6+
{{this._updateInternalFilters}}
7+
as |D|
8+
>
9+
{{yield
10+
(hash
11+
ToggleButton=(component D.ToggleButton count=this.numFilters text=@text color="secondary" size="small")
12+
Checkbox=(component
13+
"hds/advanced-table/filter-bar/checkbox"
14+
checkbox=D.Checkbox
15+
keyFilter=this.internalFilters
16+
onChange=this.onChange
17+
)
18+
Radio=(component
19+
"hds/advanced-table/filter-bar/radio" radio=D.Radio keyFilter=this.internalFilters onChange=this.onChange
20+
)
21+
)
22+
}}
23+
{{#unless @isLiveFilter}}
24+
<D.Footer @hasDivider={{true}}>
25+
<Hds::ButtonSet>
26+
<Hds::Button
27+
@text="Apply filters"
28+
@isFullWidth={{true}}
29+
@size="small"
30+
{{on "click" (fn this.onApply D.close)}}
31+
/>
32+
<Hds::Button @text="Clear" @color="secondary" @size="small" {{on "click" (fn this.onClear D.close)}} />
33+
</Hds::ButtonSet>
34+
</D.Footer>
35+
{{/unless}}
36+
</Hds::Dropdown>
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
/**
2+
* Copyright (c) HashiCorp, Inc.
3+
* SPDX-License-Identifier: MPL-2.0
4+
*/
5+
6+
import Component from '@glimmer/component';
7+
import { action } from '@ember/object';
8+
import { tracked } from '@glimmer/tracking';
9+
import { modifier } from 'ember-modifier';
10+
import type { WithBoundArgs } from '@glint/template';
11+
12+
import HdsDropdown from '../../dropdown/index.ts';
13+
import HdsDropdownToggleButton from '../../dropdown/toggle/button.ts';
14+
15+
import HdsAdvancedTableFilterBarCheckbox from './checkbox.ts';
16+
import HdsAdvancedTableFilterBarRadio from './radio.ts';
17+
18+
import type {
19+
HdsAdvancedTableFilter,
20+
HdsAdvancedTableFilters,
21+
} from '../types.ts';
22+
import type { HdsDropdownSignature } from '../../dropdown/index.ts';
23+
24+
export interface HdsAdvancedTableFilterBarDropdownSignature {
25+
Args: HdsDropdownSignature['Args'] & {
26+
dropdown?: WithBoundArgs<typeof HdsDropdown, never>;
27+
key: string;
28+
filters: HdsAdvancedTableFilters;
29+
isMultiSelect?: boolean;
30+
isLiveFilter?: boolean;
31+
activeFilterableColumns?: string[];
32+
onChange: (key: string, keyFilter?: HdsAdvancedTableFilter[]) => void;
33+
};
34+
Blocks: {
35+
default: [
36+
{
37+
ToggleButton?: WithBoundArgs<
38+
typeof HdsDropdownToggleButton,
39+
'color' | 'text' | 'size'
40+
>;
41+
Checkbox?: WithBoundArgs<
42+
typeof HdsAdvancedTableFilterBarCheckbox,
43+
'checkbox' | 'keyFilter' | 'onChange'
44+
>;
45+
Radio?: WithBoundArgs<
46+
typeof HdsAdvancedTableFilterBarRadio,
47+
'radio' | 'keyFilter' | 'onChange'
48+
>;
49+
},
50+
];
51+
};
52+
Element: HTMLDivElement;
53+
}
54+
55+
export default class HdsAdvancedTableFilterBarDropdown extends Component<
56+
HdsDropdownSignature & HdsAdvancedTableFilterBarDropdownSignature
57+
> {
58+
@tracked internalFilters: HdsAdvancedTableFilter[] | undefined = [];
59+
60+
private _updateInternalFilters = modifier(() => {
61+
if (this.keyFilter) {
62+
this.internalFilters = JSON.parse(
63+
JSON.stringify(this.keyFilter)
64+
) as HdsAdvancedTableFilter[];
65+
} else {
66+
this.internalFilters = [];
67+
}
68+
});
69+
70+
get keyFilter(): HdsAdvancedTableFilter[] | undefined {
71+
const { filters, key } = this.args;
72+
73+
if (!filters) {
74+
return undefined;
75+
}
76+
return filters[key];
77+
}
78+
79+
get numFilters(): number {
80+
if (Array.isArray(this.keyFilter)) {
81+
return this.keyFilter.length;
82+
}
83+
return 0;
84+
}
85+
86+
@action
87+
onChange(event: Event): void {
88+
const addFilter = (value: unknown): HdsAdvancedTableFilter[] => {
89+
const newFilter = {
90+
text: value as string,
91+
value: value,
92+
};
93+
if (
94+
Array.isArray(this.internalFilters) &&
95+
input.classList.contains('hds-form-checkbox')
96+
) {
97+
this.internalFilters.push(newFilter);
98+
return this.internalFilters;
99+
} else {
100+
return [newFilter];
101+
}
102+
};
103+
104+
const removeFilter = (value: string): HdsAdvancedTableFilter[] => {
105+
const newFilter = [] as HdsAdvancedTableFilter[];
106+
if (Array.isArray(this.internalFilters)) {
107+
this.internalFilters.forEach((filter) => {
108+
if (filter.value != value) {
109+
newFilter.push(filter);
110+
}
111+
});
112+
}
113+
return newFilter;
114+
};
115+
116+
const input = event.target as HTMLInputElement;
117+
118+
let newFilter = [] as HdsAdvancedTableFilter[];
119+
120+
if (input.checked) {
121+
newFilter = addFilter(input.value);
122+
} else {
123+
newFilter = removeFilter(input.value);
124+
}
125+
126+
this.internalFilters = newFilter;
127+
128+
if (this.args.isLiveFilter) {
129+
const { onChange } = this.args;
130+
if (onChange && typeof onChange === 'function') {
131+
if (newFilter.length === 0) {
132+
onChange(this.args.key, undefined);
133+
} else {
134+
onChange(this.args.key, newFilter);
135+
}
136+
}
137+
}
138+
}
139+
140+
@action
141+
onApply(closeDropdown?: () => void): void {
142+
const { onChange } = this.args;
143+
if (onChange && typeof onChange === 'function') {
144+
onChange(this.args.key, this.internalFilters);
145+
}
146+
147+
if (closeDropdown && typeof closeDropdown === 'function') {
148+
closeDropdown();
149+
}
150+
}
151+
152+
@action
153+
onClear(closeDropdown?: () => void): void {
154+
this.internalFilters = [];
155+
156+
const { onChange } = this.args;
157+
if (onChange && typeof onChange === 'function') {
158+
onChange(this.args.key, this.internalFilters);
159+
}
160+
161+
if (closeDropdown && typeof closeDropdown === 'function') {
162+
closeDropdown();
163+
}
164+
}
165+
166+
get classNames(): string {
167+
const classes = ['hds-advanced-table__filter-bar__dropdown'];
168+
169+
// add a class based on the @align argument
170+
if (!this._isActiveFilterableColumn()) {
171+
classes.push('hds-advanced-table__filter-bar__dropdown--hidden');
172+
}
173+
174+
return classes.join(' ');
175+
}
176+
177+
private _isActiveFilterableColumn(): boolean {
178+
if (this.args.activeFilterableColumns) {
179+
return this.args.activeFilterableColumns.includes(this.args.key);
180+
}
181+
return false;
182+
}
183+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{{#let @checkbox as |Checkbox|}}
2+
<Checkbox checked={{this.isChecked}} @value={{@value}} {{on "change" this.onChange}}>
3+
{{yield}}
4+
</Checkbox>
5+
{{/let}}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* Copyright (c) HashiCorp, Inc.
3+
* SPDX-License-Identifier: MPL-2.0
4+
*/
5+
6+
import Component from '@glimmer/component';
7+
import { action } from '@ember/object';
8+
import type { WithBoundArgs } from '@glint/template';
9+
10+
import HdsDropdownListItemCheckbox from '../../dropdown/list-item/checkbox.ts';
11+
12+
import type { HdsDropdownSignature } from '../../dropdown/index.ts';
13+
14+
export interface HdsAdvancedTableFilterBarFiltersCheckboxSignature {
15+
Args: HdsDropdownSignature['Args'] & {
16+
checkbox?: WithBoundArgs<typeof HdsDropdownListItemCheckbox, never>;
17+
value?: string;
18+
activeFilterableColumns?: string[];
19+
onChange?: (event: Event) => void;
20+
};
21+
Blocks: {
22+
default: [];
23+
};
24+
Element: HTMLDivElement;
25+
}
26+
27+
export default class HdsAdvancedTableFilterBarFiltersCheckbox extends Component<HdsAdvancedTableFilterBarFiltersCheckboxSignature> {
28+
@action
29+
onChange(event: Event): void {
30+
const { onChange } = this.args;
31+
if (onChange && typeof onChange === 'function') {
32+
onChange(event);
33+
}
34+
}
35+
36+
get isChecked(): boolean {
37+
const { value, activeFilterableColumns } = this.args;
38+
return activeFilterableColumns?.includes(value || '') || false;
39+
}
40+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{{! @glint-nocheck }}
2+
<Hds::Dropdown @listPosition="bottom-left" @height="180px" class={{this.classNames}} as |D|>
3+
<D.ToggleButton @text="Filter" @color="secondary" @size="small" />
4+
{{yield
5+
(hash
6+
Checkbox=(component
7+
"hds/advanced-table/filter-bar/filters-checkbox"
8+
checkbox=D.Checkbox
9+
activeFilterableColumns=this.activeFilterableColumns
10+
onChange=this.onChange
11+
)
12+
)
13+
}}
14+
<D.Footer @hasDivider={{true}}>
15+
<Hds::ButtonSet>
16+
<Hds::Button @text="Apply" @isFullWidth={{true}} @size="small" {{on "click" (fn this.onApply D.close)}} />
17+
<Hds::Button @text="Clear" @color="secondary" @size="small" {{on "click" (fn this.onClear D.close)}} />
18+
</Hds::ButtonSet>
19+
</D.Footer>
20+
</Hds::Dropdown>

0 commit comments

Comments
 (0)