mirror of
https://github.com/apache/superset.git
synced 2024-09-06 22:07:34 -04:00
feat: View all fav charts and dashboards (#12060)
* Add fav filter - tentative * Closes #11984 * Fix tests * Delete trailing spaces * Fix spec btns length * Fix mock test * Add urlDisplay option * Redirect with history * Catch initial fav filter
This commit is contained in:
parent
2a23744223
commit
f4ce831a10
@ -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);
|
||||
});
|
||||
|
@ -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',
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -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<Dashboard | null>(
|
||||
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,
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -115,8 +115,8 @@ export function useListViewResource<D extends object = any>(
|
||||
|
||||
const filterExps = (baseFilters || [])
|
||||
.concat(filterValues)
|
||||
.map(({ id: col, operator: opr, value }) => ({
|
||||
col,
|
||||
.map(({ id, operator: opr, value }) => ({
|
||||
col: id,
|
||||
opr,
|
||||
value,
|
||||
}));
|
||||
|
@ -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);
|
||||
},
|
||||
},
|
||||
]}
|
||||
|
@ -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);
|
||||
},
|
||||
},
|
||||
]}
|
||||
|
@ -255,6 +255,7 @@ const SavedQueries = ({
|
||||
<SubMenu
|
||||
activeChild={queryFilter}
|
||||
tabs={[
|
||||
/* @TODO uncomment when fav functionality is implemented
|
||||
{
|
||||
name: 'Favorite',
|
||||
label: t('Favorite'),
|
||||
@ -262,6 +263,7 @@ const SavedQueries = ({
|
||||
getData('Favorite').then(() => setQueryFilter('Favorite'));
|
||||
},
|
||||
},
|
||||
*/
|
||||
{
|
||||
name: 'Mine',
|
||||
label: t('Mine'),
|
||||
|
Loading…
Reference in New Issue
Block a user