diff --git a/superset-frontend/spec/javascripts/views/CRUD/welcome/SavedQueries_spec.tsx b/superset-frontend/spec/javascripts/views/CRUD/welcome/SavedQueries_spec.tsx index 1ef5748c43..1abd3cd5c4 100644 --- a/superset-frontend/spec/javascripts/views/CRUD/welcome/SavedQueries_spec.tsx +++ b/superset-frontend/spec/javascripts/views/CRUD/welcome/SavedQueries_spec.tsx @@ -96,7 +96,7 @@ describe('SavedQueries', () => { expect(wrapper.find(SavedQueries)).toExist(); }); - it('fetches queries favorites and renders listviewcard cards', async () => { + it('fetches queries mine and renders listviewcard cards', async () => { clickTab(0); await waitForComponentToPaint(wrapper); expect(fetchMock.calls(/saved_query\/\?q/)).toHaveLength(1); @@ -105,9 +105,9 @@ describe('SavedQueries', () => { it('it renders a submenu with clickable tables and buttons', async () => { expect(wrapper.find(SubMenu)).toExist(); - expect(wrapper.find('li')).toHaveLength(2); + expect(wrapper.find('li')).toHaveLength(1); expect(wrapper.find('button')).toHaveLength(2); - clickTab(1); + clickTab(0); await waitForComponentToPaint(wrapper); expect(fetchMock.calls(/saved_query\/\?q/)).toHaveLength(2); }); diff --git a/superset-frontend/src/components/ListView/types.ts b/superset-frontend/src/components/ListView/types.ts index 4f2a867a77..f73b177c1f 100644 --- a/superset-frontend/src/components/ListView/types.ts +++ b/superset-frontend/src/components/ListView/types.ts @@ -55,11 +55,14 @@ type FilterOperator = | 'all_text' | 'chart_all_text' | 'dataset_is_null_or_empty' - | 'between'; + | 'between' + | 'dashboard_is_fav' + | 'chart_is_fav'; export interface Filter { Header: ReactNode; id: string; + urlDisplay?: string; operator?: FilterOperator; input?: | 'text' @@ -85,6 +88,7 @@ export type ViewModeType = 'card' | 'table'; export interface FilterValue { id: string; + urlDisplay?: string; operator?: string; value: string | boolean | number | null | undefined | string[] | number[]; } @@ -119,4 +123,6 @@ export enum FilterOperators { chartAllText = 'chart_all_text', datasetIsNullOrEmpty = 'dataset_is_null_or_empty', between = 'between', + dashboardIsFav = 'dashboard_is_fav', + chartIsFav = 'chart_is_fav', } diff --git a/superset-frontend/src/components/ListView/utils.ts b/superset-frontend/src/components/ListView/utils.ts index af935234c9..6cfdd67c55 100644 --- a/superset-frontend/src/components/ListView/utils.ts +++ b/superset-frontend/src/components/ListView/utils.ts @@ -80,10 +80,11 @@ type QueryFilterState = { }; function mergeCreateFilterValues(list: Filter[], updateObj: QueryFilterState) { - return list.map(({ id, operator }) => { - const update = updateObj[id]; + return list.map(({ id, urlDisplay, operator }) => { + const currentFilterId = urlDisplay || id; + const update = updateObj[currentFilterId]; - return { id, operator, value: update }; + return { id, urlDisplay, operator, value: update }; }); } @@ -143,10 +144,12 @@ export function convertFiltersRison( // Add operators from filter list list.forEach(value => { - const filter = refs[value.id]; + const currentFilterId = value.urlDisplay || value.id; + const filter = refs[currentFilterId]; if (filter) { filter.operator = value.operator; + filter.id = value.id; } }); @@ -294,7 +297,8 @@ export function useListViewState({ filter.value !== undefined && (typeof filter.value !== 'string' || filter.value.length > 0) ) { - filterObj[filter.id] = filter.value; + const currentFilterId = filter.urlDisplay || filter.id; + filterObj[currentFilterId] = filter.value; } }); @@ -318,6 +322,7 @@ export function useListViewState({ : 'replace'; setQuery(queryParams, method); + fetchData({ pageIndex, pageSize, sortBy, filters }); }, [fetchData, pageIndex, pageSize, sortBy, filters, viewMode]); @@ -333,12 +338,14 @@ export function useListViewState({ if (currentInternalFilters[index].value === value) { return currentInternalFilters; } + const update = { ...currentInternalFilters[index], value }; const updatedFilters = updateInList( currentInternalFilters, index, update, ); + setAllFilters(convertFilters(updatedFilters)); gotoPage(0); // clear pagination on filter return updatedFilters; diff --git a/superset-frontend/src/views/CRUD/chart/ChartList.tsx b/superset-frontend/src/views/CRUD/chart/ChartList.tsx index 13d27403a6..018d551b5d 100644 --- a/superset-frontend/src/views/CRUD/chart/ChartList.tsx +++ b/superset-frontend/src/views/CRUD/chart/ChartList.tsx @@ -40,6 +40,7 @@ import ListView, { ListViewProps, Filters, SelectOption, + FilterOperators, } from 'src/components/ListView'; import withToasts from 'src/messageToasts/enhancers/withToasts'; import PropertiesModal from 'src/explore/components/PropertiesModal'; @@ -195,7 +196,7 @@ function ChartList(props: ChartListProps) { /> ), Header: '', - id: 'favorite', + id: 'id', disableSortBy: true, size: 'xs', }, @@ -367,7 +368,7 @@ function ChartList(props: ChartListProps) { Header: t('Owner'), id: 'owners', input: 'select', - operator: 'rel_m_m', + operator: FilterOperators.relationManyMany, unfilteredLabel: 'All', fetchSelects: createFetchRelated( 'chart', @@ -388,7 +389,7 @@ function ChartList(props: ChartListProps) { Header: t('Created By'), id: 'created_by', input: 'select', - operator: 'rel_o_m', + operator: FilterOperators.relationOneMany, unfilteredLabel: 'All', fetchSelects: createFetchRelated( 'chart', @@ -409,7 +410,7 @@ function ChartList(props: ChartListProps) { Header: t('Viz Type'), id: 'viz_type', input: 'select', - operator: 'eq', + operator: FilterOperators.equals, unfilteredLabel: 'All', selects: getChartMetadataRegistry() .keys() @@ -433,7 +434,7 @@ function ChartList(props: ChartListProps) { Header: t('Dataset'), id: 'datasource_id', input: 'select', - operator: 'eq', + operator: FilterOperators.equals, unfilteredLabel: 'All', fetchSelects: createFetchDatasets( createErrorHandler(errMsg => @@ -447,11 +448,23 @@ function ChartList(props: ChartListProps) { ), paginate: false, }, + { + Header: t('Favorite'), + id: 'id', + urlDisplay: 'favorite', + input: 'select', + operator: FilterOperators.chartIsFav, + unfilteredLabel: 'Any', + selects: [ + { label: t('Yes'), value: true }, + { label: t('No'), value: false }, + ], + }, { Header: t('Search'), id: 'slice_name', input: 'search', - operator: 'chart_all_text', + operator: FilterOperators.chartAllText, }, ]; diff --git a/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx b/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx index 6b440d461d..b1b2f542f2 100644 --- a/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx +++ b/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx @@ -29,7 +29,11 @@ import { import { useListViewResource, useFavoriteStatus } from 'src/views/CRUD/hooks'; import ConfirmStatusChange from 'src/components/ConfirmStatusChange'; import SubMenu, { SubMenuProps } from 'src/components/Menu/SubMenu'; -import ListView, { ListViewProps, Filters } from 'src/components/ListView'; +import ListView, { + ListViewProps, + Filters, + FilterOperators, +} from 'src/components/ListView'; import Owner from 'src/types/Owner'; import withToasts from 'src/messageToasts/enhancers/withToasts'; import FacePile from 'src/components/FacePile'; @@ -104,6 +108,7 @@ function DashboardList(props: DashboardListProps) { dashboardIds, addDangerToast, ); + const [dashboardToEdit, setDashboardToEdit] = useState( null, ); @@ -189,7 +194,7 @@ function DashboardList(props: DashboardListProps) { /> ), Header: '', - id: 'favorite', + id: 'id', disableSortBy: true, size: 'xs', }, @@ -354,7 +359,7 @@ function DashboardList(props: DashboardListProps) { Header: t('Owner'), id: 'owners', input: 'select', - operator: 'rel_m_m', + operator: FilterOperators.relationManyMany, unfilteredLabel: 'All', fetchSelects: createFetchRelated( 'dashboard', @@ -375,7 +380,7 @@ function DashboardList(props: DashboardListProps) { Header: t('Created By'), id: 'created_by', input: 'select', - operator: 'rel_o_m', + operator: FilterOperators.relationOneMany, unfilteredLabel: 'All', fetchSelects: createFetchRelated( 'dashboard', @@ -396,18 +401,30 @@ function DashboardList(props: DashboardListProps) { Header: t('Status'), id: 'published', input: 'select', - operator: 'eq', + operator: FilterOperators.equals, unfilteredLabel: 'Any', selects: [ { label: t('Published'), value: true }, { label: t('Unpublished'), value: false }, ], }, + { + Header: t('Favorite'), + id: 'id', + urlDisplay: 'favorite', + input: 'select', + operator: FilterOperators.dashboardIsFav, + unfilteredLabel: 'Any', + selects: [ + { label: t('Yes'), value: true }, + { label: t('No'), value: false }, + ], + }, { Header: t('Search'), id: 'dashboard_title', input: 'search', - operator: 'title_or_slug', + operator: FilterOperators.titleOrSlug, }, ]; diff --git a/superset-frontend/src/views/CRUD/hooks.ts b/superset-frontend/src/views/CRUD/hooks.ts index 410e0d8a84..9799eac575 100644 --- a/superset-frontend/src/views/CRUD/hooks.ts +++ b/superset-frontend/src/views/CRUD/hooks.ts @@ -115,8 +115,8 @@ export function useListViewResource( const filterExps = (baseFilters || []) .concat(filterValues) - .map(({ id: col, operator: opr, value }) => ({ - col, + .map(({ id, operator: opr, value }) => ({ + col: id, opr, value, })); diff --git a/superset-frontend/src/views/CRUD/welcome/ChartTable.tsx b/superset-frontend/src/views/CRUD/welcome/ChartTable.tsx index d6cca205e8..cbf351f43d 100644 --- a/superset-frontend/src/views/CRUD/welcome/ChartTable.tsx +++ b/superset-frontend/src/views/CRUD/welcome/ChartTable.tsx @@ -24,6 +24,7 @@ import { useFavoriteStatus, } from 'src/views/CRUD/hooks'; import withToasts from 'src/messageToasts/enhancers/withToasts'; +import { useHistory } from 'react-router-dom'; import PropertiesModal from 'src/explore/components/PropertiesModal'; import { User } from 'src/types/bootstrapTypes'; import Icon from 'src/components/Icon'; @@ -50,6 +51,7 @@ function ChartTable({ addSuccessToast, mine, }: ChartTableProps) { + const history = useHistory(); const { state: { resourceCollection: charts, bulkSelectEnabled }, setResourceCollection: setCharts, @@ -148,14 +150,18 @@ function ChartTable({ ), buttonStyle: 'tertiary', onClick: () => { - window.location.href = '/chart/add'; + history.push('/chart/add'); }, }, { name: 'View All »', buttonStyle: 'link', onClick: () => { - window.location.href = '/chart/list'; + const target = + chartFilter === 'Favorite' + ? '/chart/list/?filters=(favorite:!t)' + : '/chart/list/'; + history.push(target); }, }, ]} diff --git a/superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx b/superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx index 6b06553c39..7830122f91 100644 --- a/superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx +++ b/superset-frontend/src/views/CRUD/welcome/DashboardTable.tsx @@ -20,6 +20,7 @@ import React, { useState, useMemo } from 'react'; import { SupersetClient, t } from '@superset-ui/core'; import { useListViewResource, useFavoriteStatus } from 'src/views/CRUD/hooks'; import { Dashboard, DashboardTableProps } from 'src/views/CRUD/types'; +import { useHistory } from 'react-router-dom'; import withToasts from 'src/messageToasts/enhancers/withToasts'; import PropertiesModal from 'src/dashboard/components/PropertiesModal'; import DashboardCard from 'src/views/CRUD/dashboard/DashboardCard'; @@ -42,6 +43,7 @@ function DashboardTable({ addSuccessToast, mine, }: DashboardTableProps) { + const history = useHistory(); const { state: { loading, resourceCollection: dashboards }, setResourceCollection: setDashboards, @@ -155,14 +157,18 @@ function DashboardTable({ ), buttonStyle: 'tertiary', onClick: () => { - window.location.href = '/dashboard/new'; + history.push('/dashboard/new'); }, }, { name: 'View All »', buttonStyle: 'link', onClick: () => { - window.location.href = '/dashboard/list/'; + const target = + dashboardFilter === 'Favorite' + ? '/dashboard/list/?filters=(favorite:!t)' + : '/dashboard/list/'; + history.push(target); }, }, ]} diff --git a/superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx b/superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx index 0ef57897d7..fecd549a3a 100644 --- a/superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx +++ b/superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx @@ -255,6 +255,7 @@ const SavedQueries = ({ setQueryFilter('Favorite')); }, }, + */ { name: 'Mine', label: t('Mine'),