diff --git a/superset/assets/spec/javascripts/dashboard/components/RefreshIntervalModal_spec.jsx b/superset/assets/spec/javascripts/dashboard/components/RefreshIntervalModal_spec.jsx
index ac06cfc32..8dfb4016f 100644
--- a/superset/assets/spec/javascripts/dashboard/components/RefreshIntervalModal_spec.jsx
+++ b/superset/assets/spec/javascripts/dashboard/components/RefreshIntervalModal_spec.jsx
@@ -24,6 +24,7 @@ import RefreshIntervalModal from '../../../../src/dashboard/components/RefreshIn
describe('RefreshIntervalModal', () => {
const mockedProps = {
triggerNode: ,
+ refreshFrequency: 10,
};
it('is valid', () => {
expect(
@@ -34,4 +35,8 @@ describe('RefreshIntervalModal', () => {
const wrapper = mount();
expect(wrapper.find('.fa-edit')).toHaveLength(1);
});
+ it('should render a interval seconds', () => {
+ const wrapper = mount();
+ expect(wrapper.prop('refreshFrequency')).toEqual(10);
+ });
});
diff --git a/superset/assets/src/dashboard/actions/dashboardState.js b/superset/assets/src/dashboard/actions/dashboardState.js
index 135658d93..086481919 100644
--- a/superset/assets/src/dashboard/actions/dashboardState.js
+++ b/superset/assets/src/dashboard/actions/dashboardState.js
@@ -123,6 +123,11 @@ export function onSave() {
return { type: ON_SAVE };
}
+export const SET_REFRESH_FREQUENCY = 'SET_REFRESH_FREQUENCY';
+export function setRefreshFrequency(refreshFrequency) {
+ return { type: SET_REFRESH_FREQUENCY, refreshFrequency };
+}
+
export function saveDashboardRequestSuccess() {
return dispatch => {
dispatch(onSave());
diff --git a/superset/assets/src/dashboard/components/Header.jsx b/superset/assets/src/dashboard/components/Header.jsx
index b2238d0e0..796a2df09 100644
--- a/superset/assets/src/dashboard/components/Header.jsx
+++ b/superset/assets/src/dashboard/components/Header.jsx
@@ -77,6 +77,8 @@ const propTypes = {
redoLength: PropTypes.number.isRequired,
setMaxUndoHistoryExceeded: PropTypes.func.isRequired,
maxUndoHistoryToast: PropTypes.func.isRequired,
+ refreshFrequency: PropTypes.number.isRequired,
+ setRefreshFrequency: PropTypes.func.isRequired,
};
class Header extends React.PureComponent {
@@ -100,6 +102,11 @@ class Header extends React.PureComponent {
this.overwriteDashboard = this.overwriteDashboard.bind(this);
}
+ componentDidMount() {
+ const refreshFrequency = this.props.refreshFrequency;
+ this.props.startPeriodicRender(refreshFrequency * 1000);
+ }
+
componentWillReceiveProps(nextProps) {
if (
UNDO_LIMIT - nextProps.undoLength <= 0 &&
@@ -234,6 +241,8 @@ class Header extends React.PureComponent {
dashboardInfo,
hasUnsavedChanges,
isLoading,
+ refreshFrequency,
+ setRefreshFrequency,
} = this.props;
const userCanEdit = dashboardInfo.dash_edit_perm;
@@ -346,6 +355,8 @@ class Header extends React.PureComponent {
onChange={onChange}
forceRefreshAllCharts={this.forceRefresh}
startPeriodicRender={this.startPeriodicRender}
+ refreshFrequency={refreshFrequency}
+ setRefreshFrequency={setRefreshFrequency}
updateCss={updateCss}
editMode={editMode}
hasUnsavedChanges={hasUnsavedChanges}
diff --git a/superset/assets/src/dashboard/components/HeaderActionsDropdown.jsx b/superset/assets/src/dashboard/components/HeaderActionsDropdown.jsx
index 204d5f74d..4c36d9a3c 100644
--- a/superset/assets/src/dashboard/components/HeaderActionsDropdown.jsx
+++ b/superset/assets/src/dashboard/components/HeaderActionsDropdown.jsx
@@ -40,6 +40,8 @@ const propTypes = {
onChange: PropTypes.func.isRequired,
updateCss: PropTypes.func.isRequired,
forceRefreshAllCharts: PropTypes.func.isRequired,
+ refreshFrequency: PropTypes.number.isRequired,
+ setRefreshFrequency: PropTypes.func.isRequired,
startPeriodicRender: PropTypes.func.isRequired,
editMode: PropTypes.bool.isRequired,
userCanEdit: PropTypes.bool.isRequired,
@@ -66,6 +68,7 @@ class HeaderActionsDropdown extends React.PureComponent {
};
this.changeCss = this.changeCss.bind(this);
+ this.changeRefreshInterval = this.changeRefreshInterval.bind(this);
}
componentWillMount() {
@@ -95,12 +98,17 @@ class HeaderActionsDropdown extends React.PureComponent {
this.props.updateCss(css);
}
+ changeRefreshInterval(refreshInterval) {
+ this.props.setRefreshFrequency(refreshInterval);
+ this.props.startPeriodicRender(refreshInterval * 1000);
+ }
+
render() {
const {
dashboardTitle,
dashboardId,
- startPeriodicRender,
forceRefreshAllCharts,
+ refreshFrequency,
editMode,
css,
hasUnsavedChanges,
@@ -135,6 +143,7 @@ class HeaderActionsDropdown extends React.PureComponent {
layout={layout}
filters={filters}
expandedSlices={expandedSlices}
+ refreshFrequency={refreshFrequency}
css={css}
onSave={onSave}
isMenuItem
@@ -160,9 +169,8 @@ class HeaderActionsDropdown extends React.PureComponent {
{t('Force refresh dashboard')}
- startPeriodicRender(refreshInterval * 1000)
- }
+ refreshFrequency={refreshFrequency}
+ onChange={this.changeRefreshInterval}
triggerNode={{t('Set auto-refresh interval')}}
/>
{editMode && (
diff --git a/superset/assets/src/dashboard/components/RefreshIntervalModal.jsx b/superset/assets/src/dashboard/components/RefreshIntervalModal.jsx
index 8734df90d..b314431b3 100644
--- a/superset/assets/src/dashboard/components/RefreshIntervalModal.jsx
+++ b/superset/assets/src/dashboard/components/RefreshIntervalModal.jsx
@@ -25,13 +25,8 @@ import ModalTrigger from '../../components/ModalTrigger';
const propTypes = {
triggerNode: PropTypes.node.isRequired,
- initialRefreshFrequency: PropTypes.number,
- onChange: PropTypes.func,
-};
-
-const defaultProps = {
- initialRefreshFrequency: 0,
- onChange: () => {},
+ refreshFrequency: PropTypes.number.isRequired,
+ onChange: PropTypes.func.isRequired,
};
const options = [
@@ -51,7 +46,7 @@ class RefreshIntervalModal extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
- refreshFrequency: props.initialRefreshFrequency,
+ refreshFrequency: props.refreshFrequency,
};
}
render() {
@@ -81,6 +76,5 @@ class RefreshIntervalModal extends React.PureComponent {
}
}
RefreshIntervalModal.propTypes = propTypes;
-RefreshIntervalModal.defaultProps = defaultProps;
export default RefreshIntervalModal;
diff --git a/superset/assets/src/dashboard/components/SaveModal.jsx b/superset/assets/src/dashboard/components/SaveModal.jsx
index f9a7a6cc7..aa5436979 100644
--- a/superset/assets/src/dashboard/components/SaveModal.jsx
+++ b/superset/assets/src/dashboard/components/SaveModal.jsx
@@ -41,6 +41,7 @@ const propTypes = {
onSave: PropTypes.func.isRequired,
isMenuItem: PropTypes.bool,
canOverwrite: PropTypes.bool.isRequired,
+ refreshFrequency: PropTypes.number.isRequired,
};
const defaultProps = {
@@ -95,6 +96,7 @@ class SaveModal extends React.PureComponent {
expandedSlices,
filters,
dashboardId,
+ refreshFrequency,
} = this.props;
const data = {
@@ -105,6 +107,7 @@ class SaveModal extends React.PureComponent {
saveType === SAVE_TYPE_NEWDASHBOARD ? newDashName : dashboardTitle,
default_filters: safeStringify(filters),
duplicate_slices: this.state.duplicateSlices,
+ refresh_frequency: refreshFrequency,
};
if (saveType === SAVE_TYPE_NEWDASHBOARD && !newDashName) {
diff --git a/superset/assets/src/dashboard/containers/DashboardHeader.jsx b/superset/assets/src/dashboard/containers/DashboardHeader.jsx
index 4eaca36a9..570d790ae 100644
--- a/superset/assets/src/dashboard/containers/DashboardHeader.jsx
+++ b/superset/assets/src/dashboard/containers/DashboardHeader.jsx
@@ -34,6 +34,7 @@ import {
saveDashboardRequest,
setMaxUndoHistoryExceeded,
maxUndoHistoryToast,
+ setRefreshFrequency,
} from '../actions/dashboardState';
import {
@@ -68,6 +69,7 @@ function mapStateToProps({
(undoableLayout.present[DASHBOARD_HEADER_ID] || {}).meta || {}
).text,
expandedSlices: dashboardState.expandedSlices,
+ refreshFrequency: dashboardState.refreshFrequency,
css: dashboardState.css,
charts,
userId: dashboardInfo.userId,
@@ -101,6 +103,7 @@ function mapDispatchToProps(dispatch) {
setMaxUndoHistoryExceeded,
maxUndoHistoryToast,
logEvent,
+ setRefreshFrequency,
},
dispatch,
);
diff --git a/superset/assets/src/dashboard/reducers/dashboardState.js b/superset/assets/src/dashboard/reducers/dashboardState.js
index 72c4d3678..24066ebca 100644
--- a/superset/assets/src/dashboard/reducers/dashboardState.js
+++ b/superset/assets/src/dashboard/reducers/dashboardState.js
@@ -30,6 +30,7 @@ import {
TOGGLE_EXPAND_SLICE,
TOGGLE_FAVE_STAR,
UPDATE_CSS,
+ SET_REFRESH_FREQUENCY,
} from '../actions/dashboardState';
export default function dashboardStateReducer(state = {}, action) {
@@ -147,6 +148,9 @@ export default function dashboardStateReducer(state = {}, action) {
const { hasUnsavedChanges } = action.payload;
return { ...state, hasUnsavedChanges };
},
+ [SET_REFRESH_FREQUENCY]() {
+ return { ...state, refreshFrequency: action.refreshFrequency };
+ },
};
if (action.type in actionHandlers) {
diff --git a/superset/assets/src/dashboard/reducers/getInitialState.js b/superset/assets/src/dashboard/reducers/getInitialState.js
index 57354c86a..a9c4d8f95 100644
--- a/superset/assets/src/dashboard/reducers/getInitialState.js
+++ b/superset/assets/src/dashboard/reducers/getInitialState.js
@@ -186,6 +186,7 @@ export default function(bootstrapData) {
refresh: false,
filters,
expandedSlices: dashboard.metadata.expanded_slices || {},
+ refreshFrequency: dashboard.metadata.refresh_frequency || 0,
css: dashboard.css || '',
editMode: dashboard.dash_edit_perm && editMode,
showBuilderPane: dashboard.dash_edit_perm && editMode,
diff --git a/superset/views/core.py b/superset/views/core.py
index 7e6d9d328..051ea562f 100755
--- a/superset/views/core.py
+++ b/superset/views/core.py
@@ -1735,6 +1735,7 @@ class Superset(BaseSupersetView):
if 'filter_immune_slice_fields' not in md:
md['filter_immune_slice_fields'] = {}
md['expanded_slices'] = data['expanded_slices']
+ md['refresh_frequency'] = data.get('refresh_frequency', 0)
default_filters_data = json.loads(data.get('default_filters', '{}'))
applicable_filters = \
{key: v for key, v in default_filters_data.items()