diff --git a/CHANGELOG.md b/CHANGELOG.md index d157bc66b7..9a6da3508a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ 4. [#892](https://github.com/influxdata/chronograf/issues/891): Make dashboard visualizations resizable 5. [#893](https://github.com/influxdata/chronograf/issues/893): Persist dashboard visualization position 6. [#922](https://github.com/influxdata/chronograf/issues/922): Additional OAuth2 support for [Heroku](https://github.com/influxdata/chronograf/blob/master/docs/auth.md#heroku) and [Google](https://github.com/influxdata/chronograf/blob/master/docs/auth.md#google) + 7. [#781](https://github.com/influxdata/chronograf/issues/781): Add global auto-refresh dropdown to all graph dashboards ### UI Improvements 1. [#905](https://github.com/influxdata/chronograf/pull/905): Make scroll bar thumb element bigger diff --git a/ui/src/dashboards/components/Dashboard.js b/ui/src/dashboards/components/Dashboard.js index 46eb173b05..3ff1c1ca46 100644 --- a/ui/src/dashboards/components/Dashboard.js +++ b/ui/src/dashboards/components/Dashboard.js @@ -10,6 +10,7 @@ const Dashboard = ({ inPresentationMode, onPositionChange, source, + autoRefresh, timeRange, }) => { if (dashboard.id === 0) { @@ -20,14 +21,13 @@ const Dashboard = ({
{isEditMode ? : null} - {Dashboard.renderDashboard(dashboard, timeRange, source, onPositionChange)} + {Dashboard.renderDashboard(dashboard, autoRefresh, timeRange, source, onPositionChange)}
) } -Dashboard.renderDashboard = (dashboard, timeRange, source, onPositionChange) => { - const autoRefreshMs = 15000 +Dashboard.renderDashboard = (dashboard, autoRefresh, timeRange, source, onPositionChange) => { const cells = dashboard.cells.map((cell, i) => { i = `${i}` const dashboardCell = {...cell, i} @@ -42,7 +42,7 @@ Dashboard.renderDashboard = (dashboard, timeRange, source, onPositionChange) => @@ -54,6 +54,7 @@ const { func, shape, string, + number, } = PropTypes Dashboard.propTypes = { @@ -66,6 +67,7 @@ Dashboard.propTypes = { proxy: string, }).isRequired, }).isRequired, + autoRefresh: number.isRequired, timeRange: shape({}).isRequired, } diff --git a/ui/src/dashboards/components/DashboardHeader.js b/ui/src/dashboards/components/DashboardHeader.js index be6fd69a0f..55dd1b7b05 100644 --- a/ui/src/dashboards/components/DashboardHeader.js +++ b/ui/src/dashboards/components/DashboardHeader.js @@ -2,6 +2,7 @@ import React, {PropTypes} from 'react' import ReactTooltip from 'react-tooltip' import {Link} from 'react-router'; +import AutoRefreshDropdown from 'shared/components/AutoRefreshDropdown' import TimeRangeDropdown from 'shared/components/TimeRangeDropdown' const DashboardHeader = ({ @@ -10,8 +11,10 @@ const DashboardHeader = ({ dashboard, headerText, timeRange, + autoRefresh, isHidden, handleChooseTimeRange, + handleChooseAutoRefresh, handleClickPresentationButton, sourceID, }) => isHidden ? null : ( @@ -45,6 +48,7 @@ const DashboardHeader = ({ Graph Tips +
@@ -55,11 +59,12 @@ const DashboardHeader = ({ ) const { - shape, array, - string, - func, bool, + func, + number, + shape, + string, } = PropTypes DashboardHeader.propTypes = { @@ -69,8 +74,10 @@ DashboardHeader.propTypes = { dashboard: shape({}), headerText: string, timeRange: shape({}).isRequired, + autoRefresh: number.isRequired, isHidden: bool.isRequired, handleChooseTimeRange: func.isRequired, + handleChooseAutoRefresh: func.isRequired, handleClickPresentationButton: func.isRequired, } diff --git a/ui/src/dashboards/containers/DashboardPage.js b/ui/src/dashboards/containers/DashboardPage.js index c83c920202..0b6efe1b42 100644 --- a/ui/src/dashboards/containers/DashboardPage.js +++ b/ui/src/dashboards/containers/DashboardPage.js @@ -51,6 +51,7 @@ const DashboardPage = React.createClass({ id: number.isRequired, cells: arrayOf(shape({})).isRequired, }).isRequired, + autoRefresh: number.isRequired, timeRange: shape({}).isRequired, inPresentationMode: bool.isRequired, isEditMode: bool.isRequired, @@ -100,6 +101,7 @@ const DashboardPage = React.createClass({ isEditMode, handleClickPresentationButton, source, + autoRefresh, timeRange, } = this.props @@ -110,6 +112,7 @@ const DashboardPage = React.createClass({ {}} /> :
@@ -143,7 +147,10 @@ const DashboardPage = React.createClass({ const mapStateToProps = (state) => { const { - appUI, + app: { + ephemeral: {inPresentationMode}, + persisted: {autoRefresh}, + }, dashboardUI: { dashboards, dashboard, @@ -153,11 +160,12 @@ const mapStateToProps = (state) => { } = state return { - inPresentationMode: appUI.presentationMode, dashboards, dashboard, + autoRefresh, timeRange, isEditMode, + inPresentationMode, } } diff --git a/ui/src/data_explorer/components/Visualization.js b/ui/src/data_explorer/components/Visualization.js index b88972a9e1..b58355da60 100644 --- a/ui/src/data_explorer/components/Visualization.js +++ b/ui/src/data_explorer/components/Visualization.js @@ -15,6 +15,7 @@ const { const Visualization = React.createClass({ propTypes: { + autoRefresh: number.isRequired, timeRange: shape({ upper: string, lower: string, @@ -45,7 +46,7 @@ const Visualization = React.createClass({ }, render() { - const {queryConfigs, timeRange, activeQueryIndex, height, heightPixels} = this.props; + const {queryConfigs, autoRefresh, timeRange, activeQueryIndex, height, heightPixels} = this.props; const {source} = this.context; const proxyLink = source.links.proxy; @@ -57,7 +58,6 @@ const Visualization = React.createClass({ const queries = statements.filter((s) => s.text !== null).map((s) => { return {host: [proxyLink], text: s.text, id: s.id}; }); - const autoRefreshMs = 10000; const isInDataExplorer = true; return ( @@ -77,7 +77,7 @@ const Visualization = React.createClass({ {isGraphInView ? ( diff --git a/ui/src/data_explorer/containers/DataExplorer.js b/ui/src/data_explorer/containers/DataExplorer.js index 68a7c7b2e1..9468fca758 100644 --- a/ui/src/data_explorer/containers/DataExplorer.js +++ b/ui/src/data_explorer/containers/DataExplorer.js @@ -1,17 +1,18 @@ import React, {PropTypes} from 'react'; import {connect} from 'react-redux'; +import {bindActionCreators} from 'redux'; import QueryBuilder from '../components/QueryBuilder'; import Visualization from '../components/Visualization'; import Header from '../containers/Header'; import ResizeContainer from 'src/shared/components/ResizeContainer'; -import { - setTimeRange as setTimeRangeAction, -} from '../actions/view'; +import {setAutoRefresh} from 'shared/actions/app' +import {setTimeRange as setTimeRangeAction} from '../actions/view'; const { arrayOf, func, + number, shape, string, } = PropTypes; @@ -25,6 +26,8 @@ const DataExplorer = React.createClass({ }).isRequired, }).isRequired, queryConfigs: PropTypes.shape({}), + autoRefresh: number.isRequired, + handleChooseAutoRefresh: func.isRequired, timeRange: shape({ upper: string, lower: string, @@ -59,18 +62,20 @@ const DataExplorer = React.createClass({ }, render() { - const {timeRange, setTimeRange, queryConfigs, dataExplorer} = this.props; + const {autoRefresh, handleChooseAutoRefresh, timeRange, setTimeRange, queryConfigs, dataExplorer} = this.props; const {activeQueryID} = this.state; const queries = dataExplorer.queryIDs.map((qid) => queryConfigs[qid]); return (
@@ -50,6 +62,7 @@ const Header = React.createClass({ {this.context.source.name}
+
diff --git a/ui/src/data_explorer/reducers/index.js b/ui/src/data_explorer/reducers/index.js index cccca5d791..6db959b198 100644 --- a/ui/src/data_explorer/reducers/index.js +++ b/ui/src/data_explorer/reducers/index.js @@ -2,8 +2,8 @@ import queryConfigs from './queryConfigs'; import timeRange from './timeRange'; import dataExplorer from './ui'; -export { +export default { queryConfigs, timeRange, dataExplorer, -}; +} diff --git a/ui/src/hosts/containers/HostPage.js b/ui/src/hosts/containers/HostPage.js index 38ff3ae160..641aa63f19 100644 --- a/ui/src/hosts/containers/HostPage.js +++ b/ui/src/hosts/containers/HostPage.js @@ -1,6 +1,7 @@ import React, {PropTypes} from 'react' import {Link} from 'react-router' import {connect} from 'react-redux' +import {bindActionCreators} from 'redux' import _ from 'lodash' import classnames from 'classnames'; @@ -9,6 +10,8 @@ import DashboardHeader from 'src/dashboards/components/DashboardHeader'; import timeRanges from 'hson!../../shared/data/timeRanges.hson'; import {getMappings, getAppsForHosts, getMeasurementsForHost, getAllHosts} from 'src/hosts/apis'; import {fetchLayouts} from 'shared/apis'; + +import {setAutoRefresh} from 'shared/actions/app' import {presentationButtonDispatcher} from 'shared/dispatchers' const { @@ -16,6 +19,7 @@ const { string, bool, func, + number, } = PropTypes export const HostPage = React.createClass({ @@ -35,6 +39,8 @@ export const HostPage = React.createClass({ app: string, }), }), + autoRefresh: number.isRequired, + handleChooseAutoRefresh: func.isRequired, inPresentationMode: bool, handleClickPresentationButton: func, }, @@ -87,9 +93,8 @@ export const HostPage = React.createClass({ }, renderLayouts(layouts) { - const autoRefreshMs = 15000; const {timeRange} = this.state; - const {source} = this.props; + const {source, autoRefresh} = this.props; const autoflowLayouts = layouts.filter((layout) => !!layout.autoflow); @@ -137,7 +142,7 @@ export const HostPage = React.createClass({ @@ -145,7 +150,7 @@ export const HostPage = React.createClass({ }, render() { - const {params: {hostID}, location: {query: {app}}, source: {id}, inPresentationMode, handleClickPresentationButton} = this.props + const {params: {hostID}, location: {query: {app}}, source: {id}, autoRefresh, handleChooseAutoRefresh, inPresentationMode, handleClickPresentationButton} = this.props const {layouts, timeRange, hosts} = this.state const appParam = app ? `?app=${app}` : '' @@ -153,9 +158,11 @@ export const HostPage = React.createClass({
{Object.keys(hosts).map((host, i) => { @@ -181,11 +188,13 @@ export const HostPage = React.createClass({ }, }); -const mapStateToProps = (state) => ({ - inPresentationMode: state.appUI.presentationMode, +const mapStateToProps = ({app: {ephemeral: {inPresentationMode}, persisted: {autoRefresh}}}) => ({ + inPresentationMode, + autoRefresh, }) const mapDispatchToProps = (dispatch) => ({ + handleChooseAutoRefresh: bindActionCreators(setAutoRefresh, dispatch), handleClickPresentationButton: presentationButtonDispatcher(dispatch), }) diff --git a/ui/src/index.js b/ui/src/index.js index c2a8f4cd3d..e45201ad6d 100644 --- a/ui/src/index.js +++ b/ui/src/index.js @@ -19,7 +19,7 @@ import configureStore from 'src/store/configureStore'; import {getMe, getSources} from 'shared/apis'; import {receiveMe} from 'shared/actions/me'; import {receiveAuth} from 'shared/actions/auth'; -import {disablePresentationMode} from 'shared/actions/ui'; +import {disablePresentationMode} from 'shared/actions/app'; import {loadLocalStorage} from './localStorage'; import 'src/style/chronograf.scss'; diff --git a/ui/src/kubernetes/components/KubernetesDashboard.js b/ui/src/kubernetes/components/KubernetesDashboard.js index 2c4afc5b41..6092b03e8e 100644 --- a/ui/src/kubernetes/components/KubernetesDashboard.js +++ b/ui/src/kubernetes/components/KubernetesDashboard.js @@ -6,11 +6,12 @@ import DashboardHeader from 'src/dashboards/components/DashboardHeader'; import timeRanges from 'hson!../../shared/data/timeRanges.hson'; const { - shape, - string, arrayOf, bool, func, + number, + shape, + string, } = PropTypes export const KubernetesDashboard = React.createClass({ @@ -22,6 +23,8 @@ export const KubernetesDashboard = React.createClass({ telegraf: string.isRequired, }), layouts: arrayOf(shape().isRequired).isRequired, + autoRefresh: number.isRequired, + handleChooseAutoRefresh: func.isRequired, inPresentationMode: bool.isRequired, handleClickPresentationButton: func, }, @@ -34,9 +37,8 @@ export const KubernetesDashboard = React.createClass({ }, renderLayouts(layouts) { - const autoRefreshMs = 15000; const {timeRange} = this.state; - const {source} = this.props; + const {source, autoRefresh} = this.props; let layoutCells = []; layouts.forEach((layout) => { @@ -56,7 +58,7 @@ export const KubernetesDashboard = React.createClass({ ); @@ -68,7 +70,7 @@ export const KubernetesDashboard = React.createClass({ }, render() { - const {layouts, inPresentationMode, handleClickPresentationButton} = this.props; + const {layouts, autoRefresh, handleChooseAutoRefresh, inPresentationMode, handleClickPresentationButton} = this.props; const {timeRange} = this.state; const emptyState = (
@@ -81,6 +83,8 @@ export const KubernetesDashboard = React.createClass({
@@ -51,11 +59,13 @@ export const KubernetesPage = React.createClass({ }, }); -const mapStateToProps = (state) => ({ - inPresentationMode: state.appUI.presentationMode, +const mapStateToProps = ({app: {ephemeral: {inPresentationMode}, persisted: {autoRefresh}}}) => ({ + inPresentationMode, + autoRefresh, }) const mapDispatchToProps = (dispatch) => ({ + handleChooseAutoRefresh: bindActionCreators(setAutoRefresh, dispatch), handleClickPresentationButton: presentationButtonDispatcher(dispatch), }) diff --git a/ui/src/localStorage.js b/ui/src/localStorage.js index 5cd29aa071..4b8381503c 100644 --- a/ui/src/localStorage.js +++ b/ui/src/localStorage.js @@ -9,9 +9,12 @@ export const loadLocalStorage = () => { } }; -export const saveToLocalStorage = ({queryConfigs, timeRange, dataExplorer}) => { +export const saveToLocalStorage = ({app: {persisted}, queryConfigs, timeRange, dataExplorer}) => { try { + const appPersisted = Object.assign({}, {app: {persisted}}) + window.localStorage.setItem('state', JSON.stringify({ + ...appPersisted, queryConfigs, timeRange, dataExplorer, diff --git a/ui/src/shared/actions/app.js b/ui/src/shared/actions/app.js new file mode 100644 index 0000000000..f8939f408f --- /dev/null +++ b/ui/src/shared/actions/app.js @@ -0,0 +1,22 @@ +import {PRESENTATION_MODE_ANIMATION_DELAY} from '../constants' + +// ephemeral state reducers +export const enablePresentationMode = () => ({ + type: 'ENABLE_PRESENTATION_MODE', +}) + +export const disablePresentationMode = () => ({ + type: 'DISABLE_PRESENTATION_MODE', +}) + +export const delayEnablePresentationMode = () => (dispatch) => { + setTimeout(() => dispatch(enablePresentationMode()), PRESENTATION_MODE_ANIMATION_DELAY) +} + +// persistent state reducers +export const setAutoRefresh = (milliseconds) => ({ + type: 'SET_AUTOREFRESH', + payload: { + milliseconds, + }, +}) diff --git a/ui/src/shared/actions/ui.js b/ui/src/shared/actions/ui.js deleted file mode 100644 index 740566beb9..0000000000 --- a/ui/src/shared/actions/ui.js +++ /dev/null @@ -1,19 +0,0 @@ -import {PRESENTATION_MODE_ANIMATION_DELAY} from '../constants' - -export function enablePresentationMode() { - return { - type: 'ENABLE_PRESENTATION_MODE', - } -} - -export function disablePresentationMode() { - return { - type: 'DISABLE_PRESENTATION_MODE', - } -} - -export function delayEnablePresentationMode() { - return (dispatch) => { - setTimeout(() => dispatch(enablePresentationMode()), PRESENTATION_MODE_ANIMATION_DELAY) - } -} diff --git a/ui/src/shared/components/AutoRefresh.js b/ui/src/shared/components/AutoRefresh.js index fd79cd620a..ecf560beff 100644 --- a/ui/src/shared/components/AutoRefresh.js +++ b/ui/src/shared/components/AutoRefresh.js @@ -6,25 +6,34 @@ function _fetchTimeSeries(source, db, rp, query) { return proxy({source, db, rp, query}); } +const { + element, + number, + arrayOf, + shape, + oneOfType, + string, +} = PropTypes + export default function AutoRefresh(ComposedComponent) { const wrapper = React.createClass({ displayName: `AutoRefresh_${ComposedComponent.displayName}`, propTypes: { - children: PropTypes.element, - autoRefresh: PropTypes.number, - queries: PropTypes.arrayOf(PropTypes.shape({ - host: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]), - text: PropTypes.string, + children: element, + autoRefresh: number.isRequired, + queries: arrayOf(shape({ + host: oneOfType([string, arrayOf(string)]), + text: string, }).isRequired).isRequired, }, getInitialState() { return {timeSeries: []}; }, componentDidMount() { - const {queries} = this.props; + const {queries, autoRefresh} = this.props; this.executeQueries(queries); - if (this.props.autoRefresh) { - this.intervalID = setInterval(() => this.executeQueries(queries), this.props.autoRefresh); + if (autoRefresh) { + this.intervalID = setInterval(() => this.executeQueries(queries), autoRefresh); } }, componentWillReceiveProps(nextProps) { diff --git a/ui/src/shared/components/AutoRefreshDropdown.js b/ui/src/shared/components/AutoRefreshDropdown.js new file mode 100644 index 0000000000..d8bafe2fda --- /dev/null +++ b/ui/src/shared/components/AutoRefreshDropdown.js @@ -0,0 +1,72 @@ +import React, {PropTypes} from 'react'; +import classnames from 'classnames'; +import OnClickOutside from 'shared/components/OnClickOutside'; + +import autoRefreshItems from 'hson!../data/autoRefreshes.hson'; + +const { + number, + func, +} = PropTypes + +const AutoRefreshDropdown = React.createClass({ + autobind: false, + + propTypes: { + selected: number.isRequired, + onChoose: func.isRequired, + }, + + getInitialState() { + return { + isOpen: false, + }; + }, + + findAutoRefreshItem(milliseconds) { + return autoRefreshItems.find((values) => values.milliseconds === milliseconds) + }, + + handleClickOutside() { + this.setState({isOpen: false}); + }, + + handleSelection(milliseconds) { + this.props.onChoose(milliseconds); + this.setState({isOpen: false}); + }, + + toggleMenu() { + this.setState({isOpen: !this.state.isOpen}); + }, + + render() { + const self = this; + const {selected} = self.props; + const {isOpen} = self.state; + + return ( +
+
self.toggleMenu()}> + + {this.findAutoRefreshItem(selected).inputValue} + +
+ +
+ ); + }, +}); + +export default OnClickOutside(AutoRefreshDropdown); diff --git a/ui/src/shared/components/Dropdown.js b/ui/src/shared/components/Dropdown.js index 178b842d50..2c749449a6 100644 --- a/ui/src/shared/components/Dropdown.js +++ b/ui/src/shared/components/Dropdown.js @@ -1,14 +1,23 @@ import React, {PropTypes} from 'react'; +import classnames from 'classnames'; import OnClickOutside from 'shared/components/OnClickOutside'; +const { + arrayOf, + shape, + string, + func, +} = PropTypes + const Dropdown = React.createClass({ propTypes: { - items: PropTypes.arrayOf(PropTypes.shape({ - text: PropTypes.string.isRequired, + items: arrayOf(shape({ + text: string.isRequired, })).isRequired, - onChoose: PropTypes.func.isRequired, - selected: PropTypes.string.isRequired, - className: PropTypes.string, + onChoose: func.isRequired, + selected: string.isRequired, + iconName: string, + className: string, }, getInitialState() { return { @@ -39,11 +48,12 @@ const Dropdown = React.createClass({ }, render() { const self = this; - const {items, selected, className, actions} = self.props; + const {items, selected, className, iconName, actions} = self.props; return (
+ {iconName ? : null} {selected}
diff --git a/ui/src/shared/components/LayoutRenderer.js b/ui/src/shared/components/LayoutRenderer.js index e1c2df5e77..60eace1466 100644 --- a/ui/src/shared/components/LayoutRenderer.js +++ b/ui/src/shared/components/LayoutRenderer.js @@ -18,6 +18,7 @@ const { export const LayoutRenderer = React.createClass({ propTypes: { + autoRefresh: number.isRequired, timeRange: shape({ defaultGroupBy: string.isRequired, queryValue: string.isRequired, @@ -46,7 +47,6 @@ export const LayoutRenderer = React.createClass({ name: string.isRequired, }).isRequired ), - autoRefreshMs: number.isRequired, host: string, source: string, onPositionChange: func, @@ -84,7 +84,7 @@ export const LayoutRenderer = React.createClass({ }, generateVisualizations() { - const {autoRefreshMs, source, cells} = this.props; + const {autoRefresh, source, cells} = this.props; return cells.map((cell) => { const qs = cell.queries.map((q) => { @@ -100,7 +100,7 @@ export const LayoutRenderer = React.createClass({

{cell.name || `Graph`}

- +
); @@ -117,7 +117,7 @@ export const LayoutRenderer = React.createClass({
diff --git a/ui/src/shared/components/TimeRangeDropdown.js b/ui/src/shared/components/TimeRangeDropdown.js index dbdf5155cd..076226896c 100644 --- a/ui/src/shared/components/TimeRangeDropdown.js +++ b/ui/src/shared/components/TimeRangeDropdown.js @@ -1,5 +1,5 @@ import React from 'react'; -import cN from 'classnames'; +import classnames from 'classnames'; import OnClickOutside from 'shared/components/OnClickOutside'; import timeRanges from 'hson!../data/timeRanges.hson'; @@ -48,7 +48,7 @@ const TimeRangeDropdown = React.createClass({ {selected}
-
    +
    • Time Range
    • {timeRanges.map((item) => { return ( diff --git a/ui/src/shared/constants/index.js b/ui/src/shared/constants/index.js index 6b0d7cb600..f6f5bb7b68 100644 --- a/ui/src/shared/constants/index.js +++ b/ui/src/shared/constants/index.js @@ -470,3 +470,5 @@ export const STROKE_WIDTH = { export const PRESENTATION_MODE_ANIMATION_DELAY = 0 // In milliseconds. export const PRESENTATION_MODE_NOTIFICATION_DELAY = 2000 // In milliseconds. + +export const AUTOREFRESH_DEFAULT = 15000 // in milliseconds diff --git a/ui/src/shared/data/autoRefreshes.hson b/ui/src/shared/data/autoRefreshes.hson new file mode 100644 index 0000000000..09b4237ff4 --- /dev/null +++ b/ui/src/shared/data/autoRefreshes.hson @@ -0,0 +1,7 @@ +[ + {milliseconds: 5000, inputValue: 'Every 5 seconds', menuOption: 'Every 5 seconds'}, + {milliseconds: 10000, inputValue: 'Every 10 seconds', menuOption: 'Every 10 seconds'}, + {milliseconds: 15000, inputValue: 'Every 15 seconds', menuOption: 'Every 15 seconds'}, + {milliseconds: 30000, inputValue: 'Every 30 seconds', menuOption: 'Every 30 seconds'}, + {milliseconds: 60000, inputValue: 'Every 60 seconds', menuOption: 'Every 60 seconds'} +] diff --git a/ui/src/shared/dispatchers/index.js b/ui/src/shared/dispatchers/index.js index fcf02767f9..a7771a9ff9 100644 --- a/ui/src/shared/dispatchers/index.js +++ b/ui/src/shared/dispatchers/index.js @@ -1,4 +1,4 @@ -import {delayEnablePresentationMode} from 'shared/actions/ui' +import {delayEnablePresentationMode} from 'shared/actions/app' import {publishNotification, delayDismissNotification} from 'shared/actions/notifications' import {PRESENTATION_MODE_NOTIFICATION_DELAY} from 'shared/constants' diff --git a/ui/src/shared/reducers/app.js b/ui/src/shared/reducers/app.js new file mode 100644 index 0000000000..adcb4c2428 --- /dev/null +++ b/ui/src/shared/reducers/app.js @@ -0,0 +1,57 @@ +import {combineReducers} from 'redux'; + +import {AUTOREFRESH_DEFAULT} from 'src/shared/constants' + +const initialState = { + ephemeral: { + inPresentationMode: false, + }, + persisted: { + autoRefresh: AUTOREFRESH_DEFAULT, + }, +} + +const { + ephemeral: initialEphemeralState, + persisted: initialPersistedState, +} = initialState + +const ephemeralReducer = (state = initialEphemeralState, action) => { + switch (action.type) { + case 'ENABLE_PRESENTATION_MODE': { + return { + ...state, + inPresentationMode: true, + } + } + + case 'DISABLE_PRESENTATION_MODE': { + return { + ...state, + inPresentationMode: false, + } + } + + default: + return state + } +} + +const persistedReducer = (state = initialPersistedState, action) => { + switch (action.type) { + case 'SET_AUTOREFRESH': { + return { + ...state, + autoRefresh: action.payload.milliseconds, + } + } + + default: + return state + } +} + +export default combineReducers({ + ephemeral: ephemeralReducer, + persisted: persistedReducer, +}) diff --git a/ui/src/shared/reducers/index.js b/ui/src/shared/reducers/index.js index 47ed0c62f4..bf191ecd78 100644 --- a/ui/src/shared/reducers/index.js +++ b/ui/src/shared/reducers/index.js @@ -1,13 +1,13 @@ -import appUI from './ui'; import me from './me'; +import app from './app'; import auth from './auth'; import notifications from './notifications'; import sources from './sources'; -export { - appUI, +export default { me, + app, auth, notifications, sources, -}; +} diff --git a/ui/src/shared/reducers/ui.js b/ui/src/shared/reducers/ui.js deleted file mode 100644 index 77a2f77a8a..0000000000 --- a/ui/src/shared/reducers/ui.js +++ /dev/null @@ -1,23 +0,0 @@ -const initialState = { - presentationMode: false, -}; - -export default function ui(state = initialState, action) { - switch (action.type) { - case 'ENABLE_PRESENTATION_MODE': { - return { - ...state, - presentationMode: true, - } - } - - case 'DISABLE_PRESENTATION_MODE': { - return { - ...state, - presentationMode: false, - } - } - } - - return state -} diff --git a/ui/src/side_nav/containers/SideNavApp.js b/ui/src/side_nav/containers/SideNavApp.js index a93bffdf72..5c25415718 100644 --- a/ui/src/side_nav/containers/SideNavApp.js +++ b/ui/src/side_nav/containers/SideNavApp.js @@ -34,11 +34,9 @@ const SideNavApp = React.createClass({ }, }); -function mapStateToProps(state) { - return { - me: state.me, - inPresentationMode: state.appUI.presentationMode, - }; -} +const mapStateToProps = ({me, app: {ephemeral: {inPresentationMode}}}) => ({ + me, + inPresentationMode, +}) export default connect(mapStateToProps)(SideNavApp); diff --git a/ui/src/store/configureStore.js b/ui/src/store/configureStore.js index 44b03fa66c..5aa6b77eee 100644 --- a/ui/src/store/configureStore.js +++ b/ui/src/store/configureStore.js @@ -3,8 +3,8 @@ import {combineReducers} from 'redux'; import thunkMiddleware from 'redux-thunk'; import makeQueryExecuter from 'src/shared/middleware/queryExecuter'; import resizeLayout from 'src/shared/middleware/resizeLayout'; -import * as dataExplorerReducers from 'src/data_explorer/reducers'; -import * as sharedReducers from 'src/shared/reducers'; +import sharedReducers from 'src/shared/reducers'; +import dataExplorerReducers from 'src/data_explorer/reducers'; import rulesReducer from 'src/kapacitor/reducers/rules'; import dashboardUI from 'src/dashboards/reducers/ui'; import persistStateEnhancer from './persistStateEnhancer';