mirror of
https://github.com/apache/superset.git
synced 2026-07-03 13:25:32 +00:00
Compare commits
1 Commits
fix/105973
...
fix/issue-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc30677690 |
@@ -27,6 +27,7 @@ import { EmptyState, Loading } from '@superset-ui/core/components';
|
||||
import { ErrorBoundary, BasicErrorAlert } from 'src/components';
|
||||
import BuilderComponentPane from 'src/dashboard/components/BuilderComponentPane';
|
||||
import DashboardHeader from 'src/dashboard/components/Header';
|
||||
import HeadlessAutoRefresh from 'src/dashboard/components/Header/HeadlessAutoRefresh';
|
||||
import { Icons } from '@superset-ui/core/components/Icons';
|
||||
import IconButton from 'src/dashboard/components/IconButton';
|
||||
import { Droppable } from 'src/dashboard/components/dnd/DragDroppable';
|
||||
@@ -515,7 +516,7 @@ const DashboardBuilder = () => {
|
||||
const headerContent = useMemo(
|
||||
() => (
|
||||
<>
|
||||
{!hideDashboardHeader && <DashboardHeader />}
|
||||
{hideDashboardHeader ? <HeadlessAutoRefresh /> : <DashboardHeader />}
|
||||
{showFilterBar &&
|
||||
filterBarOrientation === FilterBarOrientation.Horizontal && (
|
||||
<FilterBar
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { render } from 'spec/helpers/testing-library';
|
||||
import { AutoRefreshProvider } from 'src/dashboard/contexts/AutoRefreshContext';
|
||||
import HeadlessAutoRefresh from './HeadlessAutoRefresh';
|
||||
|
||||
const mockUseHeaderAutoRefresh = jest.fn();
|
||||
|
||||
jest.mock('./useHeaderAutoRefresh', () => ({
|
||||
useHeaderAutoRefresh: (props: unknown) => {
|
||||
mockUseHeaderAutoRefresh(props);
|
||||
return {
|
||||
forceRefresh: jest.fn(),
|
||||
handlePauseToggle: jest.fn(),
|
||||
autoRefreshPauseOnInactiveTab: false,
|
||||
setPauseOnInactiveTab: jest.fn(),
|
||||
};
|
||||
},
|
||||
}));
|
||||
|
||||
const initialState = {
|
||||
dashboardInfo: {
|
||||
id: 42,
|
||||
metadata: { timed_refresh_immune_slices: [7] },
|
||||
common: { conf: { DASHBOARD_AUTO_REFRESH_MODE: 'fetch' } },
|
||||
},
|
||||
dashboardState: {
|
||||
refreshFrequency: 30,
|
||||
sliceIds: [1, 2, 3],
|
||||
},
|
||||
charts: {
|
||||
1: { id: 1, chartUpdateStartTime: 0, chartUpdateEndTime: 0 },
|
||||
2: { id: 2, chartUpdateStartTime: 0, chartUpdateEndTime: 0 },
|
||||
},
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
mockUseHeaderAutoRefresh.mockClear();
|
||||
});
|
||||
|
||||
test('drives the auto-refresh hook from redux state without a header', () => {
|
||||
const { container } = render(
|
||||
<AutoRefreshProvider>
|
||||
<HeadlessAutoRefresh />
|
||||
</AutoRefreshProvider>,
|
||||
{ useRedux: true, initialState },
|
||||
);
|
||||
|
||||
// The component renders nothing but must still start the refresh timer.
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
expect(mockUseHeaderAutoRefresh).toHaveBeenCalledTimes(1);
|
||||
expect(mockUseHeaderAutoRefresh).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
chartIds: [1, 2, 3],
|
||||
dashboardId: 42,
|
||||
refreshFrequency: 30,
|
||||
timedRefreshImmuneSlices: [7],
|
||||
autoRefreshMode: 'fetch',
|
||||
isLoading: false,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
test('passes the redux refresh frequency through to the hook', () => {
|
||||
render(
|
||||
<AutoRefreshProvider>
|
||||
<HeadlessAutoRefresh />
|
||||
</AutoRefreshProvider>,
|
||||
{
|
||||
useRedux: true,
|
||||
initialState: {
|
||||
...initialState,
|
||||
dashboardState: { ...initialState.dashboardState, refreshFrequency: 0 },
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
expect(mockUseHeaderAutoRefresh).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ refreshFrequency: 0 }),
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { useMemo } from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { RootState } from 'src/dashboard/types';
|
||||
import { useChartIds } from 'src/dashboard/util/charts/useChartIds';
|
||||
import { onRefresh, setRefreshFrequency } from '../../actions/dashboardState';
|
||||
import { logEvent } from '../../../logger/actions';
|
||||
import { useHeaderAutoRefresh } from './useHeaderAutoRefresh';
|
||||
|
||||
/**
|
||||
* Headless component that drives the dashboard auto-refresh timer when the
|
||||
* dashboard header is not rendered (e.g. standalone mode or `hideTitle: true`
|
||||
* in embedded dashboards). The auto-refresh logic lives in the header, so
|
||||
* hiding the header would otherwise stop the refresh interval from ever
|
||||
* starting. Rendering this component keeps the timer running independently of
|
||||
* header visibility. It renders nothing.
|
||||
*/
|
||||
const HeadlessAutoRefresh = (): null => {
|
||||
const dispatch = useDispatch();
|
||||
const chartIds = useChartIds();
|
||||
const dashboardId = useSelector((state: RootState) => state.dashboardInfo.id);
|
||||
const refreshFrequency = useSelector(
|
||||
(state: RootState) => state.dashboardState.refreshFrequency ?? 0,
|
||||
);
|
||||
const timedRefreshImmuneSlices = useSelector(
|
||||
(state: RootState) =>
|
||||
state.dashboardInfo.metadata?.timed_refresh_immune_slices || [],
|
||||
);
|
||||
const autoRefreshMode = useSelector(
|
||||
(state: RootState) =>
|
||||
state.dashboardInfo.common?.conf?.DASHBOARD_AUTO_REFRESH_MODE,
|
||||
);
|
||||
const isLoading = useSelector((state: RootState) =>
|
||||
Object.values(state.charts).some(chart => {
|
||||
const start = chart.chartUpdateStartTime ?? 0;
|
||||
const end = chart.chartUpdateEndTime ?? 0;
|
||||
return start > end;
|
||||
}),
|
||||
);
|
||||
|
||||
const boundActionCreators = useMemo(
|
||||
() =>
|
||||
bindActionCreators(
|
||||
{
|
||||
onRefresh,
|
||||
setRefreshFrequency,
|
||||
logEvent,
|
||||
},
|
||||
dispatch,
|
||||
),
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
useHeaderAutoRefresh({
|
||||
chartIds,
|
||||
dashboardId,
|
||||
refreshFrequency,
|
||||
timedRefreshImmuneSlices,
|
||||
autoRefreshMode,
|
||||
isLoading,
|
||||
onRefresh: boundActionCreators.onRefresh,
|
||||
setRefreshFrequency: boundActionCreators.setRefreshFrequency,
|
||||
logEvent: boundActionCreators.logEvent,
|
||||
});
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export default HeadlessAutoRefresh;
|
||||
Reference in New Issue
Block a user