@furystack/shades-common-components 13.5.0 → 14.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +58 -0
- package/README.md +3 -3
- package/esm/components/accordion/accordion-item.js +1 -1
- package/esm/components/accordion/accordion-item.js.map +1 -1
- package/esm/components/accordion/accordion.js +1 -1
- package/esm/components/accordion/accordion.js.map +1 -1
- package/esm/components/alert.js +1 -1
- package/esm/components/alert.js.map +1 -1
- package/esm/components/app-bar-link.js +1 -1
- package/esm/components/app-bar-link.js.map +1 -1
- package/esm/components/app-bar.js +1 -1
- package/esm/components/app-bar.js.map +1 -1
- package/esm/components/avatar.js +1 -1
- package/esm/components/avatar.js.map +1 -1
- package/esm/components/badge.js +1 -1
- package/esm/components/badge.js.map +1 -1
- package/esm/components/breadcrumb.js +1 -1
- package/esm/components/breadcrumb.js.map +1 -1
- package/esm/components/breadcrumb.spec.js +3 -3
- package/esm/components/breadcrumb.spec.js.map +1 -1
- package/esm/components/button-group.js +4 -4
- package/esm/components/button-group.js.map +1 -1
- package/esm/components/button.js +1 -1
- package/esm/components/button.js.map +1 -1
- package/esm/components/button.spec.js +1 -1
- package/esm/components/button.spec.js.map +1 -1
- package/esm/components/cache-view.js +1 -1
- package/esm/components/cache-view.js.map +1 -1
- package/esm/components/cache-view.spec.js +2 -2
- package/esm/components/cache-view.spec.js.map +1 -1
- package/esm/components/card.js +5 -5
- package/esm/components/card.js.map +1 -1
- package/esm/components/carousel.js +1 -1
- package/esm/components/carousel.js.map +1 -1
- package/esm/components/chip.js +1 -1
- package/esm/components/chip.js.map +1 -1
- package/esm/components/circular-progress.d.ts +2 -4
- package/esm/components/circular-progress.d.ts.map +1 -1
- package/esm/components/circular-progress.js +3 -6
- package/esm/components/circular-progress.js.map +1 -1
- package/esm/components/circular-progress.spec.js +19 -14
- package/esm/components/circular-progress.spec.js.map +1 -1
- package/esm/components/command-palette/command-palette-input.js +1 -1
- package/esm/components/command-palette/command-palette-input.js.map +1 -1
- package/esm/components/command-palette/command-palette-suggestion-list.js +1 -1
- package/esm/components/command-palette/command-palette-suggestion-list.js.map +1 -1
- package/esm/components/command-palette/command-palette-suggestion-list.spec.js +1 -1
- package/esm/components/command-palette/command-palette-suggestion-list.spec.js.map +1 -1
- package/esm/components/command-palette/index.js +1 -1
- package/esm/components/command-palette/index.js.map +1 -1
- package/esm/components/context-menu/context-menu-item.js +1 -1
- package/esm/components/context-menu/context-menu-item.js.map +1 -1
- package/esm/components/context-menu/context-menu.js +1 -1
- package/esm/components/context-menu/context-menu.js.map +1 -1
- package/esm/components/data-grid/body.js +1 -1
- package/esm/components/data-grid/body.js.map +1 -1
- package/esm/components/data-grid/data-grid-row.js +1 -1
- package/esm/components/data-grid/data-grid-row.js.map +1 -1
- package/esm/components/data-grid/data-grid.d.ts +5 -2
- package/esm/components/data-grid/data-grid.d.ts.map +1 -1
- package/esm/components/data-grid/data-grid.js +5 -3
- package/esm/components/data-grid/data-grid.js.map +1 -1
- package/esm/components/data-grid/data-grid.spec.js +60 -60
- package/esm/components/data-grid/data-grid.spec.js.map +1 -1
- package/esm/components/data-grid/filters/boolean-filter.d.ts +2 -2
- package/esm/components/data-grid/filters/boolean-filter.d.ts.map +1 -1
- package/esm/components/data-grid/filters/boolean-filter.js +4 -4
- package/esm/components/data-grid/filters/boolean-filter.js.map +1 -1
- package/esm/components/data-grid/filters/boolean-filter.spec.js +18 -17
- package/esm/components/data-grid/filters/boolean-filter.spec.js.map +1 -1
- package/esm/components/data-grid/filters/date-filter.d.ts +2 -2
- package/esm/components/data-grid/filters/date-filter.d.ts.map +1 -1
- package/esm/components/data-grid/filters/date-filter.js +6 -6
- package/esm/components/data-grid/filters/date-filter.js.map +1 -1
- package/esm/components/data-grid/filters/date-filter.spec.js +26 -21
- package/esm/components/data-grid/filters/date-filter.spec.js.map +1 -1
- package/esm/components/data-grid/filters/enum-filter.d.ts +2 -2
- package/esm/components/data-grid/filters/enum-filter.d.ts.map +1 -1
- package/esm/components/data-grid/filters/enum-filter.js +5 -5
- package/esm/components/data-grid/filters/enum-filter.js.map +1 -1
- package/esm/components/data-grid/filters/enum-filter.spec.js +21 -19
- package/esm/components/data-grid/filters/enum-filter.spec.js.map +1 -1
- package/esm/components/data-grid/filters/filter-dropdown.js +1 -1
- package/esm/components/data-grid/filters/filter-dropdown.js.map +1 -1
- package/esm/components/data-grid/filters/number-filter.d.ts +2 -2
- package/esm/components/data-grid/filters/number-filter.d.ts.map +1 -1
- package/esm/components/data-grid/filters/number-filter.js +5 -5
- package/esm/components/data-grid/filters/number-filter.js.map +1 -1
- package/esm/components/data-grid/filters/number-filter.spec.js +23 -21
- package/esm/components/data-grid/filters/number-filter.spec.js.map +1 -1
- package/esm/components/data-grid/filters/string-filter.d.ts +2 -2
- package/esm/components/data-grid/filters/string-filter.d.ts.map +1 -1
- package/esm/components/data-grid/filters/string-filter.js +5 -5
- package/esm/components/data-grid/filters/string-filter.js.map +1 -1
- package/esm/components/data-grid/filters/string-filter.spec.js +21 -19
- package/esm/components/data-grid/filters/string-filter.spec.js.map +1 -1
- package/esm/components/data-grid/footer.d.ts +2 -2
- package/esm/components/data-grid/footer.d.ts.map +1 -1
- package/esm/components/data-grid/footer.js +8 -13
- package/esm/components/data-grid/footer.js.map +1 -1
- package/esm/components/data-grid/footer.spec.js +38 -27
- package/esm/components/data-grid/footer.spec.js.map +1 -1
- package/esm/components/data-grid/header.d.ts +6 -6
- package/esm/components/data-grid/header.d.ts.map +1 -1
- package/esm/components/data-grid/header.js +16 -17
- package/esm/components/data-grid/header.js.map +1 -1
- package/esm/components/data-grid/header.spec.js +66 -60
- package/esm/components/data-grid/header.spec.js.map +1 -1
- package/esm/components/data-grid/selection-cell.js +1 -1
- package/esm/components/data-grid/selection-cell.js.map +1 -1
- package/esm/components/dialog.js +1 -1
- package/esm/components/dialog.js.map +1 -1
- package/esm/components/divider.js +1 -1
- package/esm/components/divider.js.map +1 -1
- package/esm/components/drawer/drawer-toggle-button.js +1 -1
- package/esm/components/drawer/drawer-toggle-button.js.map +1 -1
- package/esm/components/drawer/index.js +1 -1
- package/esm/components/drawer/index.js.map +1 -1
- package/esm/components/dropdown.js +1 -1
- package/esm/components/dropdown.js.map +1 -1
- package/esm/components/fab.js +1 -1
- package/esm/components/fab.js.map +1 -1
- package/esm/components/form.js +1 -1
- package/esm/components/form.js.map +1 -1
- package/esm/components/grid.js +1 -1
- package/esm/components/grid.js.map +1 -1
- package/esm/components/icons/icon.js +1 -1
- package/esm/components/icons/icon.js.map +1 -1
- package/esm/components/image.js +2 -2
- package/esm/components/image.js.map +1 -1
- package/esm/components/inputs/autocomplete.js +1 -1
- package/esm/components/inputs/autocomplete.js.map +1 -1
- package/esm/components/inputs/checkbox.js +1 -1
- package/esm/components/inputs/checkbox.js.map +1 -1
- package/esm/components/inputs/checkbox.spec.js +1 -1
- package/esm/components/inputs/checkbox.spec.js.map +1 -1
- package/esm/components/inputs/input-number.js +1 -1
- package/esm/components/inputs/input-number.js.map +1 -1
- package/esm/components/inputs/input-number.spec.js +1 -1
- package/esm/components/inputs/input-number.spec.js.map +1 -1
- package/esm/components/inputs/input.js +1 -1
- package/esm/components/inputs/input.js.map +1 -1
- package/esm/components/inputs/input.spec.js +1 -1
- package/esm/components/inputs/input.spec.js.map +1 -1
- package/esm/components/inputs/radio-group.js +1 -1
- package/esm/components/inputs/radio-group.js.map +1 -1
- package/esm/components/inputs/radio-group.spec.js +1 -1
- package/esm/components/inputs/radio-group.spec.js.map +1 -1
- package/esm/components/inputs/radio.js +1 -1
- package/esm/components/inputs/radio.js.map +1 -1
- package/esm/components/inputs/radio.spec.js +1 -1
- package/esm/components/inputs/radio.spec.js.map +1 -1
- package/esm/components/inputs/select.js +1 -1
- package/esm/components/inputs/select.js.map +1 -1
- package/esm/components/inputs/slider.js +1 -1
- package/esm/components/inputs/slider.js.map +1 -1
- package/esm/components/inputs/switch.js +1 -1
- package/esm/components/inputs/switch.js.map +1 -1
- package/esm/components/inputs/switch.spec.js +1 -1
- package/esm/components/inputs/switch.spec.js.map +1 -1
- package/esm/components/inputs/text-area.js +1 -1
- package/esm/components/inputs/text-area.js.map +1 -1
- package/esm/components/inputs/text-area.spec.js +1 -1
- package/esm/components/inputs/text-area.spec.js.map +1 -1
- package/esm/components/linear-progress.d.ts +2 -4
- package/esm/components/linear-progress.d.ts.map +1 -1
- package/esm/components/linear-progress.js +3 -6
- package/esm/components/linear-progress.js.map +1 -1
- package/esm/components/linear-progress.spec.js +21 -18
- package/esm/components/linear-progress.spec.js.map +1 -1
- package/esm/components/list/list-item.js +1 -1
- package/esm/components/list/list-item.js.map +1 -1
- package/esm/components/list/list.js +1 -1
- package/esm/components/list/list.js.map +1 -1
- package/esm/components/loader.js +1 -1
- package/esm/components/loader.js.map +1 -1
- package/esm/components/loader.spec.js +1 -1
- package/esm/components/loader.spec.js.map +1 -1
- package/esm/components/markdown/markdown-display.js +1 -1
- package/esm/components/markdown/markdown-display.js.map +1 -1
- package/esm/components/markdown/markdown-display.spec.js +1 -1
- package/esm/components/markdown/markdown-display.spec.js.map +1 -1
- package/esm/components/markdown/markdown-editor.js +1 -1
- package/esm/components/markdown/markdown-editor.js.map +1 -1
- package/esm/components/markdown/markdown-editor.spec.js +1 -1
- package/esm/components/markdown/markdown-editor.spec.js.map +1 -1
- package/esm/components/markdown/markdown-input.js +1 -1
- package/esm/components/markdown/markdown-input.js.map +1 -1
- package/esm/components/markdown/markdown-input.spec.js +1 -1
- package/esm/components/markdown/markdown-input.spec.js.map +1 -1
- package/esm/components/menu/menu.js +1 -1
- package/esm/components/menu/menu.js.map +1 -1
- package/esm/components/modal.js +1 -1
- package/esm/components/modal.js.map +1 -1
- package/esm/components/modal.spec.js +3 -3
- package/esm/components/modal.spec.js.map +1 -1
- package/esm/components/noty-list.js +2 -2
- package/esm/components/noty-list.js.map +1 -1
- package/esm/components/page-container/index.js +1 -1
- package/esm/components/page-container/index.js.map +1 -1
- package/esm/components/page-container/page-header.js +1 -1
- package/esm/components/page-container/page-header.js.map +1 -1
- package/esm/components/page-layout/index.js +1 -1
- package/esm/components/page-layout/index.js.map +1 -1
- package/esm/components/pagination.js +1 -1
- package/esm/components/pagination.js.map +1 -1
- package/esm/components/paper.js +1 -1
- package/esm/components/paper.js.map +1 -1
- package/esm/components/rating.js +1 -1
- package/esm/components/rating.js.map +1 -1
- package/esm/components/rating.spec.js +1 -1
- package/esm/components/rating.spec.js.map +1 -1
- package/esm/components/result.js +1 -1
- package/esm/components/result.js.map +1 -1
- package/esm/components/skeleton.js +1 -1
- package/esm/components/skeleton.js.map +1 -1
- package/esm/components/suggest/index.js +1 -1
- package/esm/components/suggest/index.js.map +1 -1
- package/esm/components/suggest/index.spec.js +1 -1
- package/esm/components/suggest/index.spec.js.map +1 -1
- package/esm/components/suggest/suggest-input.js +1 -1
- package/esm/components/suggest/suggest-input.js.map +1 -1
- package/esm/components/suggest/suggest-input.spec.js +1 -1
- package/esm/components/suggest/suggest-input.spec.js.map +1 -1
- package/esm/components/suggest/suggestion-list.js +1 -1
- package/esm/components/suggest/suggestion-list.js.map +1 -1
- package/esm/components/suggest/suggestion-list.spec.js +1 -1
- package/esm/components/suggest/suggestion-list.spec.js.map +1 -1
- package/esm/components/tabs.js +2 -2
- package/esm/components/tabs.js.map +1 -1
- package/esm/components/timeline.js +2 -2
- package/esm/components/timeline.js.map +1 -1
- package/esm/components/tooltip.js +1 -1
- package/esm/components/tooltip.js.map +1 -1
- package/esm/components/tree/tree-item.js +1 -1
- package/esm/components/tree/tree-item.js.map +1 -1
- package/esm/components/tree/tree.js +1 -1
- package/esm/components/tree/tree.js.map +1 -1
- package/esm/components/typography.js +1 -1
- package/esm/components/typography.js.map +1 -1
- package/esm/components/wizard/index.js +1 -1
- package/esm/components/wizard/index.js.map +1 -1
- package/esm/components/wizard/index.spec.js +3 -3
- package/esm/components/wizard/index.spec.js.map +1 -1
- package/package.json +3 -3
- package/src/components/accordion/accordion-item.tsx +1 -1
- package/src/components/accordion/accordion.tsx +1 -1
- package/src/components/alert.tsx +1 -1
- package/src/components/app-bar-link.tsx +1 -1
- package/src/components/app-bar.tsx +1 -1
- package/src/components/avatar.tsx +1 -1
- package/src/components/badge.tsx +1 -1
- package/src/components/breadcrumb.spec.tsx +3 -3
- package/src/components/breadcrumb.tsx +1 -1
- package/src/components/button-group.tsx +4 -4
- package/src/components/button.spec.tsx +1 -1
- package/src/components/button.tsx +1 -1
- package/src/components/cache-view.spec.tsx +2 -2
- package/src/components/cache-view.tsx +3 -3
- package/src/components/card.tsx +5 -5
- package/src/components/carousel.tsx +1 -1
- package/src/components/chip.tsx +1 -1
- package/src/components/circular-progress.spec.tsx +20 -14
- package/src/components/circular-progress.tsx +5 -11
- package/src/components/command-palette/command-palette-input.tsx +1 -1
- package/src/components/command-palette/command-palette-suggestion-list.spec.tsx +1 -1
- package/src/components/command-palette/command-palette-suggestion-list.tsx +1 -1
- package/src/components/command-palette/index.tsx +1 -1
- package/src/components/context-menu/context-menu-item.tsx +1 -1
- package/src/components/context-menu/context-menu.tsx +1 -1
- package/src/components/data-grid/body.tsx +1 -1
- package/src/components/data-grid/data-grid-row.tsx +1 -1
- package/src/components/data-grid/data-grid.spec.tsx +62 -36
- package/src/components/data-grid/data-grid.tsx +14 -8
- package/src/components/data-grid/filters/boolean-filter.spec.tsx +29 -18
- package/src/components/data-grid/filters/boolean-filter.tsx +6 -6
- package/src/components/data-grid/filters/date-filter.spec.tsx +35 -22
- package/src/components/data-grid/filters/date-filter.tsx +8 -8
- package/src/components/data-grid/filters/enum-filter.spec.tsx +35 -20
- package/src/components/data-grid/filters/enum-filter.tsx +7 -7
- package/src/components/data-grid/filters/filter-dropdown.tsx +1 -1
- package/src/components/data-grid/filters/number-filter.spec.tsx +32 -22
- package/src/components/data-grid/filters/number-filter.tsx +7 -7
- package/src/components/data-grid/filters/string-filter.spec.tsx +32 -20
- package/src/components/data-grid/filters/string-filter.tsx +7 -7
- package/src/components/data-grid/footer.spec.tsx +79 -31
- package/src/components/data-grid/footer.tsx +10 -15
- package/src/components/data-grid/header.spec.tsx +152 -68
- package/src/components/data-grid/header.tsx +64 -27
- package/src/components/data-grid/selection-cell.tsx +1 -1
- package/src/components/dialog.tsx +1 -1
- package/src/components/divider.tsx +1 -1
- package/src/components/drawer/drawer-toggle-button.tsx +1 -1
- package/src/components/drawer/index.tsx +1 -1
- package/src/components/dropdown.tsx +1 -1
- package/src/components/fab.tsx +1 -1
- package/src/components/form.tsx +1 -1
- package/src/components/grid.tsx +1 -1
- package/src/components/icons/icon.tsx +1 -1
- package/src/components/image.tsx +2 -2
- package/src/components/inputs/autocomplete.tsx +1 -1
- package/src/components/inputs/checkbox.spec.tsx +1 -1
- package/src/components/inputs/checkbox.tsx +1 -1
- package/src/components/inputs/input-number.spec.tsx +1 -1
- package/src/components/inputs/input-number.tsx +1 -1
- package/src/components/inputs/input.spec.tsx +1 -1
- package/src/components/inputs/input.tsx +1 -1
- package/src/components/inputs/radio-group.spec.tsx +1 -1
- package/src/components/inputs/radio-group.tsx +1 -1
- package/src/components/inputs/radio.spec.tsx +1 -1
- package/src/components/inputs/radio.tsx +1 -1
- package/src/components/inputs/select.tsx +1 -1
- package/src/components/inputs/slider.tsx +1 -1
- package/src/components/inputs/switch.spec.tsx +1 -1
- package/src/components/inputs/switch.tsx +1 -1
- package/src/components/inputs/text-area.spec.tsx +1 -1
- package/src/components/inputs/text-area.tsx +1 -1
- package/src/components/linear-progress.spec.tsx +22 -18
- package/src/components/linear-progress.tsx +5 -11
- package/src/components/list/list-item.tsx +1 -1
- package/src/components/list/list.tsx +1 -1
- package/src/components/loader.spec.tsx +1 -1
- package/src/components/loader.tsx +1 -1
- package/src/components/markdown/markdown-display.spec.tsx +1 -1
- package/src/components/markdown/markdown-display.tsx +1 -1
- package/src/components/markdown/markdown-editor.spec.tsx +1 -1
- package/src/components/markdown/markdown-editor.tsx +1 -1
- package/src/components/markdown/markdown-input.spec.tsx +1 -1
- package/src/components/markdown/markdown-input.tsx +1 -1
- package/src/components/menu/menu.tsx +1 -1
- package/src/components/modal.spec.tsx +3 -3
- package/src/components/modal.tsx +1 -1
- package/src/components/noty-list.tsx +2 -2
- package/src/components/page-container/index.tsx +1 -1
- package/src/components/page-container/page-header.tsx +1 -1
- package/src/components/page-layout/index.tsx +1 -1
- package/src/components/pagination.tsx +1 -1
- package/src/components/paper.tsx +1 -1
- package/src/components/rating.spec.tsx +1 -1
- package/src/components/rating.tsx +1 -1
- package/src/components/result.tsx +1 -1
- package/src/components/skeleton.tsx +1 -1
- package/src/components/suggest/index.spec.tsx +1 -1
- package/src/components/suggest/index.tsx +1 -1
- package/src/components/suggest/suggest-input.spec.tsx +1 -1
- package/src/components/suggest/suggest-input.tsx +1 -1
- package/src/components/suggest/suggestion-list.spec.tsx +1 -1
- package/src/components/suggest/suggestion-list.tsx +1 -1
- package/src/components/tabs.tsx +2 -2
- package/src/components/timeline.tsx +2 -2
- package/src/components/tooltip.tsx +1 -1
- package/src/components/tree/tree-item.tsx +1 -1
- package/src/components/tree/tree.tsx +1 -1
- package/src/components/typography.tsx +1 -1
- package/src/components/wizard/index.spec.tsx +3 -3
- package/src/components/wizard/index.tsx +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Injector } from '@furystack/inject'
|
|
2
2
|
import { createComponent, flushUpdates, initializeShadeRoot } from '@furystack/shades'
|
|
3
|
-
import {
|
|
3
|
+
import { usingAsync } from '@furystack/utils'
|
|
4
4
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
5
5
|
import type { FilterableFindOptions } from '../data-grid.js'
|
|
6
6
|
import { BooleanFilter } from './boolean-filter.js'
|
|
@@ -14,24 +14,32 @@ describe('BooleanFilter', () => {
|
|
|
14
14
|
document.body.innerHTML = ''
|
|
15
15
|
})
|
|
16
16
|
|
|
17
|
-
const createFindOptions = (options: Partial<FilterableFindOptions> = {}):
|
|
18
|
-
return
|
|
17
|
+
const createFindOptions = (options: Partial<FilterableFindOptions> = {}): FilterableFindOptions => {
|
|
18
|
+
return options as FilterableFindOptions
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
const renderBooleanFilter = async (
|
|
22
|
-
findOptions:
|
|
22
|
+
findOptions: FilterableFindOptions,
|
|
23
23
|
field = 'isActive',
|
|
24
24
|
onClose = vi.fn(),
|
|
25
|
+
onFindOptionsChange = vi.fn(),
|
|
25
26
|
) => {
|
|
26
27
|
const injector = new Injector()
|
|
27
28
|
const rootElement = document.getElementById('root')!
|
|
28
29
|
initializeShadeRoot({
|
|
29
30
|
injector,
|
|
30
31
|
rootElement,
|
|
31
|
-
jsxElement:
|
|
32
|
+
jsxElement: (
|
|
33
|
+
<BooleanFilter
|
|
34
|
+
field={field}
|
|
35
|
+
findOptions={findOptions}
|
|
36
|
+
onFindOptionsChange={onFindOptionsChange}
|
|
37
|
+
onClose={onClose}
|
|
38
|
+
/>
|
|
39
|
+
),
|
|
32
40
|
})
|
|
33
41
|
await flushUpdates()
|
|
34
|
-
return { injector, onClose }
|
|
42
|
+
return { injector, onClose, onFindOptionsChange }
|
|
35
43
|
}
|
|
36
44
|
|
|
37
45
|
it('should render three options: True, False, Any', async () => {
|
|
@@ -70,7 +78,7 @@ describe('BooleanFilter', () => {
|
|
|
70
78
|
|
|
71
79
|
it('should set filter to $eq: true when "True" is clicked', async () => {
|
|
72
80
|
const findOptions = createFindOptions()
|
|
73
|
-
const { injector, onClose } = await renderBooleanFilter(findOptions)
|
|
81
|
+
const { injector, onClose, onFindOptionsChange } = await renderBooleanFilter(findOptions)
|
|
74
82
|
await usingAsync(injector, async () => {
|
|
75
83
|
const trueButton = document.querySelector(
|
|
76
84
|
'shade-segmented-control button[data-value="true"]',
|
|
@@ -78,14 +86,14 @@ describe('BooleanFilter', () => {
|
|
|
78
86
|
trueButton?.click()
|
|
79
87
|
await flushUpdates()
|
|
80
88
|
|
|
81
|
-
expect(
|
|
89
|
+
expect(onFindOptionsChange).toHaveBeenCalledWith(expect.objectContaining({ filter: { isActive: { $eq: true } } }))
|
|
82
90
|
expect(onClose).toHaveBeenCalled()
|
|
83
91
|
})
|
|
84
92
|
})
|
|
85
93
|
|
|
86
94
|
it('should set filter to $eq: false when "False" is clicked', async () => {
|
|
87
95
|
const findOptions = createFindOptions()
|
|
88
|
-
const { injector, onClose } = await renderBooleanFilter(findOptions)
|
|
96
|
+
const { injector, onClose, onFindOptionsChange } = await renderBooleanFilter(findOptions)
|
|
89
97
|
await usingAsync(injector, async () => {
|
|
90
98
|
const falseButton = document.querySelector(
|
|
91
99
|
'shade-segmented-control button[data-value="false"]',
|
|
@@ -93,42 +101,45 @@ describe('BooleanFilter', () => {
|
|
|
93
101
|
falseButton?.click()
|
|
94
102
|
await flushUpdates()
|
|
95
103
|
|
|
96
|
-
expect(
|
|
104
|
+
expect(onFindOptionsChange).toHaveBeenCalledWith(
|
|
105
|
+
expect.objectContaining({ filter: { isActive: { $eq: false } } }),
|
|
106
|
+
)
|
|
97
107
|
expect(onClose).toHaveBeenCalled()
|
|
98
108
|
})
|
|
99
109
|
})
|
|
100
110
|
|
|
101
111
|
it('should remove filter when "Any" is clicked', async () => {
|
|
102
112
|
const findOptions = createFindOptions({ filter: { isActive: { $eq: true } } })
|
|
103
|
-
const { injector, onClose } = await renderBooleanFilter(findOptions)
|
|
113
|
+
const { injector, onClose, onFindOptionsChange } = await renderBooleanFilter(findOptions)
|
|
104
114
|
await usingAsync(injector, async () => {
|
|
105
115
|
const anyButton = document.querySelector('shade-segmented-control button[data-value="any"]') as HTMLButtonElement
|
|
106
116
|
anyButton?.click()
|
|
107
117
|
await flushUpdates()
|
|
108
118
|
|
|
109
|
-
|
|
119
|
+
const updatedOptions = onFindOptionsChange.mock.lastCall?.[0] as FilterableFindOptions
|
|
120
|
+
expect(updatedOptions.filter?.isActive).toBeUndefined()
|
|
110
121
|
expect(onClose).toHaveBeenCalled()
|
|
111
122
|
})
|
|
112
123
|
})
|
|
113
124
|
|
|
114
125
|
it('should preserve filters on other fields', async () => {
|
|
115
126
|
const findOptions = createFindOptions({ filter: { isActive: { $eq: true }, name: { $regex: 'test' } } })
|
|
116
|
-
const { injector, onClose } = await renderBooleanFilter(findOptions)
|
|
127
|
+
const { injector, onClose, onFindOptionsChange } = await renderBooleanFilter(findOptions)
|
|
117
128
|
await usingAsync(injector, async () => {
|
|
118
129
|
const anyButton = document.querySelector('shade-segmented-control button[data-value="any"]') as HTMLButtonElement
|
|
119
130
|
anyButton?.click()
|
|
120
131
|
await flushUpdates()
|
|
121
132
|
|
|
122
|
-
const
|
|
123
|
-
expect(
|
|
124
|
-
expect(
|
|
133
|
+
const updatedOptions = onFindOptionsChange.mock.lastCall?.[0] as FilterableFindOptions
|
|
134
|
+
expect(updatedOptions.filter?.isActive).toBeUndefined()
|
|
135
|
+
expect(updatedOptions.filter?.name).toEqual({ $regex: 'test' })
|
|
125
136
|
expect(onClose).toHaveBeenCalled()
|
|
126
137
|
})
|
|
127
138
|
})
|
|
128
139
|
|
|
129
140
|
it('should reset skip to 0 when applying filter', async () => {
|
|
130
141
|
const findOptions = createFindOptions({ skip: 20 })
|
|
131
|
-
const { injector } = await renderBooleanFilter(findOptions)
|
|
142
|
+
const { injector, onFindOptionsChange } = await renderBooleanFilter(findOptions)
|
|
132
143
|
await usingAsync(injector, async () => {
|
|
133
144
|
const trueButton = document.querySelector(
|
|
134
145
|
'shade-segmented-control button[data-value="true"]',
|
|
@@ -136,7 +147,7 @@ describe('BooleanFilter', () => {
|
|
|
136
147
|
trueButton?.click()
|
|
137
148
|
await flushUpdates()
|
|
138
149
|
|
|
139
|
-
expect(
|
|
150
|
+
expect(onFindOptionsChange).toHaveBeenCalledWith(expect.objectContaining({ skip: 0 }))
|
|
140
151
|
})
|
|
141
152
|
})
|
|
142
153
|
})
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { createComponent, Shade } from '@furystack/shades'
|
|
2
|
-
import type { ObservableValue } from '@furystack/utils'
|
|
3
2
|
import { SegmentedControl } from '../../button-group.js'
|
|
4
3
|
import { cssVariableTheme } from '../../../services/css-variable-theme.js'
|
|
5
4
|
import type { FilterableFindOptions } from '../data-grid.js'
|
|
@@ -8,13 +7,14 @@ type BooleanFilterValue = 'true' | 'false' | 'any'
|
|
|
8
7
|
|
|
9
8
|
export const BooleanFilter = Shade<{
|
|
10
9
|
field: string
|
|
11
|
-
findOptions:
|
|
10
|
+
findOptions: FilterableFindOptions
|
|
11
|
+
onFindOptionsChange: (options: FilterableFindOptions) => void
|
|
12
12
|
onClose: () => void
|
|
13
13
|
}>({
|
|
14
|
-
|
|
14
|
+
customElementName: 'data-grid-boolean-filter',
|
|
15
15
|
css: { fontFamily: cssVariableTheme.typography.fontFamily },
|
|
16
|
-
render: ({ props
|
|
17
|
-
const
|
|
16
|
+
render: ({ props }) => {
|
|
17
|
+
const { findOptions } = props
|
|
18
18
|
|
|
19
19
|
const currentFilter = findOptions.filter?.[props.field] as { $eq?: boolean } | undefined
|
|
20
20
|
const currentValue: BooleanFilterValue =
|
|
@@ -27,7 +27,7 @@ export const BooleanFilter = Shade<{
|
|
|
27
27
|
} else {
|
|
28
28
|
filter[props.field] = { $eq: value === 'true' }
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
props.onFindOptionsChange({ ...findOptions, filter, skip: 0 })
|
|
31
31
|
props.onClose()
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Injector } from '@furystack/inject'
|
|
2
2
|
import { createComponent, flushUpdates, initializeShadeRoot } from '@furystack/shades'
|
|
3
|
-
import {
|
|
3
|
+
import { usingAsync } from '@furystack/utils'
|
|
4
4
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
5
5
|
import type { FilterableFindOptions } from '../data-grid.js'
|
|
6
6
|
import { DateFilter } from './date-filter.js'
|
|
@@ -14,24 +14,32 @@ describe('DateFilter', () => {
|
|
|
14
14
|
document.body.innerHTML = ''
|
|
15
15
|
})
|
|
16
16
|
|
|
17
|
-
const createFindOptions = (options: Partial<FilterableFindOptions> = {}):
|
|
18
|
-
return
|
|
17
|
+
const createFindOptions = (options: Partial<FilterableFindOptions> = {}): FilterableFindOptions => {
|
|
18
|
+
return options as FilterableFindOptions
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
const renderDateFilter = async (
|
|
22
|
-
findOptions:
|
|
22
|
+
findOptions: FilterableFindOptions,
|
|
23
23
|
field = 'createdAt',
|
|
24
24
|
onClose = vi.fn(),
|
|
25
|
+
onFindOptionsChange = vi.fn(),
|
|
25
26
|
) => {
|
|
26
27
|
const injector = new Injector()
|
|
27
28
|
const rootElement = document.getElementById('root')!
|
|
28
29
|
initializeShadeRoot({
|
|
29
30
|
injector,
|
|
30
31
|
rootElement,
|
|
31
|
-
jsxElement:
|
|
32
|
+
jsxElement: (
|
|
33
|
+
<DateFilter
|
|
34
|
+
field={field}
|
|
35
|
+
findOptions={findOptions}
|
|
36
|
+
onFindOptionsChange={onFindOptionsChange}
|
|
37
|
+
onClose={onClose}
|
|
38
|
+
/>
|
|
39
|
+
),
|
|
32
40
|
})
|
|
33
41
|
await flushUpdates()
|
|
34
|
-
return { injector, onClose }
|
|
42
|
+
return { injector, onClose, onFindOptionsChange }
|
|
35
43
|
}
|
|
36
44
|
|
|
37
45
|
it('should render mode segmented control and date input', async () => {
|
|
@@ -47,7 +55,7 @@ describe('DateFilter', () => {
|
|
|
47
55
|
|
|
48
56
|
it('should apply "before" filter on submit', async () => {
|
|
49
57
|
const findOptions = createFindOptions()
|
|
50
|
-
const { injector, onClose } = await renderDateFilter(findOptions)
|
|
58
|
+
const { injector, onClose, onFindOptionsChange } = await renderDateFilter(findOptions)
|
|
51
59
|
await usingAsync(injector, async () => {
|
|
52
60
|
const input = document.querySelector('[data-testid="date-filter-value"]') as HTMLInputElement
|
|
53
61
|
input.value = '2025-06-15T10:30'
|
|
@@ -57,7 +65,8 @@ describe('DateFilter', () => {
|
|
|
57
65
|
form.dispatchEvent(new Event('submit', { bubbles: true }))
|
|
58
66
|
await flushUpdates()
|
|
59
67
|
|
|
60
|
-
const
|
|
68
|
+
const updatedOptions = onFindOptionsChange.mock.lastCall?.[0] as FilterableFindOptions
|
|
69
|
+
const filter = updatedOptions.filter?.createdAt as Record<string, Date>
|
|
61
70
|
expect(filter.$lt).toBeInstanceOf(Date)
|
|
62
71
|
expect(filter.$lt.toISOString()).toBe(new Date('2025-06-15T10:30').toISOString())
|
|
63
72
|
expect(onClose).toHaveBeenCalled()
|
|
@@ -66,7 +75,7 @@ describe('DateFilter', () => {
|
|
|
66
75
|
|
|
67
76
|
it('should apply "after" filter when mode is changed', async () => {
|
|
68
77
|
const findOptions = createFindOptions()
|
|
69
|
-
const { injector, onClose } = await renderDateFilter(findOptions)
|
|
78
|
+
const { injector, onClose, onFindOptionsChange } = await renderDateFilter(findOptions)
|
|
70
79
|
await usingAsync(injector, async () => {
|
|
71
80
|
const afterButton = document.querySelector(
|
|
72
81
|
'shade-segmented-control button[data-value="after"]',
|
|
@@ -82,7 +91,8 @@ describe('DateFilter', () => {
|
|
|
82
91
|
form.dispatchEvent(new Event('submit', { bubbles: true }))
|
|
83
92
|
await flushUpdates()
|
|
84
93
|
|
|
85
|
-
const
|
|
94
|
+
const updatedOptions = onFindOptionsChange.mock.lastCall?.[0] as FilterableFindOptions
|
|
95
|
+
const filter = updatedOptions.filter?.createdAt as Record<string, Date>
|
|
86
96
|
expect(filter.$gt).toBeInstanceOf(Date)
|
|
87
97
|
expect(onClose).toHaveBeenCalled()
|
|
88
98
|
})
|
|
@@ -90,7 +100,7 @@ describe('DateFilter', () => {
|
|
|
90
100
|
|
|
91
101
|
it('should apply "between" filter with both dates', async () => {
|
|
92
102
|
const findOptions = createFindOptions()
|
|
93
|
-
const { injector, onClose } = await renderDateFilter(findOptions)
|
|
103
|
+
const { injector, onClose, onFindOptionsChange } = await renderDateFilter(findOptions)
|
|
94
104
|
await usingAsync(injector, async () => {
|
|
95
105
|
const betweenButton = document.querySelector(
|
|
96
106
|
'shade-segmented-control button[data-value="between"]',
|
|
@@ -110,7 +120,8 @@ describe('DateFilter', () => {
|
|
|
110
120
|
form.dispatchEvent(new Event('submit', { bubbles: true }))
|
|
111
121
|
await flushUpdates()
|
|
112
122
|
|
|
113
|
-
const
|
|
123
|
+
const updatedOptions = onFindOptionsChange.mock.lastCall?.[0] as FilterableFindOptions
|
|
124
|
+
const filter = updatedOptions.filter?.createdAt as Record<string, Date>
|
|
114
125
|
expect(filter.$gte).toBeInstanceOf(Date)
|
|
115
126
|
expect(filter.$lte).toBeInstanceOf(Date)
|
|
116
127
|
expect(onClose).toHaveBeenCalled()
|
|
@@ -119,20 +130,21 @@ describe('DateFilter', () => {
|
|
|
119
130
|
|
|
120
131
|
it('should clear filter when Clear button is clicked', async () => {
|
|
121
132
|
const findOptions = createFindOptions({ filter: { createdAt: { $lt: new Date() } } })
|
|
122
|
-
const { injector, onClose } = await renderDateFilter(findOptions)
|
|
133
|
+
const { injector, onClose, onFindOptionsChange } = await renderDateFilter(findOptions)
|
|
123
134
|
await usingAsync(injector, async () => {
|
|
124
135
|
const clearButton = Array.from(document.querySelectorAll('button')).find((b) => b.textContent?.trim() === 'Clear')
|
|
125
136
|
clearButton?.click()
|
|
126
137
|
await flushUpdates()
|
|
127
138
|
|
|
128
|
-
|
|
139
|
+
const updatedOptions = onFindOptionsChange.mock.lastCall?.[0] as FilterableFindOptions
|
|
140
|
+
expect(updatedOptions.filter?.createdAt).toBeUndefined()
|
|
129
141
|
expect(onClose).toHaveBeenCalled()
|
|
130
142
|
})
|
|
131
143
|
})
|
|
132
144
|
|
|
133
145
|
it('should remove filter when submitting empty date', async () => {
|
|
134
146
|
const findOptions = createFindOptions({ filter: { createdAt: { $lt: new Date() } } })
|
|
135
|
-
const { injector, onClose } = await renderDateFilter(findOptions)
|
|
147
|
+
const { injector, onClose, onFindOptionsChange } = await renderDateFilter(findOptions)
|
|
136
148
|
await usingAsync(injector, async () => {
|
|
137
149
|
const input = document.querySelector('[data-testid="date-filter-value"]') as HTMLInputElement
|
|
138
150
|
input.value = ''
|
|
@@ -142,7 +154,8 @@ describe('DateFilter', () => {
|
|
|
142
154
|
form.dispatchEvent(new Event('submit', { bubbles: true }))
|
|
143
155
|
await flushUpdates()
|
|
144
156
|
|
|
145
|
-
|
|
157
|
+
const updatedOptions = onFindOptionsChange.mock.lastCall?.[0] as FilterableFindOptions
|
|
158
|
+
expect(updatedOptions.filter?.createdAt).toBeUndefined()
|
|
146
159
|
expect(onClose).toHaveBeenCalled()
|
|
147
160
|
})
|
|
148
161
|
})
|
|
@@ -151,21 +164,21 @@ describe('DateFilter', () => {
|
|
|
151
164
|
const findOptions = createFindOptions({
|
|
152
165
|
filter: { createdAt: { $lt: new Date() }, name: { $regex: 'keep' } },
|
|
153
166
|
})
|
|
154
|
-
const { injector } = await renderDateFilter(findOptions)
|
|
167
|
+
const { injector, onFindOptionsChange } = await renderDateFilter(findOptions)
|
|
155
168
|
await usingAsync(injector, async () => {
|
|
156
169
|
const clearButton = Array.from(document.querySelectorAll('button')).find((b) => b.textContent?.trim() === 'Clear')
|
|
157
170
|
clearButton?.click()
|
|
158
171
|
await flushUpdates()
|
|
159
172
|
|
|
160
|
-
const
|
|
161
|
-
expect(
|
|
162
|
-
expect(
|
|
173
|
+
const updatedOptions = onFindOptionsChange.mock.lastCall?.[0] as FilterableFindOptions
|
|
174
|
+
expect(updatedOptions.filter?.createdAt).toBeUndefined()
|
|
175
|
+
expect(updatedOptions.filter?.name).toEqual({ $regex: 'keep' })
|
|
163
176
|
})
|
|
164
177
|
})
|
|
165
178
|
|
|
166
179
|
it('should reset skip to 0 when applying filter', async () => {
|
|
167
180
|
const findOptions = createFindOptions({ skip: 20 })
|
|
168
|
-
const { injector } = await renderDateFilter(findOptions)
|
|
181
|
+
const { injector, onFindOptionsChange } = await renderDateFilter(findOptions)
|
|
169
182
|
await usingAsync(injector, async () => {
|
|
170
183
|
const input = document.querySelector('[data-testid="date-filter-value"]') as HTMLInputElement
|
|
171
184
|
input.value = '2025-06-15T10:30'
|
|
@@ -175,7 +188,7 @@ describe('DateFilter', () => {
|
|
|
175
188
|
form.dispatchEvent(new Event('submit', { bubbles: true }))
|
|
176
189
|
await flushUpdates()
|
|
177
190
|
|
|
178
|
-
expect(
|
|
191
|
+
expect(onFindOptionsChange).toHaveBeenCalledWith(expect.objectContaining({ skip: 0 }))
|
|
179
192
|
})
|
|
180
193
|
})
|
|
181
194
|
})
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { createComponent, Shade } from '@furystack/shades'
|
|
2
|
-
import type { ObservableValue } from '@furystack/utils'
|
|
3
2
|
import { SegmentedControl } from '../../button-group.js'
|
|
4
3
|
import { Button } from '../../button.js'
|
|
5
4
|
import { close as closeIcon, search as searchIcon } from '../../icons/icon-definitions.js'
|
|
@@ -12,17 +11,18 @@ type DateMode = 'before' | 'after' | 'between'
|
|
|
12
11
|
|
|
13
12
|
export const DateFilter = Shade<{
|
|
14
13
|
field: string
|
|
15
|
-
findOptions:
|
|
14
|
+
findOptions: FilterableFindOptions
|
|
15
|
+
onFindOptionsChange: (options: FilterableFindOptions) => void
|
|
16
16
|
onClose: () => void
|
|
17
17
|
}>({
|
|
18
|
-
|
|
18
|
+
customElementName: 'data-grid-date-filter',
|
|
19
19
|
css: {
|
|
20
20
|
...filterBaseCss,
|
|
21
21
|
fontFamily: cssVariableTheme.typography.fontFamily,
|
|
22
22
|
'& input[type="datetime-local"]': filterInputCss,
|
|
23
23
|
},
|
|
24
|
-
render: ({ props,
|
|
25
|
-
const
|
|
24
|
+
render: ({ props, useState }) => {
|
|
25
|
+
const { findOptions } = props
|
|
26
26
|
|
|
27
27
|
const currentFilter = findOptions.filter?.[props.field] as
|
|
28
28
|
| { $lt?: Date; $gt?: Date; $gte?: Date; $lte?: Date }
|
|
@@ -63,7 +63,7 @@ export const DateFilter = Shade<{
|
|
|
63
63
|
const filter = { ...findOptions.filter }
|
|
64
64
|
if (!dateValue) {
|
|
65
65
|
delete filter[props.field]
|
|
66
|
-
|
|
66
|
+
props.onFindOptionsChange({ ...findOptions, filter, skip: 0 })
|
|
67
67
|
props.onClose()
|
|
68
68
|
return
|
|
69
69
|
}
|
|
@@ -87,14 +87,14 @@ export const DateFilter = Shade<{
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
filter[props.field] = filterValue
|
|
90
|
-
|
|
90
|
+
props.onFindOptionsChange({ ...findOptions, filter, skip: 0 })
|
|
91
91
|
props.onClose()
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
const clearFilter = () => {
|
|
95
95
|
const filter = { ...findOptions.filter }
|
|
96
96
|
delete filter[props.field]
|
|
97
|
-
|
|
97
|
+
props.onFindOptionsChange({ ...findOptions, filter, skip: 0 })
|
|
98
98
|
props.onClose()
|
|
99
99
|
}
|
|
100
100
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Injector } from '@furystack/inject'
|
|
2
2
|
import { createComponent, flushUpdates, initializeShadeRoot } from '@furystack/shades'
|
|
3
|
-
import {
|
|
3
|
+
import { usingAsync } from '@furystack/utils'
|
|
4
4
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
5
5
|
import type { FilterableFindOptions } from '../data-grid.js'
|
|
6
6
|
import { EnumFilter } from './enum-filter.js'
|
|
@@ -20,25 +20,34 @@ describe('EnumFilter', () => {
|
|
|
20
20
|
document.body.innerHTML = ''
|
|
21
21
|
})
|
|
22
22
|
|
|
23
|
-
const createFindOptions = (options: Partial<FilterableFindOptions> = {}):
|
|
24
|
-
return
|
|
23
|
+
const createFindOptions = (options: Partial<FilterableFindOptions> = {}): FilterableFindOptions => {
|
|
24
|
+
return options as FilterableFindOptions
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
const renderEnumFilter = async (
|
|
28
|
-
findOptions:
|
|
28
|
+
findOptions: FilterableFindOptions,
|
|
29
29
|
field = 'role',
|
|
30
30
|
values = enumValues,
|
|
31
31
|
onClose = vi.fn(),
|
|
32
|
+
onFindOptionsChange = vi.fn(),
|
|
32
33
|
) => {
|
|
33
34
|
const injector = new Injector()
|
|
34
35
|
const rootElement = document.getElementById('root')!
|
|
35
36
|
initializeShadeRoot({
|
|
36
37
|
injector,
|
|
37
38
|
rootElement,
|
|
38
|
-
jsxElement:
|
|
39
|
+
jsxElement: (
|
|
40
|
+
<EnumFilter
|
|
41
|
+
field={field}
|
|
42
|
+
values={values}
|
|
43
|
+
findOptions={findOptions}
|
|
44
|
+
onFindOptionsChange={onFindOptionsChange}
|
|
45
|
+
onClose={onClose}
|
|
46
|
+
/>
|
|
47
|
+
),
|
|
39
48
|
})
|
|
40
49
|
await flushUpdates()
|
|
41
|
-
return { injector, onClose }
|
|
50
|
+
return { injector, onClose, onFindOptionsChange }
|
|
42
51
|
}
|
|
43
52
|
|
|
44
53
|
it('should render mode control and checkboxes for each value', async () => {
|
|
@@ -54,7 +63,7 @@ describe('EnumFilter', () => {
|
|
|
54
63
|
|
|
55
64
|
it('should apply $in filter when values are selected and Apply is clicked', async () => {
|
|
56
65
|
const findOptions = createFindOptions()
|
|
57
|
-
const { injector, onClose } = await renderEnumFilter(findOptions)
|
|
66
|
+
const { injector, onClose, onFindOptionsChange } = await renderEnumFilter(findOptions)
|
|
58
67
|
await usingAsync(injector, async () => {
|
|
59
68
|
const checkboxes = document.querySelectorAll('shade-checkbox input[type="checkbox"]')
|
|
60
69
|
const adminCheckbox = checkboxes[0] as HTMLInputElement
|
|
@@ -65,14 +74,16 @@ describe('EnumFilter', () => {
|
|
|
65
74
|
applyButton?.click()
|
|
66
75
|
await flushUpdates()
|
|
67
76
|
|
|
68
|
-
expect(
|
|
77
|
+
expect(onFindOptionsChange).toHaveBeenCalledWith(
|
|
78
|
+
expect.objectContaining({ filter: { role: { $in: ['admin'] } } }),
|
|
79
|
+
)
|
|
69
80
|
expect(onClose).toHaveBeenCalled()
|
|
70
81
|
})
|
|
71
82
|
})
|
|
72
83
|
|
|
73
84
|
it('should apply $nin filter when exclude mode is selected', async () => {
|
|
74
85
|
const findOptions = createFindOptions()
|
|
75
|
-
const { injector, onClose } = await renderEnumFilter(findOptions)
|
|
86
|
+
const { injector, onClose, onFindOptionsChange } = await renderEnumFilter(findOptions)
|
|
76
87
|
await usingAsync(injector, async () => {
|
|
77
88
|
const excludeButton = document.querySelector(
|
|
78
89
|
'shade-segmented-control button[data-value="exclude"]',
|
|
@@ -89,14 +100,16 @@ describe('EnumFilter', () => {
|
|
|
89
100
|
applyButton?.click()
|
|
90
101
|
await flushUpdates()
|
|
91
102
|
|
|
92
|
-
expect(
|
|
103
|
+
expect(onFindOptionsChange).toHaveBeenCalledWith(
|
|
104
|
+
expect.objectContaining({ filter: { role: { $nin: ['guest'] } } }),
|
|
105
|
+
)
|
|
93
106
|
expect(onClose).toHaveBeenCalled()
|
|
94
107
|
})
|
|
95
108
|
})
|
|
96
109
|
|
|
97
110
|
it('should remove filter when no values are selected', async () => {
|
|
98
111
|
const findOptions = createFindOptions({ filter: { role: { $in: ['admin'] } } })
|
|
99
|
-
const { injector, onClose } = await renderEnumFilter(findOptions)
|
|
112
|
+
const { injector, onClose, onFindOptionsChange } = await renderEnumFilter(findOptions)
|
|
100
113
|
await usingAsync(injector, async () => {
|
|
101
114
|
const checkboxes = document.querySelectorAll('shade-checkbox input[type="checkbox"]')
|
|
102
115
|
const adminCheckbox = checkboxes[0] as HTMLInputElement
|
|
@@ -107,41 +120,43 @@ describe('EnumFilter', () => {
|
|
|
107
120
|
applyButton?.click()
|
|
108
121
|
await flushUpdates()
|
|
109
122
|
|
|
110
|
-
|
|
123
|
+
const updatedOptions = onFindOptionsChange.mock.lastCall?.[0] as FilterableFindOptions
|
|
124
|
+
expect(updatedOptions.filter?.role).toBeUndefined()
|
|
111
125
|
expect(onClose).toHaveBeenCalled()
|
|
112
126
|
})
|
|
113
127
|
})
|
|
114
128
|
|
|
115
129
|
it('should clear filter when Clear button is clicked', async () => {
|
|
116
130
|
const findOptions = createFindOptions({ filter: { role: { $in: ['admin', 'user'] } } })
|
|
117
|
-
const { injector, onClose } = await renderEnumFilter(findOptions)
|
|
131
|
+
const { injector, onClose, onFindOptionsChange } = await renderEnumFilter(findOptions)
|
|
118
132
|
await usingAsync(injector, async () => {
|
|
119
133
|
const clearButton = Array.from(document.querySelectorAll('button')).find((b) => b.textContent?.trim() === 'Clear')
|
|
120
134
|
clearButton?.click()
|
|
121
135
|
await flushUpdates()
|
|
122
136
|
|
|
123
|
-
|
|
137
|
+
const updatedOptions = onFindOptionsChange.mock.lastCall?.[0] as FilterableFindOptions
|
|
138
|
+
expect(updatedOptions.filter?.role).toBeUndefined()
|
|
124
139
|
expect(onClose).toHaveBeenCalled()
|
|
125
140
|
})
|
|
126
141
|
})
|
|
127
142
|
|
|
128
143
|
it('should preserve filters on other fields', async () => {
|
|
129
144
|
const findOptions = createFindOptions({ filter: { role: { $in: ['admin'] }, name: { $regex: 'keep' } } })
|
|
130
|
-
const { injector } = await renderEnumFilter(findOptions)
|
|
145
|
+
const { injector, onFindOptionsChange } = await renderEnumFilter(findOptions)
|
|
131
146
|
await usingAsync(injector, async () => {
|
|
132
147
|
const clearButton = Array.from(document.querySelectorAll('button')).find((b) => b.textContent?.trim() === 'Clear')
|
|
133
148
|
clearButton?.click()
|
|
134
149
|
await flushUpdates()
|
|
135
150
|
|
|
136
|
-
const
|
|
137
|
-
expect(
|
|
138
|
-
expect(
|
|
151
|
+
const updatedOptions = onFindOptionsChange.mock.lastCall?.[0] as FilterableFindOptions
|
|
152
|
+
expect(updatedOptions.filter?.role).toBeUndefined()
|
|
153
|
+
expect(updatedOptions.filter?.name).toEqual({ $regex: 'keep' })
|
|
139
154
|
})
|
|
140
155
|
})
|
|
141
156
|
|
|
142
157
|
it('should reset skip to 0 when applying filter', async () => {
|
|
143
158
|
const findOptions = createFindOptions({ skip: 20 })
|
|
144
|
-
const { injector } = await renderEnumFilter(findOptions)
|
|
159
|
+
const { injector, onFindOptionsChange } = await renderEnumFilter(findOptions)
|
|
145
160
|
await usingAsync(injector, async () => {
|
|
146
161
|
const checkboxes = document.querySelectorAll('shade-checkbox input[type="checkbox"]')
|
|
147
162
|
const checkbox = checkboxes[0] as HTMLInputElement
|
|
@@ -152,7 +167,7 @@ describe('EnumFilter', () => {
|
|
|
152
167
|
applyButton?.click()
|
|
153
168
|
await flushUpdates()
|
|
154
169
|
|
|
155
|
-
expect(
|
|
170
|
+
expect(onFindOptionsChange).toHaveBeenCalledWith(expect.objectContaining({ skip: 0 }))
|
|
156
171
|
})
|
|
157
172
|
})
|
|
158
173
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { createComponent, Shade } from '@furystack/shades'
|
|
2
|
-
import type { ObservableValue } from '@furystack/utils'
|
|
3
2
|
import { SegmentedControl } from '../../button-group.js'
|
|
4
3
|
import { Button } from '../../button.js'
|
|
5
4
|
import { close as closeIcon, search as searchIcon } from '../../icons/icon-definitions.js'
|
|
@@ -14,10 +13,11 @@ type EnumMode = 'include' | 'exclude'
|
|
|
14
13
|
export const EnumFilter = Shade<{
|
|
15
14
|
field: string
|
|
16
15
|
values: Array<{ label: string; value: string }>
|
|
17
|
-
findOptions:
|
|
16
|
+
findOptions: FilterableFindOptions
|
|
17
|
+
onFindOptionsChange: (options: FilterableFindOptions) => void
|
|
18
18
|
onClose: () => void
|
|
19
19
|
}>({
|
|
20
|
-
|
|
20
|
+
customElementName: 'data-grid-enum-filter',
|
|
21
21
|
css: {
|
|
22
22
|
...filterBaseCss,
|
|
23
23
|
fontFamily: cssVariableTheme.typography.fontFamily,
|
|
@@ -36,8 +36,8 @@ export const EnumFilter = Shade<{
|
|
|
36
36
|
marginBottom: '0',
|
|
37
37
|
},
|
|
38
38
|
},
|
|
39
|
-
render: ({ props,
|
|
40
|
-
const
|
|
39
|
+
render: ({ props, useState }) => {
|
|
40
|
+
const { findOptions } = props
|
|
41
41
|
|
|
42
42
|
const currentFilter = findOptions.filter?.[props.field] as { $in?: string[]; $nin?: string[] } | undefined
|
|
43
43
|
const isExcludeMode = !!currentFilter?.$nin
|
|
@@ -54,14 +54,14 @@ export const EnumFilter = Shade<{
|
|
|
54
54
|
const operator = mode === 'include' ? '$in' : '$nin'
|
|
55
55
|
filter[props.field] = { [operator]: Array.from(selected) }
|
|
56
56
|
}
|
|
57
|
-
|
|
57
|
+
props.onFindOptionsChange({ ...findOptions, filter, skip: 0 })
|
|
58
58
|
props.onClose()
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
const clearFilter = () => {
|
|
62
62
|
const filter = { ...findOptions.filter }
|
|
63
63
|
delete filter[props.field]
|
|
64
|
-
|
|
64
|
+
props.onFindOptionsChange({ ...findOptions, filter, skip: 0 })
|
|
65
65
|
props.onClose()
|
|
66
66
|
}
|
|
67
67
|
|
|
@@ -8,7 +8,7 @@ export type FilterDropdownProps = {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export const FilterDropdown: (props: FilterDropdownProps, children: ChildrenList) => JSX.Element = Shade({
|
|
11
|
-
|
|
11
|
+
customElementName: 'data-grid-filter-dropdown',
|
|
12
12
|
css: {
|
|
13
13
|
fontFamily: cssVariableTheme.typography.fontFamily,
|
|
14
14
|
display: 'block',
|