Fix revert failure chain and thus: add autoRefresh with pause
parent
8a4ccc82d1
commit
2751a00813
|
@ -21,6 +21,7 @@
|
||||||
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
|
||||||
|
|
|
@ -10,6 +10,7 @@ const Dashboard = ({
|
||||||
inPresentationMode,
|
inPresentationMode,
|
||||||
onPositionChange,
|
onPositionChange,
|
||||||
source,
|
source,
|
||||||
|
autoRefresh,
|
||||||
timeRange,
|
timeRange,
|
||||||
}) => {
|
}) => {
|
||||||
if (dashboard.id === 0) {
|
if (dashboard.id === 0) {
|
||||||
|
@ -20,14 +21,13 @@ 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, timeRange, source, onPositionChange)}
|
{Dashboard.renderDashboard(dashboard, autoRefresh, timeRange, source, onPositionChange)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Dashboard.renderDashboard = (dashboard, timeRange, source, onPositionChange) => {
|
Dashboard.renderDashboard = (dashboard, autoRefresh, 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, timeRange, source, onPositionChange) =>
|
||||||
<LayoutRenderer
|
<LayoutRenderer
|
||||||
timeRange={timeRange}
|
timeRange={timeRange}
|
||||||
cells={cells}
|
cells={cells}
|
||||||
autoRefreshMs={autoRefreshMs}
|
autoRefresh={autoRefresh}
|
||||||
source={source.links.proxy}
|
source={source.links.proxy}
|
||||||
onPositionChange={onPositionChange}
|
onPositionChange={onPositionChange}
|
||||||
/>
|
/>
|
||||||
|
@ -54,6 +54,7 @@ const {
|
||||||
func,
|
func,
|
||||||
shape,
|
shape,
|
||||||
string,
|
string,
|
||||||
|
number,
|
||||||
} = PropTypes
|
} = PropTypes
|
||||||
|
|
||||||
Dashboard.propTypes = {
|
Dashboard.propTypes = {
|
||||||
|
@ -66,6 +67,7 @@ Dashboard.propTypes = {
|
||||||
proxy: string,
|
proxy: string,
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
|
autoRefresh: number.isRequired,
|
||||||
timeRange: shape({}).isRequired,
|
timeRange: shape({}).isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ 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 = ({
|
||||||
|
@ -10,8 +11,10 @@ const DashboardHeader = ({
|
||||||
dashboard,
|
dashboard,
|
||||||
headerText,
|
headerText,
|
||||||
timeRange,
|
timeRange,
|
||||||
|
autoRefresh,
|
||||||
isHidden,
|
isHidden,
|
||||||
handleChooseTimeRange,
|
handleChooseTimeRange,
|
||||||
|
handleChooseAutoRefresh,
|
||||||
handleClickPresentationButton,
|
handleClickPresentationButton,
|
||||||
sourceID,
|
sourceID,
|
||||||
}) => isHidden ? null : (
|
}) => isHidden ? null : (
|
||||||
|
@ -45,6 +48,7 @@ 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>
|
||||||
|
@ -55,11 +59,12 @@ const DashboardHeader = ({
|
||||||
)
|
)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
shape,
|
|
||||||
array,
|
array,
|
||||||
string,
|
|
||||||
func,
|
|
||||||
bool,
|
bool,
|
||||||
|
func,
|
||||||
|
number,
|
||||||
|
shape,
|
||||||
|
string,
|
||||||
} = PropTypes
|
} = PropTypes
|
||||||
|
|
||||||
DashboardHeader.propTypes = {
|
DashboardHeader.propTypes = {
|
||||||
|
@ -69,8 +74,10 @@ 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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,7 @@ 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,
|
||||||
|
@ -100,6 +101,7 @@ const DashboardPage = React.createClass({
|
||||||
isEditMode,
|
isEditMode,
|
||||||
handleClickPresentationButton,
|
handleClickPresentationButton,
|
||||||
source,
|
source,
|
||||||
|
autoRefresh,
|
||||||
timeRange,
|
timeRange,
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
|
@ -110,6 +112,7 @@ 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}
|
||||||
|
@ -133,6 +136,7 @@ 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}
|
||||||
/>
|
/>
|
||||||
|
@ -143,7 +147,10 @@ const DashboardPage = React.createClass({
|
||||||
|
|
||||||
const mapStateToProps = (state) => {
|
const mapStateToProps = (state) => {
|
||||||
const {
|
const {
|
||||||
appUI,
|
app: {
|
||||||
|
ephemeral: {inPresentationMode},
|
||||||
|
persisted: {autoRefresh},
|
||||||
|
},
|
||||||
dashboardUI: {
|
dashboardUI: {
|
||||||
dashboards,
|
dashboards,
|
||||||
dashboard,
|
dashboard,
|
||||||
|
@ -153,11 +160,12 @@ const mapStateToProps = (state) => {
|
||||||
} = state
|
} = state
|
||||||
|
|
||||||
return {
|
return {
|
||||||
inPresentationMode: appUI.presentationMode,
|
|
||||||
dashboards,
|
dashboards,
|
||||||
dashboard,
|
dashboard,
|
||||||
|
autoRefresh,
|
||||||
timeRange,
|
timeRange,
|
||||||
isEditMode,
|
isEditMode,
|
||||||
|
inPresentationMode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ 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,
|
||||||
|
@ -45,7 +46,7 @@ const Visualization = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {queryConfigs, timeRange, activeQueryIndex, height, heightPixels} = this.props;
|
const {queryConfigs, autoRefresh, timeRange, activeQueryIndex, height, heightPixels} = this.props;
|
||||||
const {source} = this.context;
|
const {source} = this.context;
|
||||||
const proxyLink = source.links.proxy;
|
const proxyLink = source.links.proxy;
|
||||||
|
|
||||||
|
@ -57,7 +58,6 @@ 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={autoRefreshMs}
|
autoRefresh={autoRefresh}
|
||||||
activeQueryIndex={activeQueryIndex}
|
activeQueryIndex={activeQueryIndex}
|
||||||
isInDataExplorer={isInDataExplorer}
|
isInDataExplorer={isInDataExplorer}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
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 {
|
import {setAutoRefresh} from 'shared/actions/app'
|
||||||
setTimeRange as setTimeRangeAction,
|
import {setTimeRange as setTimeRangeAction} from '../actions/view';
|
||||||
} from '../actions/view';
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
arrayOf,
|
arrayOf,
|
||||||
func,
|
func,
|
||||||
|
number,
|
||||||
shape,
|
shape,
|
||||||
string,
|
string,
|
||||||
} = PropTypes;
|
} = PropTypes;
|
||||||
|
@ -25,6 +26,8 @@ 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,
|
||||||
|
@ -59,18 +62,20 @@ const DataExplorer = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {timeRange, setTimeRange, queryConfigs, dataExplorer} = this.props;
|
const {autoRefresh, handleChooseAutoRefresh, 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={{setTimeRange}}
|
actions={{handleChooseAutoRefresh, 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}
|
||||||
|
@ -78,6 +83,7 @@ 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}
|
||||||
|
@ -89,15 +95,21 @@ const DataExplorer = React.createClass({
|
||||||
});
|
});
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
function mapStateToProps(state) {
|
||||||
const {timeRange, queryConfigs, dataExplorer} = state;
|
const {app: {persisted: {autoRefresh}}, timeRange, queryConfigs, dataExplorer} = state;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
autoRefresh,
|
||||||
timeRange,
|
timeRange,
|
||||||
queryConfigs,
|
queryConfigs,
|
||||||
dataExplorer,
|
dataExplorer,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, {
|
function mapDispatchToProps(dispatch) {
|
||||||
setTimeRange: setTimeRangeAction,
|
return {
|
||||||
})(DataExplorer);
|
handleChooseAutoRefresh: bindActionCreators(setAutoRefresh, dispatch),
|
||||||
|
setTimeRange: bindActionCreators(setTimeRangeAction, dispatch),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(DataExplorer);
|
||||||
|
|
|
@ -1,23 +1,35 @@
|
||||||
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: {
|
||||||
timeRange: PropTypes.shape({
|
autoRefresh: number.isRequired,
|
||||||
upper: PropTypes.string,
|
timeRange: shape({
|
||||||
lower: PropTypes.string,
|
upper: string,
|
||||||
|
lower: string,
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
actions: PropTypes.shape({
|
actions: shape({
|
||||||
setTimeRange: PropTypes.func.isRequired,
|
handleChooseAutoRefresh: func.isRequired,
|
||||||
|
setTimeRange: func.isRequired,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
|
||||||
contextTypes: {
|
contextTypes: {
|
||||||
source: PropTypes.shape({
|
source: shape({
|
||||||
name: PropTypes.string,
|
name: string,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -36,7 +48,7 @@ const Header = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {timeRange} = this.props;
|
const {autoRefresh, actions: {handleChooseAutoRefresh}, timeRange} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="page-header">
|
<div className="page-header">
|
||||||
|
@ -50,6 +62,7 @@ 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>
|
||||||
|
|
|
@ -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 {
|
export default {
|
||||||
queryConfigs,
|
queryConfigs,
|
||||||
timeRange,
|
timeRange,
|
||||||
dataExplorer,
|
dataExplorer,
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
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';
|
||||||
|
|
||||||
|
@ -9,6 +10,8 @@ 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 {
|
||||||
|
@ -16,6 +19,7 @@ const {
|
||||||
string,
|
string,
|
||||||
bool,
|
bool,
|
||||||
func,
|
func,
|
||||||
|
number,
|
||||||
} = PropTypes
|
} = PropTypes
|
||||||
|
|
||||||
export const HostPage = React.createClass({
|
export const HostPage = React.createClass({
|
||||||
|
@ -35,6 +39,8 @@ export const HostPage = React.createClass({
|
||||||
app: string,
|
app: string,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
autoRefresh: number.isRequired,
|
||||||
|
handleChooseAutoRefresh: func.isRequired,
|
||||||
inPresentationMode: bool,
|
inPresentationMode: bool,
|
||||||
handleClickPresentationButton: func,
|
handleClickPresentationButton: func,
|
||||||
},
|
},
|
||||||
|
@ -87,9 +93,8 @@ export const HostPage = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
renderLayouts(layouts) {
|
renderLayouts(layouts) {
|
||||||
const autoRefreshMs = 15000;
|
|
||||||
const {timeRange} = this.state;
|
const {timeRange} = this.state;
|
||||||
const {source} = this.props;
|
const {source, autoRefresh} = this.props;
|
||||||
|
|
||||||
const autoflowLayouts = layouts.filter((layout) => !!layout.autoflow);
|
const autoflowLayouts = layouts.filter((layout) => !!layout.autoflow);
|
||||||
|
|
||||||
|
@ -137,7 +142,7 @@ export const HostPage = React.createClass({
|
||||||
<LayoutRenderer
|
<LayoutRenderer
|
||||||
timeRange={timeRange}
|
timeRange={timeRange}
|
||||||
cells={layoutCells}
|
cells={layoutCells}
|
||||||
autoRefreshMs={autoRefreshMs}
|
autoRefresh={autoRefresh}
|
||||||
source={source.links.proxy}
|
source={source.links.proxy}
|
||||||
host={this.props.params.hostID}
|
host={this.props.params.hostID}
|
||||||
/>
|
/>
|
||||||
|
@ -145,7 +150,7 @@ export const HostPage = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
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 {layouts, timeRange, hosts} = this.state
|
||||||
const appParam = app ? `?app=${app}` : ''
|
const appParam = app ? `?app=${app}` : ''
|
||||||
|
|
||||||
|
@ -153,9 +158,11 @@ 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) => {
|
||||||
|
@ -181,11 +188,13 @@ export const HostPage = React.createClass({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = ({app: {ephemeral: {inPresentationMode}, persisted: {autoRefresh}}}) => ({
|
||||||
inPresentationMode: state.appUI.presentationMode,
|
inPresentationMode,
|
||||||
|
autoRefresh,
|
||||||
})
|
})
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
handleChooseAutoRefresh: bindActionCreators(setAutoRefresh, dispatch),
|
||||||
handleClickPresentationButton: presentationButtonDispatcher(dispatch),
|
handleClickPresentationButton: presentationButtonDispatcher(dispatch),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -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/ui';
|
import {disablePresentationMode} from 'shared/actions/app';
|
||||||
import {loadLocalStorage} from './localStorage';
|
import {loadLocalStorage} from './localStorage';
|
||||||
|
|
||||||
import 'src/style/chronograf.scss';
|
import 'src/style/chronograf.scss';
|
||||||
|
|
|
@ -6,11 +6,12 @@ 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({
|
||||||
|
@ -22,6 +23,8 @@ 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,
|
||||||
},
|
},
|
||||||
|
@ -34,9 +37,8 @@ export const KubernetesDashboard = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
renderLayouts(layouts) {
|
renderLayouts(layouts) {
|
||||||
const autoRefreshMs = 15000;
|
|
||||||
const {timeRange} = this.state;
|
const {timeRange} = this.state;
|
||||||
const {source} = this.props;
|
const {source, autoRefresh} = this.props;
|
||||||
|
|
||||||
let layoutCells = [];
|
let layoutCells = [];
|
||||||
layouts.forEach((layout) => {
|
layouts.forEach((layout) => {
|
||||||
|
@ -56,7 +58,7 @@ export const KubernetesDashboard = React.createClass({
|
||||||
<LayoutRenderer
|
<LayoutRenderer
|
||||||
timeRange={timeRange}
|
timeRange={timeRange}
|
||||||
cells={layoutCells}
|
cells={layoutCells}
|
||||||
autoRefreshMs={autoRefreshMs}
|
autoRefresh={autoRefresh}
|
||||||
source={source.links.proxy}
|
source={source.links.proxy}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -68,7 +70,7 @@ export const KubernetesDashboard = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {layouts, inPresentationMode, handleClickPresentationButton} = this.props;
|
const {layouts, autoRefresh, handleChooseAutoRefresh, 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">
|
||||||
|
@ -81,6 +83,8 @@ 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}
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
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 {
|
||||||
shape,
|
|
||||||
string,
|
|
||||||
bool,
|
bool,
|
||||||
func,
|
func,
|
||||||
|
number,
|
||||||
|
shape,
|
||||||
|
string,
|
||||||
} = PropTypes
|
} = PropTypes
|
||||||
|
|
||||||
export const KubernetesPage = React.createClass({
|
export const KubernetesPage = React.createClass({
|
||||||
|
@ -19,6 +23,8 @@ 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,
|
||||||
},
|
},
|
||||||
|
@ -38,12 +44,14 @@ export const KubernetesPage = React.createClass({
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {layouts} = this.state
|
const {layouts} = this.state
|
||||||
const {source, inPresentationMode, handleClickPresentationButton} = this.props
|
const {source, autoRefresh, handleChooseAutoRefresh, 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}
|
||||||
/>
|
/>
|
||||||
|
@ -51,11 +59,13 @@ export const KubernetesPage = React.createClass({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = ({app: {ephemeral: {inPresentationMode}, persisted: {autoRefresh}}}) => ({
|
||||||
inPresentationMode: state.appUI.presentationMode,
|
inPresentationMode,
|
||||||
|
autoRefresh,
|
||||||
})
|
})
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
handleChooseAutoRefresh: bindActionCreators(setAutoRefresh, dispatch),
|
||||||
handleClickPresentationButton: presentationButtonDispatcher(dispatch),
|
handleClickPresentationButton: presentationButtonDispatcher(dispatch),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,12 @@ export const loadLocalStorage = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const saveToLocalStorage = ({queryConfigs, timeRange, dataExplorer}) => {
|
export const saveToLocalStorage = ({app: {persisted}, 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,
|
||||||
|
|
|
@ -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,
|
||||||
|
},
|
||||||
|
})
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,25 +6,34 @@ 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: PropTypes.element,
|
children: element,
|
||||||
autoRefresh: PropTypes.number,
|
autoRefresh: number.isRequired,
|
||||||
queries: PropTypes.arrayOf(PropTypes.shape({
|
queries: arrayOf(shape({
|
||||||
host: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
|
host: oneOfType([string, arrayOf(string)]),
|
||||||
text: PropTypes.string,
|
text: string,
|
||||||
}).isRequired).isRequired,
|
}).isRequired).isRequired,
|
||||||
},
|
},
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return {timeSeries: []};
|
return {timeSeries: []};
|
||||||
},
|
},
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const {queries} = this.props;
|
const {queries, autoRefresh} = this.props;
|
||||||
this.executeQueries(queries);
|
this.executeQueries(queries);
|
||||||
if (this.props.autoRefresh) {
|
if (autoRefresh) {
|
||||||
this.intervalID = setInterval(() => this.executeQueries(queries), this.props.autoRefresh);
|
this.intervalID = setInterval(() => this.executeQueries(queries), autoRefresh);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
|
|
|
@ -1,14 +1,23 @@
|
||||||
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: PropTypes.arrayOf(PropTypes.shape({
|
items: arrayOf(shape({
|
||||||
text: PropTypes.string.isRequired,
|
text: string.isRequired,
|
||||||
})).isRequired,
|
})).isRequired,
|
||||||
onChoose: PropTypes.func.isRequired,
|
onChoose: func.isRequired,
|
||||||
selected: PropTypes.string.isRequired,
|
selected: string.isRequired,
|
||||||
className: PropTypes.string,
|
iconName: string,
|
||||||
|
className: string,
|
||||||
},
|
},
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return {
|
return {
|
||||||
|
@ -39,11 +48,12 @@ const Dropdown = React.createClass({
|
||||||
},
|
},
|
||||||
render() {
|
render() {
|
||||||
const self = this;
|
const self = this;
|
||||||
const {items, selected, className, actions} = self.props;
|
const {items, selected, className, iconName, 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>
|
||||||
|
|
|
@ -18,6 +18,7 @@ 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,
|
||||||
|
@ -46,7 +47,6 @@ 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 {autoRefreshMs, source, cells} = this.props;
|
const {autoRefresh, 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={autoRefreshMs} />
|
<RefreshingSingleStat queries={[qs[0]]} autoRefresh={autoRefresh} />
|
||||||
</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={autoRefreshMs}
|
autoRefresh={autoRefresh}
|
||||||
showSingleStat={cell.type === "line-plus-single-stat"}
|
showSingleStat={cell.type === "line-plus-single-stat"}
|
||||||
displayOptions={displayOptions}
|
displayOptions={displayOptions}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import cN from 'classnames';
|
import classnames 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={cN("dropdown-menu", {show: isOpen})}>
|
<ul className={classnames("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 (
|
||||||
|
|
|
@ -470,3 +470,5 @@ 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
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {delayEnablePresentationMode} from 'shared/actions/ui'
|
import {delayEnablePresentationMode} from 'shared/actions/app'
|
||||||
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'
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
})
|
|
@ -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 {
|
export default {
|
||||||
appUI,
|
|
||||||
me,
|
me,
|
||||||
|
app,
|
||||||
auth,
|
auth,
|
||||||
notifications,
|
notifications,
|
||||||
sources,
|
sources,
|
||||||
};
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -34,11 +34,9 @@ const SideNavApp = React.createClass({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
const mapStateToProps = ({me, app: {ephemeral: {inPresentationMode}}}) => ({
|
||||||
return {
|
me,
|
||||||
me: state.me,
|
inPresentationMode,
|
||||||
inPresentationMode: state.appUI.presentationMode,
|
})
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps)(SideNavApp);
|
export default connect(mapStateToProps)(SideNavApp);
|
||||||
|
|
|
@ -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 * as dataExplorerReducers from 'src/data_explorer/reducers';
|
import sharedReducers from 'src/shared/reducers';
|
||||||
import * as sharedReducers from 'src/shared/reducers';
|
import dataExplorerReducers from 'src/data_explorer/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';
|
||||||
|
|
Loading…
Reference in New Issue