This is an automated email from the ASF dual-hosted git repository. tai pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-superset.git
The following commit(s) were added to refs/heads/master by this push: new d187d28 fix: fetch all owners for dashboard, chart listview filters and properties modal (#9784) d187d28 is described below commit d187d2887ea9348ffbc6de277ab56a1e0abab0f1 Author: ʈᵃᵢ <tdupree...@gmail.com> AuthorDate: Wed Jun 3 19:57:03 2020 -0700 fix: fetch all owners for dashboard, chart listview filters and properties modal (#9784) --- .../javascripts/views/chartList/ChartList_spec.jsx | 2 +- .../views/dashboardList/DashboardList_spec.jsx | 2 +- .../views/datasetList/DatasetList_spec.jsx | 2 +- .../src/components/ListView/Filters.tsx | 2 +- superset-frontend/src/components/ListView/types.ts | 6 +- superset-frontend/src/components/ListView/utils.ts | 1 + .../src/explore/components/PropertiesModal.tsx | 6 +- .../src/views/chartList/ChartList.tsx | 71 +++++++++++------- .../src/views/dashboardList/DashboardList.tsx | 83 +++++++++++++--------- .../src/views/datasetList/DatasetList.tsx | 9 +-- 10 files changed, 116 insertions(+), 68 deletions(-) diff --git a/superset-frontend/spec/javascripts/views/chartList/ChartList_spec.jsx b/superset-frontend/spec/javascripts/views/chartList/ChartList_spec.jsx index faf0c09..d5785bf 100644 --- a/superset-frontend/spec/javascripts/views/chartList/ChartList_spec.jsx +++ b/superset-frontend/spec/javascripts/views/chartList/ChartList_spec.jsx @@ -102,7 +102,7 @@ describe('ChartList', () => { const callsD = fetchMock.calls(/chart\/\?q/); expect(callsD).toHaveLength(1); expect(callsD[0][0]).toMatchInlineSnapshot( - `"/http//localhost/api/v1/chart/?q={%22order_column%22:%22changed_on%22,%22order_direction%22:%22desc%22,%22page%22:0,%22page_size%22:25}"`, + `"/http//localhost/api/v1/chart/?q=(order_column:changed_on,order_direction:desc,page:0,page_size:25)"`, ); }); }); diff --git a/superset-frontend/spec/javascripts/views/dashboardList/DashboardList_spec.jsx b/superset-frontend/spec/javascripts/views/dashboardList/DashboardList_spec.jsx index 5dbcb81..086d9d1 100644 --- a/superset-frontend/spec/javascripts/views/dashboardList/DashboardList_spec.jsx +++ b/superset-frontend/spec/javascripts/views/dashboardList/DashboardList_spec.jsx @@ -92,7 +92,7 @@ describe('DashboardList', () => { const callsD = fetchMock.calls(/dashboard\/\?q/); expect(callsD).toHaveLength(1); expect(callsD[0][0]).toMatchInlineSnapshot( - `"/http//localhost/api/v1/dashboard/?q={%22order_column%22:%22changed_on%22,%22order_direction%22:%22desc%22,%22page%22:0,%22page_size%22:25}"`, + `"/http//localhost/api/v1/dashboard/?q=(order_column:changed_on,order_direction:desc,page:0,page_size:25)"`, ); }); it('edits', () => { diff --git a/superset-frontend/spec/javascripts/views/datasetList/DatasetList_spec.jsx b/superset-frontend/spec/javascripts/views/datasetList/DatasetList_spec.jsx index b7b3e58..c393a98 100644 --- a/superset-frontend/spec/javascripts/views/datasetList/DatasetList_spec.jsx +++ b/superset-frontend/spec/javascripts/views/datasetList/DatasetList_spec.jsx @@ -92,7 +92,7 @@ describe('DatasetList', () => { const callsD = fetchMock.calls(/dataset\/\?q/); expect(callsD).toHaveLength(1); expect(callsD[0][0]).toMatchInlineSnapshot( - `"/http//localhost/api/v1/dataset/?q={%22order_column%22:%22changed_on%22,%22order_direction%22:%22desc%22,%22page%22:0,%22page_size%22:25}"`, + `"/http//localhost/api/v1/dataset/?q=(order_column:changed_on,order_direction:desc,page:0,page_size:25)"`, ); }); }); diff --git a/superset-frontend/src/components/ListView/Filters.tsx b/superset-frontend/src/components/ListView/Filters.tsx index a97e498..69421d5 100644 --- a/superset-frontend/src/components/ListView/Filters.tsx +++ b/superset-frontend/src/components/ListView/Filters.tsx @@ -116,7 +116,7 @@ function SelectFilter({ // TODO: allow real async search with `inputValue` if (optionsCache.current) return optionsCache.current; if (fetchSelects) { - const selectValues = await fetchSelects(); + const selectValues = await fetchSelects(inputValue); // update matching option at initial load const matchingOption = result.find(x => x.value === initialValue); if (matchingOption) { diff --git a/superset-frontend/src/components/ListView/types.ts b/superset-frontend/src/components/ListView/types.ts index 0a1cc24..3df36a8 100644 --- a/superset-frontend/src/components/ListView/types.ts +++ b/superset-frontend/src/components/ListView/types.ts @@ -37,7 +37,11 @@ export interface Filter { unfilteredLabel?: string; selects?: SelectOption[]; onFilterOpen?: () => void; - fetchSelects?: () => Promise<SelectOption[]>; + fetchSelects?: ( + filterValue?: string, + pageIndex?: number, + pageSize?: number, + ) => Promise<SelectOption[]>; } export type Filters = Filter[]; diff --git a/superset-frontend/src/components/ListView/utils.ts b/superset-frontend/src/components/ListView/utils.ts index 6ce2665..c77d05b 100644 --- a/superset-frontend/src/components/ListView/utils.ts +++ b/superset-frontend/src/components/ListView/utils.ts @@ -245,6 +245,7 @@ export function useListViewState({ const updatedFilters = updateInList(internalFilters, index, update); setInternalFilters(updatedFilters); setAllFilters(convertFilters(updatedFilters)); + gotoPage(0); // clear pagination on filter }; const removeFilterAndApply = (index: number) => { diff --git a/superset-frontend/src/explore/components/PropertiesModal.tsx b/superset-frontend/src/explore/components/PropertiesModal.tsx index 3a42cc8..622d5cf 100644 --- a/superset-frontend/src/explore/components/PropertiesModal.tsx +++ b/superset-frontend/src/explore/components/PropertiesModal.tsx @@ -120,7 +120,11 @@ function PropertiesModal({ slice, onHide, onSave }: InternalProps) { }, []); const loadOptions = (input = '') => { - const query = rison.encode({ filter: input }); + const query = rison.encode({ + filter: input, + page_index: -1, + page_size: -1, + }); return SupersetClient.get({ endpoint: `/api/v1/chart/related/owners?q=${query}`, }).then( diff --git a/superset-frontend/src/views/chartList/ChartList.tsx b/superset-frontend/src/views/chartList/ChartList.tsx index db5ed39..8fed532 100644 --- a/superset-frontend/src/views/chartList/ChartList.tsx +++ b/superset-frontend/src/views/chartList/ChartList.tsx @@ -22,6 +22,7 @@ import { getChartMetadataRegistry } from '@superset-ui/chart'; import moment from 'moment'; import PropTypes from 'prop-types'; import React from 'react'; +import rison from 'rison'; // @ts-ignore import { Panel } from 'react-bootstrap'; import ConfirmStatusChange from 'src/components/ConfirmStatusChange'; @@ -281,7 +282,7 @@ class ChartList extends React.PureComponent<Props, State> { handleBulkChartDelete = (charts: Chart[]) => { SupersetClient.delete({ - endpoint: `/api/v1/chart/?q=!(${charts.map(({ id }) => id).join(',')})`, + endpoint: `/api/v1/chart/?q=${rison.encode(charts.map(({ id }) => id))}`, }).then( ({ json = {} }) => { const { lastFetchDataConfig } = this.state; @@ -338,7 +339,7 @@ class ChartList extends React.PureComponent<Props, State> { return [...acc, fltr]; }, []); - const queryParams = JSON.stringify({ + const queryParams = rison.encode({ order_column: sortBy[0].id, order_direction: sortBy[0].desc ? 'desc' : 'asc', page: pageIndex, @@ -363,39 +364,60 @@ class ChartList extends React.PureComponent<Props, State> { }); }; - createFetchResource = ({ - resource, - postProcess, - }: { - resource: string; - postProcess?: (value: []) => any[]; - }) => async () => { + fetchOwners = async (filterValue = '', pageIndex = -1, pageSize = -1) => { + const resource = '/api/v1/chart/related/owners'; + try { + const queryParams = rison.encode({ + page: pageIndex, + page_size: pageSize, + ...(filterValue ? { filter: filterValue } : {}), + }); const { json = {} } = await SupersetClient.get({ - endpoint: resource, + endpoint: `${resource}?q=${queryParams}`, }); - return postProcess ? postProcess(json?.result) : json?.result; + + return json?.result?.map( + ({ text: label, value }: { text: string; value: any }) => ({ + label, + value, + }), + ); } catch (e) { this.props.addDangerToast( - t('An error occurred while fetching chart filters: %s', e.statusText), + t( + 'An error occurred while fetching chart owner values: %s', + e.statusText, + ), ); } return []; }; - convertOwners = (owners: any[]) => - owners.map(({ text: label, value }) => ({ label, value })); + fetchDatasets = async () => { + const resource = '/api/v1/chart/datasources'; + try { + const { json = {} } = await SupersetClient.get({ + endpoint: `${resource}`, + }); - stringifyValues = (datasources: any[]) => { - return datasources.map(ds => ({ ...ds, value: JSON.stringify(ds.value) })); + return json?.result?.map((ds: { label: string; value: any }) => ({ + ...ds, + value: JSON.stringify(ds.value), + })); + } catch (e) { + this.props.addDangerToast( + t( + 'An error occurred while fetching chart dataset values: %s', + e.statusText, + ), + ); + } + return []; }; updateFilters = async () => { const { filterOperators } = this.state; - const fetchOwners = this.createFetchResource({ - resource: '/api/v1/chart/related/owners', - postProcess: this.convertOwners, - }); if (this.isNewUIEnabled) { this.setState({ @@ -406,7 +428,7 @@ class ChartList extends React.PureComponent<Props, State> { input: 'select', operator: 'rel_m_m', unfilteredLabel: 'All', - fetchSelects: fetchOwners, + fetchSelects: this.fetchOwners, }, { Header: 'Viz Type', @@ -424,10 +446,7 @@ class ChartList extends React.PureComponent<Props, State> { input: 'select', operator: 'eq', unfilteredLabel: 'All', - fetchSelects: this.createFetchResource({ - resource: '/api/v1/chart/datasources', - postProcess: this.stringifyValues, - }), + fetchSelects: this.fetchDatasets, }, { Header: 'Search', @@ -448,7 +467,7 @@ class ChartList extends React.PureComponent<Props, State> { operator: string; }) => ({ label, value: operator }); - const owners = await fetchOwners(); + const owners = await this.fetchOwners(); this.setState({ filters: [ { diff --git a/superset-frontend/src/views/dashboardList/DashboardList.tsx b/superset-frontend/src/views/dashboardList/DashboardList.tsx index 912c76d..829c6e3 100644 --- a/superset-frontend/src/views/dashboardList/DashboardList.tsx +++ b/superset-frontend/src/views/dashboardList/DashboardList.tsx @@ -21,6 +21,7 @@ import { t } from '@superset-ui/translation'; import moment from 'moment'; import PropTypes from 'prop-types'; import React from 'react'; +import rison from 'rison'; // @ts-ignore import { Panel } from 'react-bootstrap'; import ConfirmStatusChange from 'src/components/ConfirmStatusChange'; @@ -48,7 +49,6 @@ interface State { loading: boolean; filterOperators: FilterOperatorMap; filters: Filters; - owners: Array<{ text: string; value: number }>; permissions: string[]; lastFetchDataConfig: FetchDataConfig | null; dashboardToEdit: Dashboard | null; @@ -77,44 +77,31 @@ class DashboardList extends React.PureComponent<Props, State> { filters: [], lastFetchDataConfig: null, loading: false, - owners: [], permissions: [], dashboardToEdit: null, }; componentDidMount() { - Promise.all([ - SupersetClient.get({ - endpoint: `/api/v1/dashboard/_info`, - }), - SupersetClient.get({ - endpoint: `/api/v1/dashboard/related/owners`, - }), - ]).then( - ([{ json: infoJson = {} }, { json: ownersJson = {} }]) => { + SupersetClient.get({ + endpoint: `/api/v1/dashboard/_info`, + }).then( + ({ json: infoJson = {} }) => { this.setState( { filterOperators: infoJson.filters, - owners: ownersJson.result, permissions: infoJson.permissions, }, this.updateFilters, ); }, - ([e1, e2]) => { + e => { this.props.addDangerToast( t( 'An error occurred while fetching Dashboards: %s, %s', - e1.statusText, - e1.statusText, + e.statusText, ), ); - if (e1) { - console.error(e1); - } - if (e2) { - console.error(e2); - } + console.error(e); }, ); } @@ -330,9 +317,9 @@ class DashboardList extends React.PureComponent<Props, State> { handleBulkDashboardDelete = (dashboards: Dashboard[]) => { SupersetClient.delete({ - endpoint: `/api/v1/dashboard/?q=!(${dashboards - .map(({ id }) => id) - .join(',')})`, + endpoint: `/api/v1/dashboard/?q=${rison.encode( + dashboards.map(({ id }) => id), + )}`, }).then( ({ json = {} }) => { const { lastFetchDataConfig } = this.state; @@ -355,9 +342,9 @@ class DashboardList extends React.PureComponent<Props, State> { handleBulkDashboardExport = (dashboards: Dashboard[]) => { return window.location.assign( - `/api/v1/dashboard/export/?q=!(${dashboards - .map(({ id }) => id) - .join(',')})`, + `/api/v1/dashboard/export/?q=${rison.encode( + dashboards.map(({ id }) => id).join(','), + )}`, ); }; @@ -378,7 +365,7 @@ class DashboardList extends React.PureComponent<Props, State> { value, })); - const queryParams = JSON.stringify({ + const queryParams = rison.encode({ order_column: sortBy[0].id, order_direction: sortBy[0].desc ? 'desc' : 'asc', page: pageIndex, @@ -402,8 +389,38 @@ class DashboardList extends React.PureComponent<Props, State> { }); }; - updateFilters = () => { - const { filterOperators, owners } = this.state; + fetchOwners = async (filterValue = '', pageIndex = -1, pageSize = -1) => { + const resource = '/api/v1/dashboard/related/owners'; + + try { + const queryParams = rison.encode({ + page: pageIndex, + page_size: pageSize, + ...(filterValue ? { filter: filterValue } : {}), + }); + const { json = {} } = await SupersetClient.get({ + endpoint: `${resource}?q=${queryParams}`, + }); + + return json?.result?.map( + ({ text: label, value }: { text: string; value: any }) => ({ + label, + value, + }), + ); + } catch (e) { + this.props.addDangerToast( + t( + 'An error occurred while fetching chart owner values: %s', + e.statusText, + ), + ); + } + return []; + }; + + updateFilters = async () => { + const { filterOperators } = this.state; if (this.isNewUIEnabled) { return this.setState({ @@ -414,7 +431,7 @@ class DashboardList extends React.PureComponent<Props, State> { input: 'select', operator: 'rel_m_m', unfilteredLabel: 'All', - selects: owners.map(({ text: label, value }) => ({ label, value })), + fetchSelects: this.fetchOwners, }, { Header: 'Published', @@ -445,6 +462,8 @@ class DashboardList extends React.PureComponent<Props, State> { operator: string; }) => ({ label, value: operator }); + const owners = await this.fetchOwners(); + return this.setState({ filters: [ { @@ -462,7 +481,7 @@ class DashboardList extends React.PureComponent<Props, State> { id: 'owners', input: 'select', operators: filterOperators.owners.map(convertFilter), - selects: owners.map(({ text: label, value }) => ({ label, value })), + selects: owners, }, { Header: 'Published', diff --git a/superset-frontend/src/views/datasetList/DatasetList.tsx b/superset-frontend/src/views/datasetList/DatasetList.tsx index 43821b0..c832290 100644 --- a/superset-frontend/src/views/datasetList/DatasetList.tsx +++ b/superset-frontend/src/views/datasetList/DatasetList.tsx @@ -21,6 +21,7 @@ import { t } from '@superset-ui/translation'; import moment from 'moment'; import PropTypes from 'prop-types'; import React from 'react'; +import rison from 'rison'; // @ts-ignore import { Panel } from 'react-bootstrap'; import Link from 'src/components/Link'; @@ -273,9 +274,9 @@ class DatasetList extends React.PureComponent<Props, State> { handleBulkDatasetDelete = (datasets: Dataset[]) => { SupersetClient.delete({ - endpoint: `/api/v1/dataset/?q=!(${datasets - .map(({ id }) => id) - .join(',')})`, + endpoint: `/api/v1/dataset/?q=${rison.encode( + datasets.map(({ id }) => id), + )}`, }).then( ({ json = {} }) => { const { lastFetchDataConfig } = this.state; @@ -310,7 +311,7 @@ class DatasetList extends React.PureComponent<Props, State> { value, })); - const queryParams = JSON.stringify({ + const queryParams = rison.encode({ order_column: sortBy[0].id, order_direction: sortBy[0].desc ? 'desc' : 'asc', page: pageIndex,