You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ru...@apache.org on 2026/06/17 06:01:29 UTC
(superset) branch fix/filter-paste-search-all-options created (now 8e7f7cd6ee0)
This is an automated email from the ASF dual-hosted git repository.
rusackas pushed a change to branch fix/filter-paste-search-all-options
in repository https://gitbox.apache.org/repos/asf/superset.git
at 8e7f7cd6ee0 fix(dashboard): keep pasted filter values outside the loaded page
This branch includes the following new commits:
new 8e7f7cd6ee0 fix(dashboard): keep pasted filter values outside the loaded page
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(superset) 01/01: fix(dashboard): keep pasted filter values outside the loaded page
Posted by ru...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
rusackas pushed a commit to branch fix/filter-paste-search-all-options
in repository https://gitbox.apache.org/repos/asf/superset.git
commit 8e7f7cd6ee061b267190dd467ed4996e2f0213b9
Author: Superset Dev <de...@superset.apache.org>
AuthorDate: Tue Jun 16 23:00:43 2026 -0700
fix(dashboard): keep pasted filter values outside the loaded page
Dashboard filters with "Dynamically search all filter values" load only
a page of options client-side. The synchronous Select's paste handler
checked just the loaded options and, with allowNewOptions disabled (as
searchAllOptions sets it), silently dropped any pasted value beyond that
page, so the whole paste appeared to fail.
Add an opt-in allowNewOptionsOnPaste prop that keeps pasted values not
present in the loaded options, and enable it for multi-select
searchAllOptions filters so those values are still applied to the query.
Existing paste behavior for normal selects is unchanged (the prop
defaults to false).
Fixes: #32645
Co-Authored-By: Claude Fable 5 <no...@anthropic.com>
---
.../src/components/Select/Select.test.tsx | 47 ++++++++++++++++++++++
.../src/components/Select/Select.tsx | 16 ++++++--
.../src/components/Select/types.ts | 10 +++++
.../components/Select/SelectFilterPlugin.tsx | 1 +
4 files changed, 71 insertions(+), 3 deletions(-)
diff --git a/superset-frontend/packages/superset-ui-core/src/components/Select/Select.test.tsx b/superset-frontend/packages/superset-ui-core/src/components/Select/Select.test.tsx
index 2b558b072cb..8ed0de298a6 100644
--- a/superset-frontend/packages/superset-ui-core/src/components/Select/Select.test.tsx
+++ b/superset-frontend/packages/superset-ui-core/src/components/Select/Select.test.tsx
@@ -1146,6 +1146,53 @@ test('pasting an non-existent option should not add it if allowNewOptions is fal
expect(await findAllSelectOptions()).toHaveLength(0);
});
+// Reference for the bug this tests: https://github.com/apache/superset/issues/32645
+// Dashboard filters with "Dynamically search all filter values" only load a
+// page of options client-side, so a pasted value outside that page used to be
+// silently dropped. allowNewOptionsOnPaste keeps such values so the filter can
+// still apply them.
+test('keeps pasted values outside loaded options when allowNewOptionsOnPaste is true', async () => {
+ render(
+ <Select
+ {...defaultProps}
+ mode="multiple"
+ allowNewOptions={false}
+ allowNewOptionsOnPaste
+ />,
+ );
+ const input = getElementByClassName('.ant-select-selection-search-input');
+ const paste = createEvent.paste(input, {
+ clipboardData: {
+ // Liam is a loaded option; OutsideValue is not in the loaded page.
+ getData: () => 'Liam,OutsideValue',
+ },
+ });
+ fireEvent(input, paste);
+ await waitFor(() => {
+ const values = [
+ ...getElementsByClassName('.ant-select-selection-item'),
+ ].map(value => value.textContent);
+ expect(values).toEqual(expect.arrayContaining(['Liam', 'OutsideValue']));
+ });
+});
+
+test('drops pasted values outside loaded options when allowNewOptionsOnPaste is false', async () => {
+ render(<Select {...defaultProps} mode="multiple" allowNewOptions={false} />);
+ const input = getElementByClassName('.ant-select-selection-search-input');
+ const paste = createEvent.paste(input, {
+ clipboardData: {
+ getData: () => 'Liam,OutsideValue',
+ },
+ });
+ fireEvent(input, paste);
+ await waitFor(() => {
+ const values = [
+ ...getElementsByClassName('.ant-select-selection-item'),
+ ].map(value => value.textContent);
+ expect(values).toEqual(['Liam']);
+ });
+});
+
test('does not fire onChange if the same value is selected in single mode', async () => {
const onChange = jest.fn();
render(<Select {...defaultProps} onChange={onChange} />);
diff --git a/superset-frontend/packages/superset-ui-core/src/components/Select/Select.tsx b/superset-frontend/packages/superset-ui-core/src/components/Select/Select.tsx
index bab0e9a7394..7ba4b4bed62 100644
--- a/superset-frontend/packages/superset-ui-core/src/components/Select/Select.tsx
+++ b/superset-frontend/packages/superset-ui-core/src/components/Select/Select.tsx
@@ -91,6 +91,7 @@ const Select = forwardRef(
className,
allowClear,
allowNewOptions = false,
+ allowNewOptionsOnPaste = false,
allowSelectAll = true,
ariaLabel,
autoClearSearchValue = false,
@@ -519,7 +520,8 @@ const Select = forwardRef(
handleSelectAll();
}}
>
- {t('Select all')} {`(${formatNumber('SMART_NUMBER', bulkSelectCounts.selectable)})`}
+ {t('Select all')}{' '}
+ {`(${formatNumber('SMART_NUMBER', bulkSelectCounts.selectable)})`}
</Button>
<Button
type="link"
@@ -536,7 +538,8 @@ const Select = forwardRef(
handleDeselectAll();
}}
>
- {t('Clear')} {`(${formatNumber('SMART_NUMBER', bulkSelectCounts.deselectable)})`}
+ {t('Clear')}{' '}
+ {`(${formatNumber('SMART_NUMBER', bulkSelectCounts.deselectable)})`}
</Button>
</StyledBulkActionsContainer>
),
@@ -693,17 +696,24 @@ const Select = forwardRef(
const array = token ? uniq(pastedText.split(token)) : [pastedText];
const newOptions: SelectOptionsType = [];
+ // When `allowNewOptionsOnPaste` is set, accept pasted values that are
+ // not in the loaded options even if `allowNewOptions` is false. The
+ // full option set is searched server-side and only partially loaded
+ // client-side, so a pasted value can legitimately exist in the dataset
+ // but fall outside the loaded page.
+ const keepUnknownValues = allowNewOptions || allowNewOptionsOnPaste;
const values = array
.map(item => {
const option = getOption(item, fullSelectOptions, true);
- if (!option && allowNewOptions) {
+ if (!option && keepUnknownValues) {
const newOption = {
label: item,
value: item,
isNewOption: true,
};
newOptions.push(newOption);
+ return labelInValue ? { label: item, value: item } : item;
}
return getPastedTextValue(item);
})
diff --git a/superset-frontend/packages/superset-ui-core/src/components/Select/types.ts b/superset-frontend/packages/superset-ui-core/src/components/Select/types.ts
index 7d38dba9d81..0024465de44 100644
--- a/superset-frontend/packages/superset-ui-core/src/components/Select/types.ts
+++ b/superset-frontend/packages/superset-ui-core/src/components/Select/types.ts
@@ -88,6 +88,16 @@ export interface BaseSelectProps extends AntdExposedProps {
* False by default.
* */
allowNewOptions?: boolean;
+ /**
+ * Accept values pasted into the Select even when they are not part of the
+ * currently loaded options and `allowNewOptions` is false. Useful for
+ * selects whose full option set is searched server-side and only partially
+ * loaded on the client (e.g. dashboard filters with "Dynamically search all
+ * filter values"), where a pasted value can legitimately exist in the
+ * dataset but fall outside the loaded page.
+ * False by default.
+ * */
+ allowNewOptionsOnPaste?: boolean;
/**
* It adds the aria-label tag for accessibility standards.
* Must be plain English and localized.
diff --git a/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx
index 1ebe8fad437..a937b727a3c 100644
--- a/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx
+++ b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx
@@ -592,6 +592,7 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) {
allowClear
autoClearSearchValue
allowNewOptions={!searchAllOptions && creatable !== false}
+ allowNewOptionsOnPaste={multiSelect && searchAllOptions}
allowSelectAll={!searchAllOptions}
value={multiSelect ? filterState.value || [] : filterState.value}
disabled={isDisabled}