diff --git a/superset-frontend/spec/javascripts/views/CRUD/data/dataset/DatasetList_spec.jsx b/superset-frontend/spec/javascripts/views/CRUD/data/dataset/DatasetList_spec.jsx index db49a0ff4691d..ae6be2e7a35eb 100644 --- a/superset-frontend/spec/javascripts/views/CRUD/data/dataset/DatasetList_spec.jsx +++ b/superset-frontend/spec/javascripts/views/CRUD/data/dataset/DatasetList_spec.jsx @@ -35,6 +35,7 @@ const store = mockStore({}); const datasetsInfoEndpoint = 'glob:*/api/v1/dataset/_info*'; const datasetsOwnersEndpoint = 'glob:*/api/v1/dataset/related/owners*'; +const datasetsSchemaEndpoint = 'glob:*/api/v1/dataset/distinct/schema*'; const databaseEndpoint = 'glob:*/api/v1/dataset/related/database*'; const datasetsEndpoint = 'glob:*/api/v1/dataset/?*'; @@ -57,6 +58,9 @@ fetchMock.get(datasetsInfoEndpoint, { fetchMock.get(datasetsOwnersEndpoint, { result: [], }); +fetchMock.get(datasetsSchemaEndpoint, { + result: [], +}); fetchMock.get(datasetsEndpoint, { result: mockdatasets, dataset_count: 3, @@ -97,12 +101,20 @@ describe('DatasetList', () => { it('fetches data', () => { const callsD = fetchMock.calls(/dataset\/\?q/); - expect(callsD).toHaveLength(2); - expect(callsD[1][0]).toMatchInlineSnapshot( + expect(callsD).toHaveLength(1); + expect(callsD[0][0]).toMatchInlineSnapshot( `"http://localhost/api/v1/dataset/?q=(order_column:changed_on_delta_humanized,order_direction:desc,page:0,page_size:25)"`, ); }); + it('fetches owner filter values', () => { + expect(fetchMock.calls(/dataset\/related\/owners/)).toHaveLength(1); + }); + + it('fetches schema filter values', () => { + expect(fetchMock.calls(/dataset\/distinct\/schema/)).toHaveLength(1); + }); + it('shows/hides bulk actions when bulk actions is clicked', async () => { await waitForComponentToPaint(wrapper); const button = wrapper.find(Button).at(0); diff --git a/superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx b/superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx index 8ef6b7fca35de..e05413c02780a 100644 --- a/superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx +++ b/superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx @@ -20,7 +20,11 @@ import { SupersetClient } from '@superset-ui/connection'; import { t } from '@superset-ui/translation'; import React, { FunctionComponent, useState, useMemo } from 'react'; import rison from 'rison'; -import { createFetchRelated, createErrorHandler } from 'src/views/CRUD/utils'; +import { + createFetchRelated, + createFetchDistinct, + createErrorHandler, +} from 'src/views/CRUD/utils'; import { useListViewResource } from 'src/views/CRUD/hooks'; import ConfirmStatusChange from 'src/components/ConfirmStatusChange'; import DatasourceModal from 'src/datasource/DatasourceModal'; @@ -59,40 +63,6 @@ interface DatasetListProps { addSuccessToast: (msg: string) => void; } -export const createFetchSchemas = ( - handleError: (error: Response) => void, -) => async (filterValue = '', pageIndex?: number, pageSize?: number) => { - // add filters if filterValue - const filters = filterValue - ? { filters: [{ col: 'schema', opr: 'sw', value: filterValue }] } - : {}; - try { - const queryParams = rison.encode({ - columns: ['schema'], - keys: ['none'], - order_by: 'schema', - ...(pageIndex ? { page: pageIndex } : {}), - ...(pageSize ? { page_size: pageSize } : {}), - ...filters, - }); - const { json = {} } = await SupersetClient.get({ - endpoint: `/api/v1/dataset/?q=${queryParams}`, - }); - - const schemas: string[] = json?.result?.map( - ({ schema }: { schema: string }) => schema, - ); - - // uniqueify schema values and create options - return [...new Set(schemas)] - .filter(schema => Boolean(schema)) - .map(schema => ({ label: schema, value: schema })); - } catch (e) { - handleError(e); - } - return []; -}; - const DatasetList: FunctionComponent = ({ addDangerToast, addSuccessToast, @@ -393,8 +363,12 @@ const DatasetList: FunctionComponent = ({ input: 'select', operator: 'eq', unfilteredLabel: 'All', - fetchSelects: createFetchSchemas(errMsg => - t('An error occurred while fetching schema values: %s', errMsg), + fetchSelects: createFetchDistinct( + 'dataset', + 'schema', + createErrorHandler(errMsg => + t('An error occurred while fetching schema values: %s', errMsg), + ), ), paginate: true, }, diff --git a/superset-frontend/src/views/CRUD/utils.tsx b/superset-frontend/src/views/CRUD/utils.tsx index 2bced467bb3c3..17377eae00593 100644 --- a/superset-frontend/src/views/CRUD/utils.tsx +++ b/superset-frontend/src/views/CRUD/utils.tsx @@ -24,12 +24,12 @@ import rison from 'rison'; import getClientErrorObject from 'src/utils/getClientErrorObject'; import { logging } from '@superset-ui/core'; -export const createFetchRelated = ( +const createFetchResourceMethod = (method: string) => ( resource: string, relation: string, handleError: (error: Response) => void, ) => async (filterValue = '', pageIndex?: number, pageSize?: number) => { - const resourceEndpoint = `/api/v1/${resource}/related/${relation}`; + const resourceEndpoint = `/api/v1/${resource}/${method}/${relation}`; try { const queryParams = rison.encode({ @@ -53,6 +53,9 @@ export const createFetchRelated = ( return []; }; +export const createFetchRelated = createFetchResourceMethod('related'); +export const createFetchDistinct = createFetchResourceMethod('distinct'); + export function createErrorHandler(handleErrorFunc: (errMsg?: string) => void) { return async (e: SupersetClientResponse | string) => { const parsedError = await getClientErrorObject(e); diff --git a/superset/views/base_api.py b/superset/views/base_api.py index a4707876dc282..6ee2016cf2c8a 100644 --- a/superset/views/base_api.py +++ b/superset/views/base_api.py @@ -415,5 +415,9 @@ def distinct(self, column_name: str, **kwargs: Any) -> FlaskResponse: # Apply pagination result = self.datamodel.apply_pagination(query, page, page_size).all() # produce response - result = [{"text": item[0]} for item in result if item[0] is not None] + result = [ + {"text": item[0], "value": item[0]} + for item in result + if item[0] is not None + ] return self.response(200, count=count, result=result) diff --git a/tests/datasets/api_tests.py b/tests/datasets/api_tests.py index 71d38677386ab..ed6b76935079b 100644 --- a/tests/datasets/api_tests.py +++ b/tests/datasets/api_tests.py @@ -192,15 +192,16 @@ def pg_test_query_parameter(query_parameter, expected_response): "columns", "information_schema", [], get_main_database() ) ) + schema_values = [ + "", + "admin_database", + "information_schema", + "public", + "superset", + ] expected_response = { "count": 5, - "result": [ - {"text": ""}, - {"text": "admin_database"}, - {"text": "information_schema"}, - {"text": "public"}, - {"text": "superset"}, - ], + "result": [{"text": val, "value": val} for val in schema_values], } self.login(username="admin") uri = "api/v1/dataset/distinct/schema" @@ -213,17 +214,26 @@ def pg_test_query_parameter(query_parameter, expected_response): query_parameter = {"filter": "inf"} pg_test_query_parameter( query_parameter, - {"count": 1, "result": [{"text": "information_schema"}]}, + { + "count": 1, + "result": [ + {"text": "information_schema", "value": "information_schema"} + ], + }, ) query_parameter = {"page": 0, "page_size": 1} pg_test_query_parameter( - query_parameter, {"count": 5, "result": [{"text": ""}]}, + query_parameter, {"count": 5, "result": [{"text": "", "value": ""}]}, ) query_parameter = {"page": 1, "page_size": 1} pg_test_query_parameter( - query_parameter, {"count": 5, "result": [{"text": "admin_database"}]} + query_parameter, + { + "count": 5, + "result": [{"text": "admin_database", "value": "admin_database"}], + }, ) for dataset in datasets: