diff --git a/superset-frontend/src/features/databases/DatabaseModal/ExtraOptions.tsx b/superset-frontend/src/features/databases/DatabaseModal/ExtraOptions.tsx index 48cdccdb55e3..221dcdaf9c14 100644 --- a/superset-frontend/src/features/databases/DatabaseModal/ExtraOptions.tsx +++ b/superset-frontend/src/features/databases/DatabaseModal/ExtraOptions.tsx @@ -116,6 +116,15 @@ const ExtraOptions = ({ ); const [activeKey, setActiveKey] = useState(); + const [schemasText, setSchemasText] = useState(''); + useEffect(() => { + if (!db) return; + const initialSchemas = ( + (extraJson?.schemas_allowed_for_file_upload as string[] | undefined) || [] + ).join(','); + setSchemasText(initialSchemas); + }, [db?.extra]); + useEffect(() => { if (!expandableModalIsOpen && activeKey !== undefined) { setActiveKey(undefined); @@ -533,11 +542,18 @@ const ExtraOptions = ({ setSchemasText(e.target.value)} + onBlur={() => + onExtraInputChange({ + target: { + type: 'text', + name: 'schemas_allowed_for_file_upload', + value: schemasText, + }, + } as ChangeEvent) + } />
diff --git a/superset-frontend/src/features/databases/DatabaseModal/index.test.tsx b/superset-frontend/src/features/databases/DatabaseModal/index.test.tsx index c41cd8c47db1..8b3dcc222617 100644 --- a/superset-frontend/src/features/databases/DatabaseModal/index.test.tsx +++ b/superset-frontend/src/features/databases/DatabaseModal/index.test.tsx @@ -1768,12 +1768,62 @@ describe('dbReducer', () => { const currentState = dbReducer(databaseFixture, action); // extra should be serialized + expect(JSON.parse(currentState!.extra!)).toEqual({ + schemas_allowed_for_file_upload: ['bar'], + }); + }); + + test(`it will set state to payload from extra + input change when schemas_allowed_for_file_upload + with trailing comma preserves empty string`, () => { + const action: DBReducerActionType = { + type: ActionType.ExtraInputChange, + payload: { name: 'schemas_allowed_for_file_upload', value: 'bar,' }, + }; + const currentState = dbReducer(databaseFixture, action); + expect(currentState).toEqual({ ...databaseFixture, extra: '{"schemas_allowed_for_file_upload":["bar"]}', }); }); + test(`it will set state to payload from extra + input change when schemas_allowed_for_file_upload + with multiple schemas and trailing comma`, () => { + const action: DBReducerActionType = { + type: ActionType.ExtraInputChange, + payload: { + name: 'schemas_allowed_for_file_upload', + value: 'schema1,schema2,', + }, + }; + const currentState = dbReducer(databaseFixture, action); + + expect(currentState).toEqual({ + ...databaseFixture, + extra: '{"schemas_allowed_for_file_upload":["schema1","schema2"]}', + }); + }); + + test(`it will set state to payload from extra + input change when schemas_allowed_for_file_upload + with double commas filters empty strings`, () => { + const action: DBReducerActionType = { + type: ActionType.ExtraInputChange, + payload: { + name: 'schemas_allowed_for_file_upload', + value: 'schema1,,schema2', + }, + }; + const currentState = dbReducer(databaseFixture, action); + + expect(currentState).toEqual({ + ...databaseFixture, + extra: '{"schemas_allowed_for_file_upload":["schema1","schema2"]}', + }); + }); + test('it will set state to payload from input change', () => { const action: DBReducerActionType = { type: ActionType.InputChange, diff --git a/superset-frontend/src/features/databases/DatabaseModal/index.tsx b/superset-frontend/src/features/databases/DatabaseModal/index.tsx index a0dae6176279..72bd70686d37 100644 --- a/superset-frontend/src/features/databases/DatabaseModal/index.tsx +++ b/superset-frontend/src/features/databases/DatabaseModal/index.tsx @@ -310,16 +310,21 @@ export function dbReducer( }; } if (action.payload.name === 'schemas_allowed_for_file_upload') { + const value = action.payload.value || ''; + const filteredSchemas = value + .split(',') + .map(s => s.trim()) + .filter(s => s.length > 0); + return { ...trimmedState, extra: JSON.stringify({ ...extraJson, - schemas_allowed_for_file_upload: (action.payload.value || '') - .split(',') - .filter(schema => schema !== ''), + schemas_allowed_for_file_upload: filteredSchemas, }), }; } + if (action.payload.name === 'http_path') { return { ...trimmedState,