Fix revert failure chain and thus: add autoRefresh with pause

pull/965/head
Jared Scheib 2017-03-03 15:30:33 -08:00
parent 8a4ccc82d1
commit 2751a00813
26 changed files with 250 additions and 125 deletions

View File

@ -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

View File

@ -10,6 +10,7 @@ const Dashboard = ({
inPresentationMode,
onPositionChange,
source,
autoRefresh,
timeRange,
}) => {
if (dashboard.id === 0) {
@ -20,14 +21,13 @@ const Dashboard = ({
<div className={classnames({'page-contents': true, 'presentation-mode': inPresentationMode})}>
<div className={classnames('container-fluid full-width dashboard', {'dashboard-edit': isEditMode})}>
{isEditMode ? <Visualizations/> : null}
{Dashboard.renderDashboard(dashboard, timeRange, source, onPositionChange)}
{Dashboard.renderDashboard(dashboard, autoRefresh, timeRange, source, onPositionChange)}
</div>
</div>
)
}
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) =>
<LayoutRenderer
timeRange={timeRange}
cells={cells}
autoRefreshMs={autoRefreshMs}
autoRefresh={autoRefresh}
source={source.links.proxy}
onPositionChange={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,
}

View File

@ -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
</div>
<ReactTooltip id="graph-tips-tooltip" effect="solid" html={true} offset={{top: 2}} place="bottom" class="influx-tooltip place-bottom" />
<AutoRefreshDropdown onChoose={handleChooseAutoRefresh} selected={autoRefresh} iconName="refresh" />
<TimeRangeDropdown onChooseTimeRange={handleChooseTimeRange} selected={timeRange.inputValue} />
<div className="btn btn-info btn-sm" onClick={handleClickPresentationButton}>
<span className="icon expand-a" style={{margin: 0}}></span>
@ -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,
}

View File

