This is an automated email from the ASF dual-hosted git repository.

diegopucci pushed a commit to branch geido/feat/disable-creatable-filter-value
in repository https://gitbox.apache.org/repos/asf/superset.git

commit f321f7af5166f7f2617e6673a86911afabe7ea98
Author: Diego Pucci <[email protected]>
AuthorDate: Tue Apr 8 16:39:04 2025 +0300

    feat(Native Filters): Configure creatable filter behavior
---
 .../cypress/e2e/dashboard/shared_dashboard_functions.ts    |  1 +
 superset-frontend/cypress-base/cypress/support/e2e.ts      |  2 +-
 superset-frontend/spec/fixtures/mockNativeFilters.ts       |  3 +++
 .../FiltersConfigForm/FiltersConfigForm.tsx                |  1 +
 .../components/Select/SelectFilterPlugin.stories.tsx       |  4 ++++
 .../filters/components/Select/SelectFilterPlugin.test.tsx  | 13 +++++++++++++
 .../src/filters/components/Select/SelectFilterPlugin.tsx   |  3 ++-
 .../src/filters/components/Select/buildQuery.test.ts       |  1 +
 .../src/filters/components/Select/controlPanel.ts          | 14 ++++++++++++++
 superset-frontend/src/filters/components/Select/types.ts   |  2 ++
 10 files changed, 42 insertions(+), 2 deletions(-)

diff --git 
a/superset-frontend/cypress-base/cypress/e2e/dashboard/shared_dashboard_functions.ts
 
