Merge pull request #962 from influxdata/revert-957-781-autorefresh_config

Revert "Allow user to set auto-refresh interval"
pull/966/head
Andrew Watkins 2017-03-03 14:22:26 -08:00 committed by GitHub
commit a483ce1c18
28 changed files with 125 additions and 329 deletions

View File

@ -21,7 +21,6 @@
4. [#892](https://github.com/influxdata/chronograf/issues/891): Make dashboard visualizations resizable 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 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) 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 ### UI Improvements
1. [#905](https://github.com/influxdata/chronograf/pull/905): Make scroll bar thumb element bigger 1. [#905](https://github.com/influxdata/chronograf/pull/905): Make scroll bar thumb element bigger

View File

@ -10,7 +10,6 @@ const Dashboard = ({
inPresentationMode, inPresentationMode,
onPositionChange, onPositionChange,
source, source,
autoRefresh,
timeRange, timeRange,
}) => { }) => {
if (dashboard.id === 0) { if (dashboard.id === 0) {
@ -21,13 +20,14 @@ const Dashboard = ({
<div className={classnames({'page-contents': true, 'presentation-mode': inPresentationMode})}> <div className={classnames({'page-contents': true, 'presentation-mode': inPresentationMode})}>
<div className={classnames('container-fluid full-width dashboard', {'dashboard-edit': isEditMode})}> <div className={classnames('container-fluid full-width dashboard', {'dashboard-edit': isEditMode})}>
{isEditMode ? <Visualizations/> : null} {isEditMode ? <Visualizations/> : null}
{Dashboard.renderDashboard(dashboard, autoRefresh, timeRange, source, onPositionChange)} {Dashboard.renderDashboard(dashboard, timeRange, source, onPositionChange)}
</div> </div>
</div> </div>
) )
} }
Dashboard.renderDashboard = (dashboard, autoRefresh, timeRange, source, onPositionChange) => { Dashboard.renderDashboard = (dashboard, timeRange, source, onPositionChange) => {
const autoRefreshMs = 15000
const cells = dashboard.cells.map((cell, i) => { const cells = dashboard.cells.map((cell, i) => {
i = `${i}` i = `${i}`
const dashboardCell = {...cell, i} const dashboardCell = {...cell, i}
@ -42,7 +42,7 @@ Dashboard.renderDashboard = (dashboard, autoRefresh, timeRange, source, onPositi
<LayoutRenderer <LayoutRenderer
timeRange={timeRange} timeRange={timeRange}
cells={cells} cells={cells}
autoRefresh={autoRefresh} autoRefreshMs={autoRefreshMs}
source={source.links.proxy} source={source.links.proxy}
onPositionChange={onPositionChange} onPositionChange={onPositionChange}
/> />
@ -54,7 +54,6 @@ const {
func, func,
shape, shape,
string, string,
number,
} = PropTypes } = PropTypes
Dashboard.propTypes = { Dashboard.propTypes = {
@ -67,7 +66,6 @@ Dashboard.propTypes = {
proxy: string, proxy: string,
}).isRequired, }).isRequired,
}).isRequired, }).isRequired,
autoRefresh: number.isRequired,
timeRange: shape({}).isRequired, timeRange: shape({}).isRequired,
} }

View File

@ -2,7 +2,6 @@ import React, {PropTypes} from 'react'
import ReactTooltip from 'react-tooltip' import ReactTooltip from 'react-tooltip'
import {Link} from 'react-router'; import {Link} from 'react-router';
import AutoRefreshDropdown from 'shared/components/AutoRefreshDropdown'
import TimeRangeDropdown from 'shared/components/TimeRangeDropdown' import TimeRangeDropdown from 'shared/components/TimeRangeDropdown'
const DashboardHeader = ({ const DashboardHeader = ({
@ -11,10 +10,8 @@ const DashboardHeader = ({
dashboard, dashboard,
headerText, headerText,
timeRange, timeRange,
autoRefresh,
isHidden, isHidden,
handleChooseTimeRange, handleChooseTimeRange,
handleChooseAutoRefresh,
handleClickPresentationButton, handleClickPresentationButton,
sourceID, sourceID,
}) => isHidden ? null : ( }) => isHidden ? null : (
@ -48,7 +45,6 @@ const DashboardHeader = ({
Graph Tips Graph Tips
</div> </div>
<ReactTooltip id="graph-tips-tooltip" effect="solid" html={true} offset={{top: 2}} place="bottom" class="influx-tooltip place-bottom" /> <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} /> <TimeRangeDropdown onChooseTimeRange={handleChooseTimeRange} selected={timeRange.inputValue} />
<div className="btn btn-info btn-sm" onClick={handleClickPresentationButton}> <div className="btn btn-info btn-sm" onClick={handleClickPresentationButton}>
<span className="icon expand-a" style={{margin: 0}}></span> <span className="icon expand-a" style={{margin: 0}}></span>
@ -59,12 +55,11 @@ const DashboardHeader = ({
) )
const { const {
array,
bool,
func,
number,
shape, shape,
array,
string, string,
func,
bool,
} = PropTypes } = PropTypes
DashboardHeader.propTypes = { DashboardHeader.propTypes = {
@ -74,10 +69,8 @@ DashboardHeader.propTypes = {
dashboard: shape({}), dashboard: shape({}),
headerText: string, headerText: string,
timeRange: shape({}).isRequired, timeRange: shape({}).isRequired,
autoRefresh: number.isRequired,
isHidden: bool.isRequired, isHidden: bool.isRequired,
handleChooseTimeRange: func.isRequired, handleChooseTimeRange: func.isRequired,
handleChooseAutoRefresh: func.isRequired,
handleClickPresentationButton: func.isRequired, handleClickPresentationButton: func.isRequired,
} }

View File

@ -51,7 +51,6 @@ const DashboardPage = React.createClass({
id: number.isRequired, id: number.isRequired,
cells: arrayOf(shape({})).isRequired, cells: arrayOf(shape({})).isRequired,
}).isRequired, }).isRequired,
autoRefresh: number.isRequired,
timeRange: shape({}).isRequired, timeRange: shape({}).isRequired,
inPresentationMode: bool.isRequired, inPresentationMode: bool.isRequired,
isEditMode: bool.isRequired, isEditMode: bool.isRequired,
@ -101,7 +100,6 @@ const DashboardPage = React.createClass({
isEditMode, isEditMode,
handleClickPresentationButton, handleClickPresentationButton,
source, source,
autoRefresh,
timeRange, timeRange,
} = this.props } = this.props
@ -112,7 +110,6 @@ const DashboardPage = React.createClass({
<EditHeader dashboard={dashboard} onSave={() => {}} /> : <EditHeader dashboard={dashboard} onSave={() => {}} /> :
<Header <Header
buttonText={dashboard ? dashboard.name : ''} buttonText={dashboard ? dashboard.name : ''}
autoRefresh={autoRefresh}
timeRange={timeRange} timeRange={timeRange}
handleChooseTimeRange={this.handleChooseTimeRange} handleChooseTimeRange={this.handleChooseTimeRange}
isHidden={inPresentationMode} isHidden={inPresentationMode}
@ -136,7 +133,6 @@ const DashboardPage = React.createClass({
isEditMode={isEditMode} isEditMode={isEditMode}
inPresentationMode={inPresentationMode} inPresentationMode={inPresentationMode}
source={source} source={source}
autoRefresh={autoRefresh}
timeRange={timeRange} timeRange={timeRange}
onPositionChange={this.handleUpdatePosition} onPositionChange={this.handleUpdatePosition}
/> />
@ -147,10 +143,7 @@ const DashboardPage = React.createClass({
const mapStateToProps = (state) => { const mapStateToProps = (state) => {
const { const {
app: { appUI,
ephemeral: {inPresentationMode},
persisted: {autoRefresh},
},
dashboardUI: { dashboardUI: {
dashboards, dashboards,
dashboard, dashboard,
@ -160,12 +153,11 @@ const mapStateToProps = (state) => {
} = state } = state
return { return {
inPresentationMode: appUI.presentationMode,
dashboards, dashboards,
dashboard, dashboard,
autoRefresh,
timeRange, timeRange,
isEditMode, isEditMode,
inPresentationMode,
} }
} }

View File

@ -15,7 +15,6 @@ const {
const Visualization = React.createClass({ const Visualization = React.createClass({
propTypes: { propTypes: {
autoRefresh: number.isRequired,
timeRange: shape({ timeRange: shape({
upper: string, upper: string,
lower: string, lower: string,
@ -46,7 +45,7 @@ const Visualization = React.createClass({
}, },
render() { render() {
const {queryConfigs, autoRefresh, timeRange, activeQueryIndex, height, heightPixels} = this.props; const {queryConfigs, timeRange, activeQueryIndex, height, heightPixels} = this.props;
const {source} = this.context; const {source} = this.context;
const proxyLink = source.links.proxy; const proxyLink = source.links.proxy;
@ -58,6 +57,7 @@ const Visualization = React.createClass({
const queries = statements.filter((s) => s.text !== null).map((s) => { const queries = statements.filter((s) => s.text !== null).map((s) => {
return {host: [proxyLink], text: s.text, id: s.id}; return {host: [proxyLink], text: s.text, id: s.id};
}); });
const autoRefreshMs = 10000;
const isInDataExplorer = true; const isInDataExplorer = true;
return ( return (
@ -77,7 +77,7 @@ const Visualization = React.createClass({
{isGraphInView ? ( {isGraphInView ? (
<RefreshingLineGraph <RefreshingLineGraph
queries={queries} queries={queries}
autoRefresh={autoRefresh} autoRefresh={autoRefreshMs}
activeQueryIndex={activeQueryIndex} activeQueryIndex={activeQueryIndex}
isInDataExplorer={isInDataExplorer} isInDataExplorer={isInDataExplorer}
/> />

View File

@ -1,18 +1,17 @@
import React, {PropTypes} from 'react'; import React, {PropTypes} from 'react';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import QueryBuilder from '../components/QueryBuilder'; import QueryBuilder from '../components/QueryBuilder';
import Visualization from '../components/Visualization'; import Visualization from '../components/Visualization';
import Header from '../containers/Header'; import Header from '../containers/Header';
import ResizeContainer from 'src/shared/components/ResizeContainer'; import ResizeContainer from 'src/shared/components/ResizeContainer';
import {setAutoRefresh} from 'shared/actions/app' import {
import {setTimeRange as setTimeRangeAction} from '../actions/view'; setTimeRange as setTimeRangeAction,
} from '../actions/view';
const { const {
arrayOf, arrayOf,
func, func,
number,
shape, shape,
string, string,
} = PropTypes; } = PropTypes;
@ -26,8 +25,6 @@ const DataExplorer = React.createClass({
}).isRequired, }).isRequired,
}).isRequired, }).isRequired,
queryConfigs: PropTypes.shape({}), queryConfigs: PropTypes.shape({}),
autoRefresh: number.isRequired,
handleChooseAutoRefresh: func.isRequired,
timeRange: shape({ timeRange: shape({
upper: string, upper: string,
lower: string, lower: string,
@ -62,20 +59,18 @@ const DataExplorer = React.createClass({
}, },
render() { render() {
const {autoRefresh, handleChooseAutoRefresh, timeRange, setTimeRange, queryConfigs, dataExplorer} = this.props; const {timeRange, setTimeRange, queryConfigs, dataExplorer} = this.props;
const {activeQueryID} = this.state; const {activeQueryID} = this.state;
const queries = dataExplorer.queryIDs.map((qid) => queryConfigs[qid]); const queries = dataExplorer.queryIDs.map((qid) => queryConfigs[qid]);
return ( return (
<div className="data-explorer"> <div className="data-explorer">
<Header <Header
actions={{handleChooseAutoRefresh, setTimeRange}} actions={{setTimeRange}}
autoRefresh={autoRefresh}
timeRange={timeRange} timeRange={timeRange}
/> />
<ResizeContainer> <ResizeContainer>
<Visualization <Visualization
autoRefresh={autoRefresh}
timeRange={timeRange} timeRange={timeRange}
queryConfigs={queries} queryConfigs={queries}
activeQueryID={this.state.activeQueryID} activeQueryID={this.state.activeQueryID}
@ -83,7 +78,6 @@ const DataExplorer = React.createClass({
/> />
<QueryBuilder <QueryBuilder
queries={queries} queries={queries}
autoRefresh={autoRefresh}
timeRange={timeRange} timeRange={timeRange}
setActiveQuery={this.handleSetActiveQuery} setActiveQuery={this.handleSetActiveQuery}
activeQueryID={activeQueryID} activeQueryID={activeQueryID}
@ -95,21 +89,15 @@ const DataExplorer = React.createClass({
}); });
function mapStateToProps(state) { function mapStateToProps(state) {
const {app: {persisted: {autoRefresh}}, timeRange, queryConfigs, dataExplorer} = state; const {timeRange, queryConfigs, dataExplorer} = state;
return { return {
autoRefresh,
timeRange, timeRange,
queryConfigs, queryConfigs,
dataExplorer, dataExplorer,
}; };
} }
function mapDispatchToProps(dispatch) { export default connect(mapStateToProps, {
return { setTimeRange: setTimeRangeAction,
handleChooseAutoRefresh: bindActionCreators(setAutoRefresh, dispatch), })(DataExplorer);
setTimeRange: bindActionCreators(setTimeRangeAction, dispatch),
}
}
export default connect(mapStateToProps, mapDispatchToProps)(DataExplorer);

View File

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

View File

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

View File

@ -1,7 +1,6 @@
import React, {PropTypes} from 'react' import React, {PropTypes} from 'react'
import {Link} from 'react-router' import {Link} from 'react-router'
import {connect} from 'react-redux' import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
import _ from 'lodash' import _ from 'lodash'
import classnames from 'classnames'; import classnames from 'classnames';
@ -10,8 +9,6 @@ import DashboardHeader from 'src/dashboards/components/DashboardHeader';
import timeRanges from 'hson!../../shared/data/timeRanges.hson'; import timeRanges from 'hson!../../shared/data/timeRanges.hson';
import {getMappings, getAppsForHosts, getMeasurementsForHost, getAllHosts} from 'src/hosts/apis'; import {getMappings, getAppsForHosts, getMeasurementsForHost, getAllHosts} from 'src/hosts/apis';
import {fetchLayouts} from 'shared/apis'; import {fetchLayouts} from 'shared/apis';
import {setAutoRefresh} from 'shared/actions/app'
import {presentationButtonDispatcher} from 'shared/dispatchers' import {presentationButtonDispatcher} from 'shared/dispatchers'
const { const {
@ -19,7 +16,6 @@ const {
string, string,
bool, bool,
func, func,
number,
} = PropTypes } = PropTypes
export const HostPage = React.createClass({ export const HostPage = React.createClass({
@ -39,8 +35,6 @@ export const HostPage = React.createClass({
app: string, app: string,
}), }),
}), }),
autoRefresh: number.isRequired,
handleChooseAutoRefresh: func.isRequired,
inPresentationMode: bool, inPresentationMode: bool,
handleClickPresentationButton: func, handleClickPresentationButton: func,
}, },
@ -93,8 +87,9 @@ export const HostPage = React.createClass({
}, },
renderLayouts(layouts) { renderLayouts(layouts) {
const autoRefreshMs = 15000;
const {timeRange} = this.state; const {timeRange} = this.state;
const {source, autoRefresh} = this.props; const {source} = this.props;
const autoflowLayouts = layouts.filter((layout) => !!layout.autoflow); const autoflowLayouts = layouts.filter((layout) => !!layout.autoflow);
@ -142,7 +137,7 @@ export const HostPage = React.createClass({
<LayoutRenderer <LayoutRenderer
timeRange={timeRange} timeRange={timeRange}
cells={layoutCells} cells={layoutCells}
autoRefresh={autoRefresh} autoRefreshMs={autoRefreshMs}
source={source.links.proxy} source={source.links.proxy}
host={this.props.params.hostID} host={this.props.params.hostID}
/> />
@ -150,7 +145,7 @@ export const HostPage = React.createClass({
}, },
render() { render() {
const {params: {hostID}, location: {query: {app}}, source: {id}, autoRefresh, handleChooseAutoRefresh, inPresentationMode, handleClickPresentationButton} = this.props const {params: {hostID}, location: {query: {app}}, source: {id}, inPresentationMode, handleClickPresentationButton} = this.props
const {layouts, timeRange, hosts} = this.state const {layouts, timeRange, hosts} = this.state
const appParam = app ? `?app=${app}` : '' const appParam = app ? `?app=${app}` : ''
@ -158,11 +153,9 @@ export const HostPage = React.createClass({
<div className="page"> <div className="page">
<DashboardHeader <DashboardHeader
buttonText={hostID} buttonText={hostID}
autoRefresh={autoRefresh}
timeRange={timeRange} timeRange={timeRange}
isHidden={inPresentationMode} isHidden={inPresentationMode}
handleChooseTimeRange={this.handleChooseTimeRange} handleChooseTimeRange={this.handleChooseTimeRange}
handleChooseAutoRefresh={handleChooseAutoRefresh}
handleClickPresentationButton={handleClickPresentationButton} handleClickPresentationButton={handleClickPresentationButton}
> >
{Object.keys(hosts).map((host, i) => { {Object.keys(hosts).map((host, i) => {
@ -188,13 +181,11 @@ export const HostPage = React.createClass({
}, },
}); });
const mapStateToProps = ({app: {ephemeral: {inPresentationMode}, persisted: {autoRefresh}}}) => ({ const mapStateToProps = (state) => ({
inPresentationMode, inPresentationMode: state.appUI.presentationMode,
autoRefresh,
}) })
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
handleChooseAutoRefresh: bindActionCreators(setAutoRefresh, dispatch),
handleClickPresentationButton: presentationButtonDispatcher(dispatch), handleClickPresentationButton: presentationButtonDispatcher(dispatch),
}) })

View File

@ -19,7 +19,7 @@ import configureStore from 'src/store/configureStore';
import {getMe, getSources} from 'shared/apis'; import {getMe, getSources} from 'shared/apis';
import {receiveMe} from 'shared/actions/me'; import {receiveMe} from 'shared/actions/me';
import {receiveAuth} from 'shared/actions/auth'; import {receiveAuth} from 'shared/actions/auth';
import {disablePresentationMode} from 'shared/actions/app'; import {disablePresentationMode} from 'shared/actions/ui';
import {loadLocalStorage} from './localStorage'; import {loadLocalStorage} from './localStorage';
import 'src/style/chronograf.scss'; import 'src/style/chronograf.scss';

View File

@ -6,12 +6,11 @@ import DashboardHeader from 'src/dashboards/components/DashboardHeader';
import timeRanges from 'hson!../../shared/data/timeRanges.hson'; import timeRanges from 'hson!../../shared/data/timeRanges.hson';
const { const {
shape,
string,
arrayOf, arrayOf,
bool, bool,
func, func,
number,
shape,
string,
} = PropTypes } = PropTypes
export const KubernetesDashboard = React.createClass({ export const KubernetesDashboard = React.createClass({
@ -23,8 +22,6 @@ export const KubernetesDashboard = React.createClass({
telegraf: string.isRequired, telegraf: string.isRequired,
}), }),
layouts: arrayOf(shape().isRequired).isRequired, layouts: arrayOf(shape().isRequired).isRequired,
autoRefresh: number.isRequired,
handleChooseAutoRefresh: func.isRequired,
inPresentationMode: bool.isRequired, inPresentationMode: bool.isRequired,
handleClickPresentationButton: func, handleClickPresentationButton: func,
}, },
@ -37,8 +34,9 @@ export const KubernetesDashboard = React.createClass({
}, },
renderLayouts(layouts) { renderLayouts(layouts) {
const autoRefreshMs = 15000;
const {timeRange} = this.state; const {timeRange} = this.state;
const {source, autoRefresh} = this.props; const {source} = this.props;
let layoutCells = []; let layoutCells = [];
layouts.forEach((layout) => { layouts.forEach((layout) => {
@ -58,7 +56,7 @@ export const KubernetesDashboard = React.createClass({
<LayoutRenderer <LayoutRenderer
timeRange={timeRange} timeRange={timeRange}
cells={layoutCells} cells={layoutCells}
autoRefresh={autoRefresh} autoRefreshMs={autoRefreshMs}
source={source.links.proxy} source={source.links.proxy}
/> />
); );
@ -70,7 +68,7 @@ export const KubernetesDashboard = React.createClass({
}, },
render() { render() {
const {layouts, autoRefresh, handleChooseAutoRefresh, inPresentationMode, handleClickPresentationButton} = this.props; const {layouts, inPresentationMode, handleClickPresentationButton} = this.props;
const {timeRange} = this.state; const {timeRange} = this.state;
const emptyState = ( const emptyState = (
<div className="generic-empty-state"> <div className="generic-empty-state">
@ -83,8 +81,6 @@ export const KubernetesDashboard = React.createClass({
<div className="page"> <div className="page">
<DashboardHeader <DashboardHeader
headerText="Kubernetes Dashboard" headerText="Kubernetes Dashboard"
autoRefresh={autoRefresh}
handleChooseAutoRefresh={handleChooseAutoRefresh}
timeRange={timeRange} timeRange={timeRange}
handleChooseTimeRange={this.handleChooseTimeRange} handleChooseTimeRange={this.handleChooseTimeRange}
isHidden={inPresentationMode} isHidden={inPresentationMode}

View File

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

View File

@ -9,12 +9,9 @@ export const loadLocalStorage = () => {
} }
}; };
export const saveToLocalStorage = ({app: {persisted}, queryConfigs, timeRange, dataExplorer}) => { export const saveToLocalStorage = ({queryConfigs, timeRange, dataExplorer}) => {
try { try {
const appPersisted = Object.assign({}, {app: {persisted}})
window.localStorage.setItem('state', JSON.stringify({ window.localStorage.setItem('state', JSON.stringify({
...appPersisted,
queryConfigs, queryConfigs,
timeRange, timeRange,
dataExplorer, dataExplorer,

View File

@ -1,22 +0,0 @@
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

@ -0,0 +1,19 @@
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,34 +6,25 @@ function _fetchTimeSeries(source, db, rp, query) {
return proxy({source, db, rp, query}); return proxy({source, db, rp, query});
} }
const {
element,
number,
arrayOf,
shape,
oneOfType,
string,
} = PropTypes
export default function AutoRefresh(ComposedComponent) { export default function AutoRefresh(ComposedComponent) {
const wrapper = React.createClass({ const wrapper = React.createClass({
displayName: `AutoRefresh_${ComposedComponent.displayName}`, displayName: `AutoRefresh_${ComposedComponent.displayName}`,
propTypes: { propTypes: {
children: element, children: PropTypes.element,
autoRefresh: number.isRequired, autoRefresh: PropTypes.number,
queries: arrayOf(shape({ queries: PropTypes.arrayOf(PropTypes.shape({
host: oneOfType([string, arrayOf(string)]), host: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
text: string, text: PropTypes.string,
}).isRequired).isRequired, }).isRequired).isRequired,
}, },
getInitialState() { getInitialState() {
return {timeSeries: []}; return {timeSeries: []};
}, },
componentDidMount() { componentDidMount() {
const {queries, autoRefresh} = this.props; const {queries} = this.props;
this.executeQueries(queries); this.executeQueries(queries);
if (autoRefresh) { if (this.props.autoRefresh) {
this.intervalID = setInterval(() => this.executeQueries(queries), autoRefresh); this.intervalID = setInterval(() => this.executeQueries(queries), this.props.autoRefresh);
} }
}, },
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {

View File

@ -1,72 +0,0 @@
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 (
<div className="dropdown time-range-dropdown">
<div className="btn btn-sm btn-info dropdown-toggle" onClick={() => self.toggleMenu()}>
<span className="icon refresh"></span>
<span className="selected-time-range">{this.findAutoRefreshItem(selected).inputValue}</span>
<span className="caret" />
</div>
<ul className={classnames("dropdown-menu", {show: isOpen})}>
<li className="dropdown-header">AutoRefresh Interval</li>
{autoRefreshItems.map((item) => {
return (
<li key={item.menuOption}>
<a href="#" onClick={() => self.handleSelection(item.milliseconds)}>
{item.menuOption}
</a>
</li>
);
})}
</ul>
</div>
);
},
});
export default OnClickOutside(AutoRefreshDropdown);

View File

@ -1,23 +1,14 @@
import React, {PropTypes} from 'react'; import React, {PropTypes} from 'react';
import classnames from 'classnames';
import OnClickOutside from 'shared/components/OnClickOutside'; import OnClickOutside from 'shared/components/OnClickOutside';
const {
arrayOf,
shape,
string,
func,
} = PropTypes
const Dropdown = React.createClass({ const Dropdown = React.createClass({
propTypes: { propTypes: {
items: arrayOf(shape({ items: PropTypes.arrayOf(PropTypes.shape({
text: string.isRequired, text: PropTypes.string.isRequired,
})).isRequired, })).isRequired,
onChoose: func.isRequired, onChoose: PropTypes.func.isRequired,
selected: string.isRequired, selected: PropTypes.string.isRequired,
iconName: string, className: PropTypes.string,
className: string,
}, },
getInitialState() { getInitialState() {
return { return {
@ -48,12 +39,11 @@ const Dropdown = React.createClass({
}, },
render() { render() {
const self = this; const self = this;
const {items, selected, className, iconName, actions} = self.props; const {items, selected, className, actions} = self.props;
return ( return (
<div onClick={this.toggleMenu} className={`dropdown ${className}`}> <div onClick={this.toggleMenu} className={`dropdown ${className}`}>
<div className="btn btn-sm btn-info dropdown-toggle"> <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="dropdown-selected">{selected}</span>
<span className="caret" /> <span className="caret" />
</div> </div>

View File

@ -18,7 +18,6 @@ const {
export const LayoutRenderer = React.createClass({ export const LayoutRenderer = React.createClass({
propTypes: { propTypes: {
autoRefresh: number.isRequired,
timeRange: shape({ timeRange: shape({
defaultGroupBy: string.isRequired, defaultGroupBy: string.isRequired,
queryValue: string.isRequired, queryValue: string.isRequired,
@ -47,6 +46,7 @@ export const LayoutRenderer = React.createClass({
name: string.isRequired, name: string.isRequired,
}).isRequired }).isRequired
), ),
autoRefreshMs: number.isRequired,
host: string, host: string,
source: string, source: string,
onPositionChange: func, onPositionChange: func,
@ -84,7 +84,7 @@ export const LayoutRenderer = React.createClass({
}, },
generateVisualizations() { generateVisualizations() {
const {autoRefresh, source, cells} = this.props; const {autoRefreshMs, source, cells} = this.props;
return cells.map((cell) => { return cells.map((cell) => {
const qs = cell.queries.map((q) => { const qs = cell.queries.map((q) => {
@ -100,7 +100,7 @@ export const LayoutRenderer = React.createClass({
<div key={cell.i}> <div key={cell.i}>
<h2 className="dash-graph--heading">{cell.name || `Graph`}</h2> <h2 className="dash-graph--heading">{cell.name || `Graph`}</h2>
<div className="dash-graph--container"> <div className="dash-graph--container">
<RefreshingSingleStat queries={[qs[0]]} autoRefresh={autoRefresh} /> <RefreshingSingleStat queries={[qs[0]]} autoRefresh={autoRefreshMs} />
</div> </div>
</div> </div>
); );
@ -117,7 +117,7 @@ export const LayoutRenderer = React.createClass({
<div className="dash-graph--container"> <div className="dash-graph--container">
<RefreshingLineGraph <RefreshingLineGraph
queries={qs} queries={qs}
autoRefresh={autoRefresh} autoRefresh={autoRefreshMs}
showSingleStat={cell.type === "line-plus-single-stat"} showSingleStat={cell.type === "line-plus-single-stat"}
displayOptions={displayOptions} displayOptions={displayOptions}
/> />

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import classnames from 'classnames'; import cN from 'classnames';
import OnClickOutside from 'shared/components/OnClickOutside'; import OnClickOutside from 'shared/components/OnClickOutside';
import timeRanges from 'hson!../data/timeRanges.hson'; import timeRanges from 'hson!../data/timeRanges.hson';
@ -48,7 +48,7 @@ const TimeRangeDropdown = React.createClass({
<span className="selected-time-range">{selected}</span> <span className="selected-time-range">{selected}</span>
<span className="caret" /> <span className="caret" />
</div> </div>
<ul className={classnames("dropdown-menu", {show: isOpen})}> <ul className={cN("dropdown-menu", {show: isOpen})}>
<li className="dropdown-header">Time Range</li> <li className="dropdown-header">Time Range</li>
{timeRanges.map((item) => { {timeRanges.map((item) => {
return ( return (

View File

@ -470,5 +470,3 @@ export const STROKE_WIDTH = {
export const PRESENTATION_MODE_ANIMATION_DELAY = 0 // In milliseconds. export const PRESENTATION_MODE_ANIMATION_DELAY = 0 // In milliseconds.
export const PRESENTATION_MODE_NOTIFICATION_DELAY = 2000 // In milliseconds. export const PRESENTATION_MODE_NOTIFICATION_DELAY = 2000 // In milliseconds.
export const AUTOREFRESH_DEFAULT = 15000 // in milliseconds

View File

@ -1,7 +0,0 @@
[
{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'}
]

View File

@ -1,4 +1,4 @@
import {delayEnablePresentationMode} from 'shared/actions/app' import {delayEnablePresentationMode} from 'shared/actions/ui'
import {publishNotification, delayDismissNotification} from 'shared/actions/notifications' import {publishNotification, delayDismissNotification} from 'shared/actions/notifications'
import {PRESENTATION_MODE_NOTIFICATION_DELAY} from 'shared/constants' import {PRESENTATION_MODE_NOTIFICATION_DELAY} from 'shared/constants'

View File

@ -1,57 +0,0 @@
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 me from './me';
import app from './app';
import auth from './auth'; import auth from './auth';
import notifications from './notifications'; import notifications from './notifications';
import sources from './sources'; import sources from './sources';
export default { export {
appUI,
me, me,
app,
auth, auth,
notifications, notifications,
sources, sources,
} };

View File

@ -0,0 +1,23 @@
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,9 +34,11 @@ const SideNavApp = React.createClass({
}, },
}); });
const mapStateToProps = ({me, app: {ephemeral: {inPresentationMode}}}) => ({ function mapStateToProps(state) {
me, return {
inPresentationMode, me: state.me,
}) inPresentationMode: state.appUI.presentationMode,
};
}
export default connect(mapStateToProps)(SideNavApp); export default connect(mapStateToProps)(SideNavApp);

View File

@ -3,8 +3,8 @@ import {combineReducers} from 'redux';
import thunkMiddleware from 'redux-thunk'; import thunkMiddleware from 'redux-thunk';
import makeQueryExecuter from 'src/shared/middleware/queryExecuter'; import makeQueryExecuter from 'src/shared/middleware/queryExecuter';
import resizeLayout from 'src/shared/middleware/resizeLayout'; import resizeLayout from 'src/shared/middleware/resizeLayout';
import sharedReducers from 'src/shared/reducers'; import * as dataExplorerReducers from 'src/data_explorer/reducers';
import dataExplorerReducers from 'src/data_explorer/reducers'; import * as sharedReducers from 'src/shared/reducers';
import rulesReducer from 'src/kapacitor/reducers/rules'; import rulesReducer from 'src/kapacitor/reducers/rules';
import dashboardUI from 'src/dashboards/reducers/ui'; import dashboardUI from 'src/dashboards/reducers/ui';
import persistStateEnhancer from './persistStateEnhancer'; import persistStateEnhancer from './persistStateEnhancer';