@ -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({
<EditHeader dashboard={dashboard} onSave={() => {}} /> :
<Header
buttonText={dashboard ? dashboard.name : ''}
autoRefresh={autoRefresh}
timeRange={timeRange}
handleChooseTimeRange={this.handleChooseTimeRange}
isHidden={inPresentationMode}
@ -133,6 +136,7 @@ const DashboardPage = React.createClass({
isEditMode={isEditMode}
inPresentationMode={inPresentationMode}
source={source}
autoRefresh={autoRefresh}
timeRange={timeRange}
onPositionChange={this.handleUpdatePosition}
/>
@ -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,
}
}

View File

@ -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 ? (
<RefreshingLineGraph
queries={queries}
autoRefresh={autoRefreshMs}
autoRefresh={autoRefresh}
activeQueryIndex={activeQueryIndex}
isInDataExplorer={isInDataExplorer}
/>

View File

@ -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 (
<div className="data-explorer">
<Header
actions={{setTimeRange}}
actions={{handleChooseAutoRefresh, setTimeRange}}
autoRefresh={autoRefresh}
timeRange={timeRange}
/>
<ResizeContainer>
<Visualization
autoRefresh={autoRefresh}
timeRange={timeRange}
queryConfigs={queries}
activeQueryID={this.state.activeQueryID}
@ -78,6 +83,7 @@ const DataExplorer = React.createClass({
/>
<QueryBuilder
queries={queries}
autoRefresh={autoRefresh}
timeRange={timeRange}
setActiveQuery={this.handleSetActiveQuery}
activeQueryID={activeQueryID}
@ -89,15 +95,21 @@ const DataExplorer = React.createClass({
});
function mapStateToProps(state) {
const {timeRange, queryConfigs, dataExplorer} = state;
const {app: {persisted: {autoRefresh}}, timeRange, queryConfigs, dataExplorer} = state;
return {
autoRefresh,
timeRange,
queryConfigs,
dataExplorer,
};
}
export default connect(mapStateToProps, {
setTimeRange: setTimeRangeAction,
})(DataExplorer);
function mapDispatchToProps(dispatch) {
return {
handleChooseAutoRefresh: bindActionCreators(setAutoRefresh, dispatch),
setTimeRange: bindActionCreators(setTimeRangeAction, dispatch),
}
}
export default connect(mapStateToProps, mapDispatchToProps)(DataExplorer);

View File

@ -1,23 +1,35 @@
import React, {PropTypes} from 'react';
import moment from 'moment';
import {withRouter} from 'react-router';
import AutoRefreshDropdown from 'shared/components/AutoRefreshDropdown'
import TimeRangeDropdown from '../../shared/components/TimeRangeDropdown';
import timeRanges from 'hson!../../shared/data/timeRanges.hson';
const {
func,
number,
shape,
string,
} = PropTypes
const Header = React.createClass({
propTypes: {
timeRange: PropTypes.shape({
upper: PropTypes.string,
lower: PropTypes.string,
autoRefresh: number.isRequired,
timeRange: shape({
upper: string,
lower: string,
}).isRequired,
actions: PropTypes.shape({
setTimeRange: PropTypes.func.isRequired,
actions: shape({
handleChooseAutoRefresh: func.isRequired,
setTimeRange: func.isRequired,
}),
},
contextTypes: {
source: PropTypes.shape({
name: PropTypes.string,
source: shape({
name: string,
}),
},
@ -36,7 +48,7 @@ const Header = React.createClass({
},
render() {
const {timeRange} = this.props;
const {autoRefresh, actions: {handleChooseAutoRefresh}, timeRange} = this.props;
return (
<div className="page-header">
@ -50,6 +62,7 @@ const Header = React.createClass({
<span className="icon cpu"></span>
{this.context.source.name}
</div>
<AutoRefreshDropdown onChoose={handleChooseAutoRefresh} selected={autoRefresh} iconName="refresh" />
<TimeRangeDropdown onChooseTimeRange={this.handleChooseTimeRange} selected={this.findSelected(timeRange)} />
</div>
</div>

View File

@ -2,8 +2,8 @@ import queryConfigs from './queryConfigs';
import timeRange from './timeRange';
import dataExplorer from './ui';
export {
export default {
queryConfigs,
timeRange,
dataExplorer,
};
}

View File

@ -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({
<LayoutRenderer
timeRange={timeRange}
cells={layoutCells}
autoRefreshMs={autoRefreshMs}
autoRefresh={autoRefresh}
source={source.links.proxy}
host={this.props.params.hostID}
/>
@ -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({
<div className="page">
<DashboardHeader
buttonText={hostID}
autoRefresh={autoRefresh}
timeRange={timeRange}
isHidden={inPresentationMode}
handleChooseTimeRange={this.handleChooseTimeRange}
handleChooseAutoRefresh={handleChooseAutoRefresh}
handleClickPresentationButton={handleClickPresentationButton}
>
{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),
})

View File

@ -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';

View File

@ -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({
<LayoutRenderer
timeRange={timeRange}
cells={layoutCells}
autoRefreshMs={autoRefreshMs}
autoRefresh={autoRefresh}
source={source.links.proxy}
/>
);
@ -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 = (
<div className="generic-empty-state">
@ -81,6 +83,8 @@ export const KubernetesDashboard = React.createClass({
<div className="page">
<DashboardHeader
headerText="Kubernetes Dashboard"
autoRefresh={autoRefresh}
handleChooseAutoRefresh={handleChooseAutoRefresh}
timeRange={timeRange}
handleChooseTimeRange={this.handleChooseTimeRange}
isHidden={inPresentationMode}

View File

@ -1,15 +1,19 @@
import React, {PropTypes} from 'react';
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
import {fetchLayouts} from 'shared/apis';
import KubernetesDashboard from 'src/kubernetes/components/KubernetesDashboard';
import {setAutoRefresh} from 'shared/actions/app'
import {presentationButtonDispatcher} from 'shared/dispatchers'
const {
shape,
string,
bool,
func,
number,
shape,
string,
} = PropTypes
export const KubernetesPage = React.createClass({
@ -19,6 +23,8 @@ export const KubernetesPage = React.createClass({
proxy: string.isRequired,
}).isRequired,
}),
autoRefresh: number.isRequired,
handleChooseAutoRefresh: func.isRequired,
inPresentationMode: bool.isRequired,
handleClickPresentationButton: func,
},
@ -38,12 +44,14 @@ export const KubernetesPage = React.createClass({
render() {
const {layouts} = this.state
const {source, inPresentationMode, handleClickPresentationButton} = this.props
const {source, autoRefresh, handleChooseAutoRefresh, inPresentationMode, handleClickPresentationButton} = this.props
return (
<KubernetesDashboard
layouts={layouts}
source={source}
autoRefresh={autoRefresh}
handleChooseAutoRefresh={handleChooseAutoRefresh}
inPresentationMode={inPresentationMode}
handleClickPresentationButton={handleClickPresentationButton}
/>
@ -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),
})

View File

@ -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,

View File

@ -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,
},
})

View File

@ -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)
}
}

View File

@ -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) {

View File

@ -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 (
<div onClick={this.toggleMenu} className={`dropdown ${className}`}>
<div className="btn btn-sm btn-info dropdown-toggle">
{iconName ? <span className={classnames("icon", {[iconName]: true})}></span> : null}
<span className="dropdown-selected">{selected}</span>
<span className="caret" />
</div>

View File

@ -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({
<div key={cell.i}>
<h2 className="dash-graph--heading">{cell.name || `Graph`}</h2>
<div className="dash-graph--container">
<RefreshingSingleStat queries={[qs[0]]} autoRefresh={autoRefreshMs} />
<RefreshingSingleStat queries={[qs[0]]} autoRefresh={autoRefresh} />
</div>
</div>
);
@ -117,7 +117,7 @@ export const LayoutRenderer = React.createClass({
<div className="dash-graph--container">
<RefreshingLineGraph
queries={qs}
autoRefresh={autoRefreshMs}
autoRefresh={autoRefresh}
showSingleStat={cell.type === "line-plus-single-stat"}
displayOptions={displayOptions}
/>

View File

@ -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({
<span className="selected-time-range">{selected}</span>
<span className="caret" />
</div>
<ul className={cN("dropdown-menu", {show: isOpen})}>
<ul className={classnames("dropdown-menu", {show: isOpen})}>
<li className="dropdown-header">Time Range</li>
{timeRanges.map((item) => {
return (

View File

@ -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

View File

@ -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'

View File

@ -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,
})

View File

@ -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,
};
}

View File

@ -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
}

View File

@ -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);

View File

@ -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';