b/superset-frontend/cypress-base/cypress/e2e/dashboard/shared_dashboard_functions.ts
index b0f7853e94..595bf45da0 100644
--- 
a/superset-frontend/cypress-base/cypress/e2e/dashboard/shared_dashboard_functions.ts
+++ 
b/superset-frontend/cypress-base/cypress/e2e/dashboard/shared_dashboard_functions.ts
@@ -55,6 +55,7 @@ export function prepareDashboardFilters(
         controlValues: {
           enableEmptyFilter: false,
           defaultToFirstItem: false,
+          creatable: true,
           multiSelect: true,
           searchAllOptions: false,
           inverseSelection: false,
diff --git a/superset-frontend/cypress-base/cypress/support/e2e.ts 
b/superset-frontend/cypress-base/cypress/support/e2e.ts
index 18572b6ab2..17ac14c7e6 100644
--- a/superset-frontend/cypress-base/cypress/support/e2e.ts
+++ b/superset-frontend/cypress-base/cypress/support/e2e.ts
@@ -166,7 +166,7 @@ Cypress.Commands.add('login', () => {
   cy.request({
     method: 'POST',
     url: '/login/',
-    body: { username: 'admin', password: 'general' },
+    body: { username: 'admin', password: 'admin' },
   }).then(response => {
     if (response.status === 302) {
       // If there's a redirect, follow it manually
diff --git a/superset-frontend/spec/fixtures/mockNativeFilters.ts 
b/superset-frontend/spec/fixtures/mockNativeFilters.ts
index b83cdcc8dc..414935c8b3 100644
--- a/superset-frontend/spec/fixtures/mockNativeFilters.ts
+++ b/superset-frontend/spec/fixtures/mockNativeFilters.ts
@@ -48,6 +48,7 @@ export const nativeFilters: NativeFiltersState = {
         excluded: [],
       },
       controlValues: {
+        creatable: false,
         multiSelect: false,
         enableEmptyFilter: false,
         inverseSelection: false,
@@ -79,6 +80,7 @@ export const nativeFilters: NativeFiltersState = {
         excluded: [],
       },
       controlValues: {
+        creatable: false,
         multiSelect: false,
         enableEmptyFilter: false,
         inverseSelection: false,
@@ -463,6 +465,7 @@ export const buildNativeFilter = (
 ) => ({
   id,
   controlValues: {
+    creatable: true,
     multiSelect: true,
     enableEmptyFilter: false,
     defaultToFirstItem: false,
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
index 7ef4e6bacb..01effc9aa1 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
@@ -136,6 +136,7 @@ type ControlKey = keyof PluginFilterSelectCustomizeProps;
 const controlsOrder: ControlKey[] = [
   'enableEmptyFilter',
   'defaultToFirstItem',
+  'creatable',
   'multiSelect',
   'searchAllOptions',
   'inverseSelection',
diff --git 
a/superset-frontend/src/filters/components/Select/SelectFilterPlugin.stories.tsx
 
b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.stories.tsx
index 55808ad6ad..46e056b5ff 100644
--- 
a/superset-frontend/src/filters/components/Select/SelectFilterPlugin.stories.tsx
+++ 
b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.stories.tsx
@@ -29,17 +29,20 @@ 
getChartTransformPropsRegistry().registerValue('filter_select', transformProps);
 export default {
   title: 'Filter Plugins',
   argTypes: {
+    creatable: { control: 'boolean', defaultValue: true },
     multiSelect: { control: 'boolean', defaultValue: true },
     inverseSelection: { control: 'boolean', defaultValue: false },
   },
 };
 
 export const Select = ({
+  creatable,
   multiSeelct,
   inverseSelection,
   width,
   height,
 }: {
+  creatable: boolean;
   multiSeelct: boolean;
   inverseSelection: boolean;
   width: number;
@@ -53,6 +56,7 @@ export const Select = ({
     formData={{
       adhoc_filters: [],
       extra_filters: [],
+      creatable,
       multiSelect: { multiSeelct },
       inverseSelection: { inverseSelection },
       row_limit: 1000,
diff --git 
a/superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.tsx 
b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.tsx
index 8b88ebba69..ec6b33d95b 100644
--- 
a/superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.tsx
+++ 
b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.tsx
@@ -27,6 +27,7 @@ jest.useFakeTimers();
 const selectMultipleProps = {
   formData: {
     sortAscending: true,
+    creatable: false,
     multiSelect: true,
     enableEmptyFilter: true,
     defaultToFirstItem: false,
@@ -259,4 +260,16 @@ describe('SelectFilterPlugin', () => {
     await userEvent.type(screen.getByRole('combobox'), '1');
     expect(screen.queryByLabelText(String(bigValue))).toBeInTheDocument();
   });
+
+  test('Should not allow for new values when creatable is false', () => {
+    getWrapper({ creatable: false });
+    userEvent.type(screen.getByRole('combobox'), 'new value');
+    expect(screen.queryByTitle('new value')).not.toBeInTheDocument();
+  });
+
+  test('Should allow for new values when creatable is false', async () => {
+    getWrapper({ creatable: true });
+    userEvent.type(screen.getByRole('combobox'), 'new value');
+    expect(await screen.findByTitle('new value')).toBeInTheDocument();
+  });
 });
diff --git 
a/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx 
b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx
index 23447fb295..ca8fbda8df 100644
--- a/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx
+++ b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx
@@ -100,6 +100,7 @@ export default function PluginFilterSelect(props: 
PluginFilterSelectProps) {
   } = props;
   const {
     enableEmptyFilter,
+    creatable,
     multiSelect,
     showSearch,
     inverseSelection,
@@ -296,7 +297,7 @@ export default function PluginFilterSelect(props: 
PluginFilterSelectProps) {
         <Select
           name={formData.nativeFilterId}
           allowClear
-          allowNewOptions={!searchAllOptions}
+          allowNewOptions={!searchAllOptions && creatable !== false}
           allowSelectAll={!searchAllOptions}
           // @ts-ignore
           value={filterState.value || []}
diff --git a/superset-frontend/src/filters/components/Select/buildQuery.test.ts 
b/superset-frontend/src/filters/components/Select/buildQuery.test.ts
index 151b4dbd8c..3f7fc0da5c 100644
--- a/superset-frontend/src/filters/components/Select/buildQuery.test.ts
+++ b/superset-frontend/src/filters/components/Select/buildQuery.test.ts
@@ -30,6 +30,7 @@ describe('Select buildQuery', () => {
     filters: undefined,
     enableEmptyFilter: false,
     inverseSelection: false,
+    creatable: false,
     multiSelect: false,
     defaultToFirstItem: false,
     searchAllOptions: false,
diff --git a/superset-frontend/src/filters/components/Select/controlPanel.ts 
b/superset-frontend/src/filters/components/Select/controlPanel.ts
index be01821760..a43e3bd2ae 100644
--- a/superset-frontend/src/filters/components/Select/controlPanel.ts
+++ b/superset-frontend/src/filters/components/Select/controlPanel.ts
@@ -27,6 +27,7 @@ const {
   enableEmptyFilter,
   inverseSelection,
   multiSelect,
+  creatable,
   defaultToFirstItem,
   searchAllOptions,
   sortAscending,
@@ -66,6 +67,19 @@ const config: ControlPanelConfig = {
             },
           },
         ],
+        [
+          {
+            name: 'creatable',
+            config: {
+              type: 'CheckboxControl',
+              label: t('Allow creation of new values'),
+              default: creatable,
+              resetConfig: true,
+              affectsDataMask: true,
+              renderTrigger: true,
+            },
+          },
+        ],
         [
           {
             name: 'multiSelect',
diff --git a/superset-frontend/src/filters/components/Select/types.ts 
b/superset-frontend/src/filters/components/Select/types.ts
index e608f59640..896bcf16cc 100644
--- a/superset-frontend/src/filters/components/Select/types.ts
+++ b/superset-frontend/src/filters/components/Select/types.ts
@@ -36,6 +36,7 @@ export interface PluginFilterSelectCustomizeProps {
   defaultValue?: SelectValue;
   enableEmptyFilter: boolean;
   inverseSelection: boolean;
+  creatable: boolean;
   multiSelect: boolean;
   defaultToFirstItem: boolean;
   searchAllOptions: boolean;
@@ -71,6 +72,7 @@ export const DEFAULT_FORM_DATA: 
PluginFilterSelectCustomizeProps = {
   enableEmptyFilter: false,
   inverseSelection: false,
   defaultToFirstItem: false,
+  creatable: true,
   multiSelect: true,
   searchAllOptions: false,
   sortAscending: true,

Reply via email to