From 66332618db5d6ba421a5564eb2da034b09b8c99f Mon Sep 17 00:00:00 2001 From: Yordan Date: Mon, 8 Sep 2025 17:38:02 +0200 Subject: [PATCH 1/6] feat: add configurable debounce interval for datasource filter --- .../combobox-web/CHANGELOG.md | 4 ++ .../combobox-web/src/Combobox.editorConfig.ts | 1 + .../combobox-web/src/Combobox.xml | 4 ++ .../src/__tests__/MultiSelection.spec.tsx | 3 +- .../src/__tests__/SingleSelection.spec.tsx | 3 +- .../src/__tests__/StaticSelection.spec.tsx | 3 +- .../Association/BaseAssociationSelector.ts | 6 ++- .../src/helpers/Association/utils.ts | 7 ++- .../helpers/BaseDatasourceOptionsProvider.ts | 43 +++++++++++++++++-- .../DatabaseMultiSelectionSelector.ts | 6 ++- .../DatabaseSingleSelectionSelector.ts | 6 ++- .../src/helpers/Database/utils.ts | 6 ++- .../combobox-web/typings/ComboboxProps.d.ts | 2 + 13 files changed, 78 insertions(+), 16 deletions(-) diff --git a/packages/pluggableWidgets/combobox-web/CHANGELOG.md b/packages/pluggableWidgets/combobox-web/CHANGELOG.md index b43c5de8aa..6860d15a5d 100644 --- a/packages/pluggableWidgets/combobox-web/CHANGELOG.md +++ b/packages/pluggableWidgets/combobox-web/CHANGELOG.md @@ -15,6 +15,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - We fixed an issue where combobox lazy load is not working on initial load. +### Added + +- We added a configurable debounce interval for datasource filter operations via a new property in the Advanced tab. + ## [2.5.0] - 2025-08-12 ### Added diff --git a/packages/pluggableWidgets/combobox-web/src/Combobox.editorConfig.ts b/packages/pluggableWidgets/combobox-web/src/Combobox.editorConfig.ts index 7e7c05e751..dac986d637 100644 --- a/packages/pluggableWidgets/combobox-web/src/Combobox.editorConfig.ts +++ b/packages/pluggableWidgets/combobox-web/src/Combobox.editorConfig.ts @@ -152,6 +152,7 @@ export function getProperties( "selectionMethod", "selectAllButton", "selectAllButtonCaption", + "datasourceFilterDebounceInterval", ...ASSOCIATION_SOURCE_CONFIG, ...DATABASE_SOURCE_CONFIG, ...LAZY_LOADING_CONFIG diff --git a/packages/pluggableWidgets/combobox-web/src/Combobox.xml b/packages/pluggableWidgets/combobox-web/src/Combobox.xml index c1994358df..282fa6e00a 100644 --- a/packages/pluggableWidgets/combobox-web/src/Combobox.xml +++ b/packages/pluggableWidgets/combobox-web/src/Combobox.xml @@ -417,6 +417,10 @@ Skeleton + + Filter debounce + Debounce interval in milliseconds. + diff --git a/packages/pluggableWidgets/combobox-web/src/__tests__/MultiSelection.spec.tsx b/packages/pluggableWidgets/combobox-web/src/__tests__/MultiSelection.spec.tsx index c48e3514a5..874b17ca95 100644 --- a/packages/pluggableWidgets/combobox-web/src/__tests__/MultiSelection.spec.tsx +++ b/packages/pluggableWidgets/combobox-web/src/__tests__/MultiSelection.spec.tsx @@ -77,7 +77,8 @@ describe("Combo box (Association)", () => { selectedItemsSorting: "none", customEditability: "default", customEditabilityExpression: dynamic(false), - filterInputDebounceInterval: 200 + filterInputDebounceInterval: 200, + datasourceFilterDebounceInterval: 200 }; if (defaultProps.optionsSourceAssociationCaptionType === "expression") { defaultProps.optionsSourceAssociationCaptionExpression!.get = i => dynamic(`${i.id}`); diff --git a/packages/pluggableWidgets/combobox-web/src/__tests__/SingleSelection.spec.tsx b/packages/pluggableWidgets/combobox-web/src/__tests__/SingleSelection.spec.tsx index c71fccf281..8a92c1615a 100644 --- a/packages/pluggableWidgets/combobox-web/src/__tests__/SingleSelection.spec.tsx +++ b/packages/pluggableWidgets/combobox-web/src/__tests__/SingleSelection.spec.tsx @@ -80,7 +80,8 @@ describe("Combo box (Association)", () => { selectedItemsSorting: "none", customEditability: "default", customEditabilityExpression: dynamic(false), - filterInputDebounceInterval: 200 + filterInputDebounceInterval: 200, + datasourceFilterDebounceInterval: 200 }; if (defaultProps.optionsSourceAssociationCaptionType === "expression") { defaultProps.optionsSourceAssociationCaptionExpression!.get = i => dynamic(`${i.id}`); diff --git a/packages/pluggableWidgets/combobox-web/src/__tests__/StaticSelection.spec.tsx b/packages/pluggableWidgets/combobox-web/src/__tests__/StaticSelection.spec.tsx index deb2396e84..fcab22d6de 100644 --- a/packages/pluggableWidgets/combobox-web/src/__tests__/StaticSelection.spec.tsx +++ b/packages/pluggableWidgets/combobox-web/src/__tests__/StaticSelection.spec.tsx @@ -78,7 +78,8 @@ describe("Combo box (Static values)", () => { selectedItemsSorting: "none", customEditability: "default", customEditabilityExpression: dynamic(false), - filterInputDebounceInterval: 200 + filterInputDebounceInterval: 200, + datasourceFilterDebounceInterval: 200 }; if (defaultProps.optionsSourceAssociationCaptionType === "expression") { defaultProps.optionsSourceAssociationCaptionExpression!.get = i => dynamic(`${i.id}`); diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/Association/BaseAssociationSelector.ts b/packages/pluggableWidgets/combobox-web/src/helpers/Association/BaseAssociationSelector.ts index eb910d4a4e..fb2a62cb49 100644 --- a/packages/pluggableWidgets/combobox-web/src/helpers/Association/BaseAssociationSelector.ts +++ b/packages/pluggableWidgets/combobox-web/src/helpers/Association/BaseAssociationSelector.ts @@ -45,7 +45,8 @@ export class BaseAssociationSelector).id : undefined + attributeId: captionType === "attribute" ? (captionProvider as ListAttributeValue).id : undefined, + datasourceFilterDebounceInterval }); if ( diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/Association/utils.ts b/packages/pluggableWidgets/combobox-web/src/helpers/Association/utils.ts index ac0e0a99f2..cfe458c536 100644 --- a/packages/pluggableWidgets/combobox-web/src/helpers/Association/utils.ts +++ b/packages/pluggableWidgets/combobox-web/src/helpers/Association/utils.ts @@ -28,13 +28,15 @@ type ExtractionReturnValue = [ ListWidgetValue | undefined, OptionsSourceAssociationCustomContentTypeEnum, boolean, - LoadingTypeEnum + LoadingTypeEnum, + number ]; export function extractAssociationProps(props: ComboboxContainerProps): ExtractionReturnValue { const attr = props.attributeAssociation; const filterType = props.filterType; const onChangeEvent = props.onChangeEvent; + const datasourceFilterDebounceInterval = props.datasourceFilterDebounceInterval; if (!attr) { throw new Error("'optionsSourceType' type is 'association' but 'attributeAssociation' is not defined."); @@ -79,6 +81,7 @@ export function extractAssociationProps(props: ComboboxContainerProps): Extracti customContent, customContentType, lazyLoading, - loadingType + loadingType, + datasourceFilterDebounceInterval ]; } diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/BaseDatasourceOptionsProvider.ts b/packages/pluggableWidgets/combobox-web/src/helpers/BaseDatasourceOptionsProvider.ts index 1fbd1ae76a..08f7ccee38 100644 --- a/packages/pluggableWidgets/combobox-web/src/helpers/BaseDatasourceOptionsProvider.ts +++ b/packages/pluggableWidgets/combobox-web/src/helpers/BaseDatasourceOptionsProvider.ts @@ -1,3 +1,4 @@ +import { debounce } from "@mendix/widget-plugin-platform/utils/debounce"; import { ListAttributeValue, ListValue, ObjectItem } from "mendix"; import { FilterTypeEnum } from "../../typings/ComboboxProps"; import { BaseOptionsProvider } from "./BaseOptionsProvider"; @@ -10,12 +11,16 @@ export interface BaseProps { ds: ListValue; filterType: FilterTypeEnum; lazyLoading: boolean; + datasourceFilterDebounceInterval?: number; } export class BaseDatasourceOptionsProvider extends BaseOptionsProvider { private ds?: ListValue; private attributeId?: ListAttributeValue["id"]; protected loading: boolean = false; + private debouncedSetFilter?: (filterCondition: any) => void; + private abortDebouncedFilter?: () => void; + private datasourceFilterDebounceInterval: number = 200; constructor( caption: CaptionsProvider, @@ -24,6 +29,19 @@ export class BaseDatasourceOptionsProvider extends BaseOptionsProvider { + this.ds?.setFilter(filterCondition); + }, this.datasourceFilterDebounceInterval); + + this.debouncedSetFilter = debouncedFn; + this.abortDebouncedFilter = abort; + } + get sortOrder(): SortOrder { let sortDir: SortOrder = "asc"; if (this.ds) { @@ -50,11 +68,14 @@ export class BaseDatasourceOptionsProvider extends BaseOptionsProvider this.valuesMap.set(i.id, i)); this.options = Array.from(this.valuesMap.keys()); } + + cleanup(): void { + if (this.abortDebouncedFilter) { + this.abortDebouncedFilter(); + } + } } diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseMultiSelectionSelector.ts b/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseMultiSelectionSelector.ts index e91591ed08..e9cf44463d 100644 --- a/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseMultiSelectionSelector.ts +++ b/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseMultiSelectionSelector.ts @@ -75,7 +75,8 @@ export class DatabaseMultiSelectionSelector implements MultiSelector { filterType, lazyLoading, loadingType, - valueSourceAttribute + valueSourceAttribute, + datasourceFilterDebounceInterval } = extractDatabaseProps(props); if ( @@ -107,7 +108,8 @@ export class DatabaseMultiSelectionSelector implements MultiSelector { ds, filterType, lazyLoading, - attributeId: captionType === "attribute" ? (captionProvider as ListAttributeValue).id : undefined + attributeId: captionType === "attribute" ? (captionProvider as ListAttributeValue).id : undefined, + datasourceFilterDebounceInterval }); if (this.selectionMethod === "rowclick" || this.customContentType === "yes") { diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseSingleSelectionSelector.ts b/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseSingleSelectionSelector.ts index d480133072..042081e665 100644 --- a/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseSingleSelectionSelector.ts +++ b/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseSingleSelectionSelector.ts @@ -52,7 +52,8 @@ export class DatabaseSingleSelectionSelector).id : undefined + attributeId: captionType === "attribute" ? (captionProvider as ListAttributeValue).id : undefined, + datasourceFilterDebounceInterval }); this.values.updateProps({ diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/Database/utils.ts b/packages/pluggableWidgets/combobox-web/src/helpers/Database/utils.ts index 8a5296bf22..f064ba0430 100644 --- a/packages/pluggableWidgets/combobox-web/src/helpers/Database/utils.ts +++ b/packages/pluggableWidgets/combobox-web/src/helpers/Database/utils.ts @@ -28,12 +28,13 @@ type ExtractionReturnValue = { lazyLoading: boolean; loadingType: LoadingTypeEnum; valueSourceAttribute: ListAttributeValue | undefined; + datasourceFilterDebounceInterval: number; }; export function extractDatabaseProps(props: ComboboxContainerProps): ExtractionReturnValue { const targetAttribute = props.databaseAttributeString; const filterType = props.filterType; - + const datasourceFilterDebounceInterval = props.datasourceFilterDebounceInterval; const ds = props.optionsSourceDatabaseDataSource; if (!ds) { throw new Error("'optionsSourceType' type is 'database' but 'optionsSourceDatabaseDataSource' is not defined."); @@ -83,7 +84,8 @@ export function extractDatabaseProps(props: ComboboxContainerProps): ExtractionR filterType, lazyLoading, loadingType, - valueSourceAttribute + valueSourceAttribute, + datasourceFilterDebounceInterval }; } diff --git a/packages/pluggableWidgets/combobox-web/typings/ComboboxProps.d.ts b/packages/pluggableWidgets/combobox-web/typings/ComboboxProps.d.ts index aec3e503fb..6b25432343 100644 --- a/packages/pluggableWidgets/combobox-web/typings/ComboboxProps.d.ts +++ b/packages/pluggableWidgets/combobox-web/typings/ComboboxProps.d.ts @@ -100,6 +100,7 @@ export interface ComboboxContainerProps { a11yInstructions?: DynamicValue; lazyLoading: boolean; loadingType: LoadingTypeEnum; + datasourceFilterDebounceInterval: number; selectedItemsSorting: SelectedItemsSortingEnum; filterType: FilterTypeEnum; } @@ -158,6 +159,7 @@ export interface ComboboxPreviewProps { a11yInstructions: string; lazyLoading: boolean; loadingType: LoadingTypeEnum; + datasourceFilterDebounceInterval: number | null; selectedItemsSorting: SelectedItemsSortingEnum; filterType: FilterTypeEnum; } From 7f4d5c0651d4c900ba347c669a98806fde7bb3e7 Mon Sep 17 00:00:00 2001 From: Yordan Date: Thu, 11 Sep 2025 11:21:22 +0200 Subject: [PATCH 2/6] chore: update changelog --- .../pluggableWidgets/combobox-web/CHANGELOG.md | 2 +- .../combobox-web/src/Combobox.editorConfig.ts | 5 ----- .../combobox-web/src/Combobox.xml | 5 ----- .../src/__tests__/MultiSelection.spec.tsx | 3 +-- .../src/__tests__/SingleSelection.spec.tsx | 3 +-- .../src/__tests__/StaticSelection.spec.tsx | 3 +-- .../Association/BaseAssociationSelector.ts | 4 ++-- .../src/helpers/Association/utils.ts | 4 ++-- .../src/helpers/BaseDatasourceOptionsProvider.ts | 16 +++++++--------- .../Database/DatabaseMultiSelectionSelector.ts | 4 ++-- .../Database/DatabaseSingleSelectionSelector.ts | 4 ++-- .../combobox-web/src/helpers/Database/utils.ts | 6 +++--- .../combobox-web/typings/ComboboxProps.d.ts | 2 -- 13 files changed, 22 insertions(+), 39 deletions(-) diff --git a/packages/pluggableWidgets/combobox-web/CHANGELOG.md b/packages/pluggableWidgets/combobox-web/CHANGELOG.md index 6860d15a5d..c84523bfe8 100644 --- a/packages/pluggableWidgets/combobox-web/CHANGELOG.md +++ b/packages/pluggableWidgets/combobox-web/CHANGELOG.md @@ -17,7 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Added -- We added a configurable debounce interval for datasource filter operations via a new property in the Advanced tab. +- We enabled a configurable debounce interval for datasource filter operations as well, via a existing property filterInputDebounceInterval. ## [2.5.0] - 2025-08-12 diff --git a/packages/pluggableWidgets/combobox-web/src/Combobox.editorConfig.ts b/packages/pluggableWidgets/combobox-web/src/Combobox.editorConfig.ts index dac986d637..392b732415 100644 --- a/packages/pluggableWidgets/combobox-web/src/Combobox.editorConfig.ts +++ b/packages/pluggableWidgets/combobox-web/src/Combobox.editorConfig.ts @@ -152,7 +152,6 @@ export function getProperties( "selectionMethod", "selectAllButton", "selectAllButtonCaption", - "datasourceFilterDebounceInterval", ...ASSOCIATION_SOURCE_CONFIG, ...DATABASE_SOURCE_CONFIG, ...LAZY_LOADING_CONFIG @@ -179,10 +178,6 @@ export function getProperties( hidePropertiesIn(defaultProperties, values, ["loadingType"]); } - if (values.onChangeFilterInputEvent === null) { - hidePropertiesIn(defaultProperties, values, ["filterInputDebounceInterval"]); - } - return defaultProperties; } diff --git a/packages/pluggableWidgets/combobox-web/src/Combobox.xml b/packages/pluggableWidgets/combobox-web/src/Combobox.xml index 282fa6e00a..a6234de7d8 100644 --- a/packages/pluggableWidgets/combobox-web/src/Combobox.xml +++ b/packages/pluggableWidgets/combobox-web/src/Combobox.xml @@ -329,7 +329,6 @@ On leave - On filter input change @@ -417,10 +416,6 @@ Skeleton - - Filter debounce - Debounce interval in milliseconds. - diff --git a/packages/pluggableWidgets/combobox-web/src/__tests__/MultiSelection.spec.tsx b/packages/pluggableWidgets/combobox-web/src/__tests__/MultiSelection.spec.tsx index 874b17ca95..c48e3514a5 100644 --- a/packages/pluggableWidgets/combobox-web/src/__tests__/MultiSelection.spec.tsx +++ b/packages/pluggableWidgets/combobox-web/src/__tests__/MultiSelection.spec.tsx @@ -77,8 +77,7 @@ describe("Combo box (Association)", () => { selectedItemsSorting: "none", customEditability: "default", customEditabilityExpression: dynamic(false), - filterInputDebounceInterval: 200, - datasourceFilterDebounceInterval: 200 + filterInputDebounceInterval: 200 }; if (defaultProps.optionsSourceAssociationCaptionType === "expression") { defaultProps.optionsSourceAssociationCaptionExpression!.get = i => dynamic(`${i.id}`); diff --git a/packages/pluggableWidgets/combobox-web/src/__tests__/SingleSelection.spec.tsx b/packages/pluggableWidgets/combobox-web/src/__tests__/SingleSelection.spec.tsx index 8a92c1615a..c71fccf281 100644 --- a/packages/pluggableWidgets/combobox-web/src/__tests__/SingleSelection.spec.tsx +++ b/packages/pluggableWidgets/combobox-web/src/__tests__/SingleSelection.spec.tsx @@ -80,8 +80,7 @@ describe("Combo box (Association)", () => { selectedItemsSorting: "none", customEditability: "default", customEditabilityExpression: dynamic(false), - filterInputDebounceInterval: 200, - datasourceFilterDebounceInterval: 200 + filterInputDebounceInterval: 200 }; if (defaultProps.optionsSourceAssociationCaptionType === "expression") { defaultProps.optionsSourceAssociationCaptionExpression!.get = i => dynamic(`${i.id}`); diff --git a/packages/pluggableWidgets/combobox-web/src/__tests__/StaticSelection.spec.tsx b/packages/pluggableWidgets/combobox-web/src/__tests__/StaticSelection.spec.tsx index fcab22d6de..deb2396e84 100644 --- a/packages/pluggableWidgets/combobox-web/src/__tests__/StaticSelection.spec.tsx +++ b/packages/pluggableWidgets/combobox-web/src/__tests__/StaticSelection.spec.tsx @@ -78,8 +78,7 @@ describe("Combo box (Static values)", () => { selectedItemsSorting: "none", customEditability: "default", customEditabilityExpression: dynamic(false), - filterInputDebounceInterval: 200, - datasourceFilterDebounceInterval: 200 + filterInputDebounceInterval: 200 }; if (defaultProps.optionsSourceAssociationCaptionType === "expression") { defaultProps.optionsSourceAssociationCaptionExpression!.get = i => dynamic(`${i.id}`); diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/Association/BaseAssociationSelector.ts b/packages/pluggableWidgets/combobox-web/src/helpers/Association/BaseAssociationSelector.ts index fb2a62cb49..027bc1ba72 100644 --- a/packages/pluggableWidgets/combobox-web/src/helpers/Association/BaseAssociationSelector.ts +++ b/packages/pluggableWidgets/combobox-web/src/helpers/Association/BaseAssociationSelector.ts @@ -46,7 +46,7 @@ export class BaseAssociationSelector).id : undefined, - datasourceFilterDebounceInterval + filterInputDebounceInterval }); if ( diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/Association/utils.ts b/packages/pluggableWidgets/combobox-web/src/helpers/Association/utils.ts index cfe458c536..1cc1e97959 100644 --- a/packages/pluggableWidgets/combobox-web/src/helpers/Association/utils.ts +++ b/packages/pluggableWidgets/combobox-web/src/helpers/Association/utils.ts @@ -36,7 +36,7 @@ export function extractAssociationProps(props: ComboboxContainerProps): Extracti const attr = props.attributeAssociation; const filterType = props.filterType; const onChangeEvent = props.onChangeEvent; - const datasourceFilterDebounceInterval = props.datasourceFilterDebounceInterval; + const filterInputDebounceInterval = props.filterInputDebounceInterval; if (!attr) { throw new Error("'optionsSourceType' type is 'association' but 'attributeAssociation' is not defined."); @@ -82,6 +82,6 @@ export function extractAssociationProps(props: ComboboxContainerProps): Extracti customContentType, lazyLoading, loadingType, - datasourceFilterDebounceInterval + filterInputDebounceInterval ]; } diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/BaseDatasourceOptionsProvider.ts b/packages/pluggableWidgets/combobox-web/src/helpers/BaseDatasourceOptionsProvider.ts index 08f7ccee38..8b9ed541c9 100644 --- a/packages/pluggableWidgets/combobox-web/src/helpers/BaseDatasourceOptionsProvider.ts +++ b/packages/pluggableWidgets/combobox-web/src/helpers/BaseDatasourceOptionsProvider.ts @@ -11,7 +11,7 @@ export interface BaseProps { ds: ListValue; filterType: FilterTypeEnum; lazyLoading: boolean; - datasourceFilterDebounceInterval?: number; + filterInputDebounceInterval?: number; } export class BaseDatasourceOptionsProvider extends BaseOptionsProvider { @@ -20,7 +20,7 @@ export class BaseDatasourceOptionsProvider extends BaseOptionsProvider void; private abortDebouncedFilter?: () => void; - private datasourceFilterDebounceInterval: number = 200; + private filterInputDebounceInterval: number = 200; constructor( caption: CaptionsProvider, @@ -30,13 +30,11 @@ export class BaseDatasourceOptionsProvider extends BaseOptionsProvider { this.ds?.setFilter(filterCondition); - }, this.datasourceFilterDebounceInterval); + }, this.filterInputDebounceInterval); this.debouncedSetFilter = debouncedFn; this.abortDebouncedFilter = abort; @@ -125,9 +123,9 @@ export class BaseDatasourceOptionsProvider extends BaseOptionsProvider).id : undefined, - datasourceFilterDebounceInterval + filterInputDebounceInterval }); if (this.selectionMethod === "rowclick" || this.customContentType === "yes") { diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseSingleSelectionSelector.ts b/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseSingleSelectionSelector.ts index 042081e665..f78c01ae1b 100644 --- a/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseSingleSelectionSelector.ts +++ b/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseSingleSelectionSelector.ts @@ -53,7 +53,7 @@ export class DatabaseSingleSelectionSelector).id : undefined, - datasourceFilterDebounceInterval + filterInputDebounceInterval }); this.values.updateProps({ diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/Database/utils.ts b/packages/pluggableWidgets/combobox-web/src/helpers/Database/utils.ts index f064ba0430..1c3a0f0e7a 100644 --- a/packages/pluggableWidgets/combobox-web/src/helpers/Database/utils.ts +++ b/packages/pluggableWidgets/combobox-web/src/helpers/Database/utils.ts @@ -28,13 +28,13 @@ type ExtractionReturnValue = { lazyLoading: boolean; loadingType: LoadingTypeEnum; valueSourceAttribute: ListAttributeValue | undefined; - datasourceFilterDebounceInterval: number; + filterInputDebounceInterval: number; }; export function extractDatabaseProps(props: ComboboxContainerProps): ExtractionReturnValue { const targetAttribute = props.databaseAttributeString; const filterType = props.filterType; - const datasourceFilterDebounceInterval = props.datasourceFilterDebounceInterval; + const filterInputDebounceInterval = props.filterInputDebounceInterval; const ds = props.optionsSourceDatabaseDataSource; if (!ds) { throw new Error("'optionsSourceType' type is 'database' but 'optionsSourceDatabaseDataSource' is not defined."); @@ -85,7 +85,7 @@ export function extractDatabaseProps(props: ComboboxContainerProps): ExtractionR lazyLoading, loadingType, valueSourceAttribute, - datasourceFilterDebounceInterval + filterInputDebounceInterval }; } diff --git a/packages/pluggableWidgets/combobox-web/typings/ComboboxProps.d.ts b/packages/pluggableWidgets/combobox-web/typings/ComboboxProps.d.ts index 6b25432343..aec3e503fb 100644 --- a/packages/pluggableWidgets/combobox-web/typings/ComboboxProps.d.ts +++ b/packages/pluggableWidgets/combobox-web/typings/ComboboxProps.d.ts @@ -100,7 +100,6 @@ export interface ComboboxContainerProps { a11yInstructions?: DynamicValue; lazyLoading: boolean; loadingType: LoadingTypeEnum; - datasourceFilterDebounceInterval: number; selectedItemsSorting: SelectedItemsSortingEnum; filterType: FilterTypeEnum; } @@ -159,7 +158,6 @@ export interface ComboboxPreviewProps { a11yInstructions: string; lazyLoading: boolean; loadingType: LoadingTypeEnum; - datasourceFilterDebounceInterval: number | null; selectedItemsSorting: SelectedItemsSortingEnum; filterType: FilterTypeEnum; } From 9afbc0b45f60ae167c6d740b4cbbbe4b4e6fd057 Mon Sep 17 00:00:00 2001 From: Yordan Date: Fri, 12 Sep 2025 11:43:50 +0200 Subject: [PATCH 3/6] fix: ensure abort function is called only if defined in cleanup method --- .../src/helpers/BaseDatasourceOptionsProvider.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/BaseDatasourceOptionsProvider.ts b/packages/pluggableWidgets/combobox-web/src/helpers/BaseDatasourceOptionsProvider.ts index 8b9ed541c9..cca0d9f054 100644 --- a/packages/pluggableWidgets/combobox-web/src/helpers/BaseDatasourceOptionsProvider.ts +++ b/packages/pluggableWidgets/combobox-web/src/helpers/BaseDatasourceOptionsProvider.ts @@ -5,6 +5,7 @@ import { BaseOptionsProvider } from "./BaseOptionsProvider"; import { datasourceFilter } from "./datasourceFilter"; import { CaptionsProvider, SortOrder, Status } from "./types"; import { DEFAULT_LIMIT_SIZE } from "./utils"; +import { FilterCondition } from "mendix/filters"; export interface BaseProps { attributeId?: ListAttributeValue["id"]; @@ -18,8 +19,8 @@ export class BaseDatasourceOptionsProvider extends BaseOptionsProvider void; - private abortDebouncedFilter?: () => void; + private debouncedSetFilter!: (filterCondition: FilterCondition | undefined) => void; + private abortDebouncedFilter!: () => void; private filterInputDebounceInterval: number = 200; constructor( @@ -27,12 +28,13 @@ export class BaseDatasourceOptionsProvider extends BaseOptionsProvider ) { super(caption); + this.createDebouncedSetFilter(); } private createDebouncedSetFilter(): void { this.cleanup(); - const [debouncedFn, abort] = debounce((filterCondition: any) => { + const [debouncedFn, abort] = debounce((filterCondition: FilterCondition | undefined) => { this.ds?.setFilter(filterCondition); }, this.filterInputDebounceInterval); @@ -66,9 +68,6 @@ export class BaseDatasourceOptionsProvider extends BaseOptionsProvider Date: Fri, 12 Sep 2025 11:43:50 +0200 Subject: [PATCH 4/6] fix: update providers to include timeout parameter --- .../Association/BaseAssociationSelector.ts | 2 +- .../helpers/BaseDatasourceOptionsProvider.ts | 33 +++++-------------- .../DatabaseMultiSelectionSelector.ts | 2 +- .../DatabaseSingleSelectionSelector.ts | 2 +- 4 files changed, 11 insertions(+), 28 deletions(-) diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/Association/BaseAssociationSelector.ts b/packages/pluggableWidgets/combobox-web/src/helpers/Association/BaseAssociationSelector.ts index 027bc1ba72..b4f1ea71cf 100644 --- a/packages/pluggableWidgets/combobox-web/src/helpers/Association/BaseAssociationSelector.ts +++ b/packages/pluggableWidgets/combobox-web/src/helpers/Association/BaseAssociationSelector.ts @@ -29,7 +29,7 @@ export class BaseAssociationSelector void; - private abortDebouncedFilter!: () => void; - private filterInputDebounceInterval: number = 200; + private debouncedSetFilter: (filterCondition: FilterCondition | undefined) => void; + private filterInputDebounceInterval: number; constructor( caption: CaptionsProvider, - protected valuesMap: Map + protected valuesMap: Map, + filterInputDebounceInterval: number = 200 ) { super(caption); - this.createDebouncedSetFilter(); - } - - private createDebouncedSetFilter(): void { - this.cleanup(); + this.filterInputDebounceInterval = filterInputDebounceInterval; - const [debouncedFn, abort] = debounce((filterCondition: FilterCondition | undefined) => { + const [debouncedFn] = debounce((filterCondition: FilterCondition | undefined) => { this.ds?.setFilter(filterCondition); }, this.filterInputDebounceInterval); this.debouncedSetFilter = debouncedFn; - this.abortDebouncedFilter = abort; } get sortOrder(): SortOrder { @@ -69,10 +64,10 @@ export class BaseDatasourceOptionsProvider extends BaseOptionsProvider this.valuesMap.set(i.id, i)); this.options = Array.from(this.valuesMap.keys()); } - - cleanup(): void { - if (this.abortDebouncedFilter) { - this.abortDebouncedFilter(); - } - } } diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseMultiSelectionSelector.ts b/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseMultiSelectionSelector.ts index ad6d25a03c..f4cf22028b 100644 --- a/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseMultiSelectionSelector.ts +++ b/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseMultiSelectionSelector.ts @@ -36,7 +36,7 @@ export class DatabaseMultiSelectionSelector implements MultiSelector { constructor() { this.caption = new DatabaseCaptionsProvider(this._objectsMap); - this.options = new DatabaseOptionsProvider(this.caption, this._objectsMap); + this.options = new DatabaseOptionsProvider(this.caption, this._objectsMap, 200); } getOptions(): string[] { diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseSingleSelectionSelector.ts b/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseSingleSelectionSelector.ts index f78c01ae1b..97520e334b 100644 --- a/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseSingleSelectionSelector.ts +++ b/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseSingleSelectionSelector.ts @@ -35,7 +35,7 @@ export class DatabaseSingleSelectionSelector Date: Tue, 16 Sep 2025 14:55:36 +0200 Subject: [PATCH 5/6] fix: remove unnecessary createDebouncedSetFilter --- packages/pluggableWidgets/combobox-web/CHANGELOG.md | 2 +- .../helpers/Association/BaseAssociationSelector.ts | 10 ++++------ .../src/helpers/BaseDatasourceOptionsProvider.ts | 10 ++-------- .../Database/DatabaseMultiSelectionSelector.ts | 10 ++++------ .../Database/DatabaseSingleSelectionSelector.ts | 10 ++++------ .../combobox-web/src/helpers/getSelector.ts | 12 ++++++++---- 6 files changed, 23 insertions(+), 31 deletions(-) diff --git a/packages/pluggableWidgets/combobox-web/CHANGELOG.md b/packages/pluggableWidgets/combobox-web/CHANGELOG.md index c84523bfe8..4ee2b769b8 100644 --- a/packages/pluggableWidgets/combobox-web/CHANGELOG.md +++ b/packages/pluggableWidgets/combobox-web/CHANGELOG.md @@ -17,7 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Added -- We enabled a configurable debounce interval for datasource filter operations as well, via a existing property filterInputDebounceInterval. +- We added the option to configure a debounce interval for datasource filter operations as well. ## [2.5.0] - 2025-08-12 diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/Association/BaseAssociationSelector.ts b/packages/pluggableWidgets/combobox-web/src/helpers/Association/BaseAssociationSelector.ts index b4f1ea71cf..a4e65f8c16 100644 --- a/packages/pluggableWidgets/combobox-web/src/helpers/Association/BaseAssociationSelector.ts +++ b/packages/pluggableWidgets/combobox-web/src/helpers/Association/BaseAssociationSelector.ts @@ -27,9 +27,9 @@ export class BaseAssociationSelector = new Map(); private lazyLoader: LazyLoadProvider = new LazyLoadProvider(); - constructor() { + constructor(props: { filterInputDebounceInterval: number }) { this.caption = new AssociationSimpleCaptionsProvider(this._valuesMap); - this.options = new AssociationOptionsProvider(this.caption, this._valuesMap, 200); + this.options = new AssociationOptionsProvider(this.caption, this._valuesMap, props.filterInputDebounceInterval); } updateProps(props: ComboboxContainerProps): void { @@ -45,8 +45,7 @@ export class BaseAssociationSelector).id : undefined, - filterInputDebounceInterval + attributeId: captionType === "attribute" ? (captionProvider as ListAttributeValue).id : undefined }); if ( diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/BaseDatasourceOptionsProvider.ts b/packages/pluggableWidgets/combobox-web/src/helpers/BaseDatasourceOptionsProvider.ts index ee878a5b7e..9d2bb92632 100644 --- a/packages/pluggableWidgets/combobox-web/src/helpers/BaseDatasourceOptionsProvider.ts +++ b/packages/pluggableWidgets/combobox-web/src/helpers/BaseDatasourceOptionsProvider.ts @@ -20,7 +20,6 @@ export class BaseDatasourceOptionsProvider extends BaseOptionsProvider void; - private filterInputDebounceInterval: number; constructor( caption: CaptionsProvider, @@ -28,11 +27,10 @@ export class BaseDatasourceOptionsProvider extends BaseOptionsProvider { this.ds?.setFilter(filterCondition); - }, this.filterInputDebounceInterval); + }, filterInputDebounceInterval); this.debouncedSetFilter = debouncedFn; } @@ -101,12 +99,8 @@ export class BaseDatasourceOptionsProvider extends BaseOptionsProvider = new Map(); selectedItemsSorting: SelectedItemsSortingEnum = "none"; - constructor() { + constructor(props: { filterInputDebounceInterval: number }) { this.caption = new DatabaseCaptionsProvider(this._objectsMap); - this.options = new DatabaseOptionsProvider(this.caption, this._objectsMap, 200); + this.options = new DatabaseOptionsProvider(this.caption, this._objectsMap, props.filterInputDebounceInterval); } getOptions(): string[] { @@ -75,8 +75,7 @@ export class DatabaseMultiSelectionSelector implements MultiSelector { filterType, lazyLoading, loadingType, - valueSourceAttribute, - filterInputDebounceInterval + valueSourceAttribute } = extractDatabaseProps(props); if ( @@ -108,8 +107,7 @@ export class DatabaseMultiSelectionSelector implements MultiSelector { ds, filterType, lazyLoading, - attributeId: captionType === "attribute" ? (captionProvider as ListAttributeValue).id : undefined, - filterInputDebounceInterval + attributeId: captionType === "attribute" ? (captionProvider as ListAttributeValue).id : undefined }); if (this.selectionMethod === "rowclick" || this.customContentType === "yes") { diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseSingleSelectionSelector.ts b/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseSingleSelectionSelector.ts index 97520e334b..55944a48fe 100644 --- a/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseSingleSelectionSelector.ts +++ b/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseSingleSelectionSelector.ts @@ -33,9 +33,9 @@ export class DatabaseSingleSelectionSelector).id : undefined, - filterInputDebounceInterval + attributeId: captionType === "attribute" ? (captionProvider as ListAttributeValue).id : undefined }); this.values.updateProps({ diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/getSelector.ts b/packages/pluggableWidgets/combobox-web/src/helpers/getSelector.ts index 7bc6005f66..4667dc363c 100644 --- a/packages/pluggableWidgets/combobox-web/src/helpers/getSelector.ts +++ b/packages/pluggableWidgets/combobox-web/src/helpers/getSelector.ts @@ -13,16 +13,20 @@ export function getSelector(props: ComboboxContainerProps): Selector { return new EnumBooleanSingleSelector(); } else if (props.optionsSourceType === "association") { return props.attributeAssociation.type === "Reference" - ? new AssociationSingleSelector() - : new AssociationMultiSelector(); + ? new AssociationSingleSelector({ filterInputDebounceInterval: props.filterInputDebounceInterval }) + : new AssociationMultiSelector({ filterInputDebounceInterval: props.filterInputDebounceInterval }); } else { throw new Error(`'optionsSourceType' of type '${props.optionsSourceType}' is not supported`); } } else if (props.source === "database") { if (props.optionsSourceDatabaseItemSelection?.type === "Multi") { - return new DatabaseMultiSelectionSelector(); + return new DatabaseMultiSelectionSelector({ + filterInputDebounceInterval: props.filterInputDebounceInterval + }); } else { - return new DatabaseSingleSelectionSelector(); + return new DatabaseSingleSelectionSelector({ + filterInputDebounceInterval: props.filterInputDebounceInterval + }); } } else if (props.source === "static") { return new StaticSingleSelector(); From cd54a2cb2ff3bdcb5c0a6030a538b1ba153625e6 Mon Sep 17 00:00:00 2001 From: Yordan Date: Tue, 23 Sep 2025 15:29:03 +0200 Subject: [PATCH 6/6] chore: update changelog --- packages/pluggableWidgets/combobox-web/CHANGELOG.md | 4 ++++ packages/pluggableWidgets/combobox-web/src/Combobox.xml | 8 ++++---- .../combobox-web/typings/ComboboxProps.d.ts | 4 ++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/pluggableWidgets/combobox-web/CHANGELOG.md b/packages/pluggableWidgets/combobox-web/CHANGELOG.md index 4ee2b769b8..3007958889 100644 --- a/packages/pluggableWidgets/combobox-web/CHANGELOG.md +++ b/packages/pluggableWidgets/combobox-web/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +### Changed + +- Moved the debounce interval for filtering operations from the Events tab to Advanced tab. + ## [2.5.1] - 2025-09-19 ### Fixed diff --git a/packages/pluggableWidgets/combobox-web/src/Combobox.xml b/packages/pluggableWidgets/combobox-web/src/Combobox.xml index a6234de7d8..274e3ba9af 100644 --- a/packages/pluggableWidgets/combobox-web/src/Combobox.xml +++ b/packages/pluggableWidgets/combobox-web/src/Combobox.xml @@ -336,10 +336,6 @@ - - Debounce interval - The debounce interval for each filter input change event triggered in milliseconds. - @@ -438,6 +434,10 @@ None + + Debounce interval + The debounce interval for each filter input change event triggered in milliseconds. + diff --git a/packages/pluggableWidgets/combobox-web/typings/ComboboxProps.d.ts b/packages/pluggableWidgets/combobox-web/typings/ComboboxProps.d.ts index aec3e503fb..fcc265d859 100644 --- a/packages/pluggableWidgets/combobox-web/typings/ComboboxProps.d.ts +++ b/packages/pluggableWidgets/combobox-web/typings/ComboboxProps.d.ts @@ -90,7 +90,6 @@ export interface ComboboxContainerProps { onEnterEvent?: ActionValue; onLeaveEvent?: ActionValue; onChangeFilterInputEvent?: ActionValue<{ filterInput: Option }>; - filterInputDebounceInterval: number; ariaRequired: DynamicValue; ariaLabel?: DynamicValue; clearButtonAriaLabel?: DynamicValue; @@ -102,6 +101,7 @@ export interface ComboboxContainerProps { loadingType: LoadingTypeEnum; selectedItemsSorting: SelectedItemsSortingEnum; filterType: FilterTypeEnum; + filterInputDebounceInterval: number; } export interface ComboboxPreviewProps { @@ -148,7 +148,6 @@ export interface ComboboxPreviewProps { onEnterEvent: {} | null; onLeaveEvent: {} | null; onChangeFilterInputEvent: {} | null; - filterInputDebounceInterval: number | null; ariaRequired: string; ariaLabel: string; clearButtonAriaLabel: string; @@ -160,4 +159,5 @@ export interface ComboboxPreviewProps { loadingType: LoadingTypeEnum; selectedItemsSorting: SelectedItemsSortingEnum; filterType: FilterTypeEnum; + filterInputDebounceInterval: number | null; }