fix(dashboard): Refresh Native Filters when Dashboard refreshes (#15890)

* Implement onRefresh action

* Update tests

* Clean up

* Fix type

* Add effect dependency
This commit is contained in:
Geido 2021-07-27 01:27:08 +02:00 committed by GitHub
parent 62550db385
commit 1297fd9169
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 61 additions and 7 deletions

View File

@ -275,6 +275,32 @@ export function fetchCharts(
}; };
} }
const refreshCharts = (chartList, force, interval, dashboardId, dispatch) =>
new Promise(resolve => {
dispatch(fetchCharts(chartList, force, interval, dashboardId));
resolve();
});
export const ON_REFRESH_SUCCESS = 'ON_REFRESH_SUCCESS';
export function onRefreshSuccess() {
return { type: ON_REFRESH_SUCCESS };
}
export const ON_REFRESH = 'ON_REFRESH';
export function onRefresh(
chartList = [],
force = false,
interval = 0,
dashboardId,
) {
return dispatch => {
dispatch({ type: ON_REFRESH });
refreshCharts(chartList, force, interval, dashboardId, dispatch).then(() =>
dispatch({ type: ON_REFRESH_SUCCESS }),
);
};
}
export const SHOW_BUILDER_PANE = 'SHOW_BUILDER_PANE'; export const SHOW_BUILDER_PANE = 'SHOW_BUILDER_PANE';
export function showBuilderPane() { export function showBuilderPane() {
return { type: SHOW_BUILDER_PANE }; return { type: SHOW_BUILDER_PANE };

View File

@ -378,6 +378,7 @@ export const hydrateDashboard = (dashboardData, chartData) => (
hasUnsavedChanges: false, hasUnsavedChanges: false,
maxUndoHistoryExceeded: false, maxUndoHistoryExceeded: false,
lastModifiedTime: dashboardData.changed_on, lastModifiedTime: dashboardData.changed_on,
isRefreshing: false,
activeTabs: [], activeTabs: [],
}, },
dashboardLayout, dashboardLayout,

View File

@ -54,6 +54,7 @@ const createProps = () => ({
onChange: jest.fn(), onChange: jest.fn(),
fetchFaveStar: jest.fn(), fetchFaveStar: jest.fn(),
fetchCharts: jest.fn(), fetchCharts: jest.fn(),
onRefresh: jest.fn(),
saveFaveStar: jest.fn(), saveFaveStar: jest.fn(),
savePublished: jest.fn(), savePublished: jest.fn(),
isPublished: false, isPublished: false,
@ -301,5 +302,5 @@ test('should refresh the charts', async () => {
render(setup(mockedProps)); render(setup(mockedProps));
await openActionsDropdown(); await openActionsDropdown();
userEvent.click(screen.getByText('Refresh dashboard')); userEvent.click(screen.getByText('Refresh dashboard'));
expect(mockedProps.fetchCharts).toHaveBeenCalledTimes(1); expect(mockedProps.onRefresh).toHaveBeenCalledTimes(1);
}); });

View File

@ -82,6 +82,7 @@ const propTypes = {
lastModifiedTime: PropTypes.number.isRequired, lastModifiedTime: PropTypes.number.isRequired,
// redux // redux
onRefresh: PropTypes.func.isRequired,
onUndo: PropTypes.func.isRequired, onUndo: PropTypes.func.isRequired,
onRedo: PropTypes.func.isRequired, onRedo: PropTypes.func.isRequired,
undoLength: PropTypes.number.isRequired, undoLength: PropTypes.number.isRequired,
@ -216,8 +217,7 @@ class Header extends React.PureComponent {
interval: 0, interval: 0,
chartCount: chartList.length, chartCount: chartList.length,
}); });
return this.props.onRefresh(
return this.props.fetchCharts(
chartList, chartList,
true, true,
0, 0,

View File

@ -87,6 +87,7 @@ export interface HeaderProps {
lastModifiedTime: number; lastModifiedTime: number;
onUndo: () => void; onUndo: () => void;
onRedo: () => void; onRedo: () => void;
onRefresh: () => void;
undoLength: number; undoLength: number;
redoLength: number; redoLength: number;
setMaxUndoHistoryExceeded: () => void; setMaxUndoHistoryExceeded: () => void;

View File

@ -28,7 +28,7 @@ import {
JsonObject, JsonObject,
getChartMetadataRegistry, getChartMetadataRegistry,
} from '@superset-ui/core'; } from '@superset-ui/core';
import { useDispatch } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { areObjectsEqual } from 'src/reduxUtils'; import { areObjectsEqual } from 'src/reduxUtils';
import { getChartDataRequest } from 'src/chart/chartAction'; import { getChartDataRequest } from 'src/chart/chartAction';
import Loading from 'src/components/Loading'; import Loading from 'src/components/Loading';
@ -36,6 +36,7 @@ import BasicErrorAlert from 'src/components/ErrorMessage/BasicErrorAlert';
import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags'; import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
import { waitForAsyncData } from 'src/middleware/asyncEvent'; import { waitForAsyncData } from 'src/middleware/asyncEvent';
import { ClientErrorObject } from 'src/utils/getClientErrorObject'; import { ClientErrorObject } from 'src/utils/getClientErrorObject';
import { RootState } from 'src/dashboard/types';
import { dispatchFocusAction } from './utils'; import { dispatchFocusAction } from './utils';
import { FilterProps } from './types'; import { FilterProps } from './types';
import { getFormData } from '../../utils'; import { getFormData } from '../../utils';
@ -62,6 +63,9 @@ const FilterValue: React.FC<FilterProps> = ({
const { id, targets, filterType, adhoc_filters, time_range } = filter; const { id, targets, filterType, adhoc_filters, time_range } = filter;
const metadata = getChartMetadataRegistry().get(filterType); const metadata = getChartMetadataRegistry().get(filterType);
const cascadingFilters = useCascadingFilters(id, dataMaskSelected); const cascadingFilters = useCascadingFilters(id, dataMaskSelected);
const isDashboardRefreshing = useSelector<RootState, boolean>(
state => state.dashboardState.isRefreshing,
);
const [state, setState] = useState<ChartDataResponseResult[]>([]); const [state, setState] = useState<ChartDataResponseResult[]>([]);
const [error, setError] = useState<string>(''); const [error, setError] = useState<string>('');
const [formData, setFormData] = useState<Partial<QueryFormData>>({ const [formData, setFormData] = useState<Partial<QueryFormData>>({
@ -78,7 +82,7 @@ const FilterValue: React.FC<FilterProps> = ({
const { name: groupby } = column; const { name: groupby } = column;
const hasDataSource = !!datasetId; const hasDataSource = !!datasetId;
const [isLoading, setIsLoading] = useState<boolean>(hasDataSource); const [isLoading, setIsLoading] = useState<boolean>(hasDataSource);
const [isRefreshing, setIsRefreshing] = useState(true); const [isRefreshing, setIsRefreshing] = useState(false);
const dispatch = useDispatch(); const dispatch = useDispatch();
useEffect(() => { useEffect(() => {
@ -102,8 +106,10 @@ const FilterValue: React.FC<FilterProps> = ({
}); });
const filterOwnState = filter.dataMask?.ownState || {}; const filterOwnState = filter.dataMask?.ownState || {};
if ( if (
!areObjectsEqual(formData, newFormData) || !isRefreshing &&
!areObjectsEqual(ownState, filterOwnState) (!areObjectsEqual(formData, newFormData) ||
!areObjectsEqual(ownState, filterOwnState) ||
isDashboardRefreshing)
) { ) {
setFormData(newFormData); setFormData(newFormData);
setOwnState(filterOwnState); setOwnState(filterOwnState);
@ -165,6 +171,8 @@ const FilterValue: React.FC<FilterProps> = ({
groupby, groupby,
JSON.stringify(filter), JSON.stringify(filter),
hasDataSource, hasDataSource,
isRefreshing,
isDashboardRefreshing,
]); ]);
useEffect(() => { useEffect(() => {

View File

@ -39,6 +39,7 @@ import {
setMaxUndoHistoryExceeded, setMaxUndoHistoryExceeded,
maxUndoHistoryToast, maxUndoHistoryToast,
setRefreshFrequency, setRefreshFrequency,
onRefresh,
} from '../actions/dashboardState'; } from '../actions/dashboardState';
import { import {
@ -120,6 +121,7 @@ function mapDispatchToProps(dispatch) {
maxUndoHistoryToast, maxUndoHistoryToast,
logEvent, logEvent,
setRefreshFrequency, setRefreshFrequency,
onRefresh,
dashboardInfoChanged, dashboardInfoChanged,
dashboardTitleChanged, dashboardTitleChanged,
updateDataMask, updateDataMask,

View File

@ -32,6 +32,8 @@ import {
TOGGLE_PUBLISHED, TOGGLE_PUBLISHED,
UPDATE_CSS, UPDATE_CSS,
SET_REFRESH_FREQUENCY, SET_REFRESH_FREQUENCY,
ON_REFRESH,
ON_REFRESH_SUCCESS,
SET_DIRECT_PATH, SET_DIRECT_PATH,
SET_FOCUSED_FILTER_FIELD, SET_FOCUSED_FILTER_FIELD,
UNSET_FOCUSED_FILTER_FIELD, UNSET_FOCUSED_FILTER_FIELD,
@ -128,6 +130,18 @@ export default function dashboardStateReducer(state = {}, action) {
hasUnsavedChanges: action.isPersistent, hasUnsavedChanges: action.isPersistent,
}; };
}, },
[ON_REFRESH]() {
return {
...state,
isRefreshing: true,
};
},
[ON_REFRESH_SUCCESS]() {
return {
...state,
isRefreshing: false,
};
},
[SET_DIRECT_PATH]() { [SET_DIRECT_PATH]() {
return { return {
...state, ...state,

View File

@ -60,6 +60,7 @@ export type DashboardState = {
directPathToChild: string[]; directPathToChild: string[];
activeTabs: ActiveTabs; activeTabs: ActiveTabs;
fullSizeChartId: number | null; fullSizeChartId: number | null;
isRefreshing: boolean;
}; };
export type DashboardInfo = { export type DashboardInfo = {
common: { common: {