diff --git a/superset/assets/javascripts/SqlLab/components/SqlEditor.jsx b/superset/assets/javascripts/SqlLab/components/SqlEditor.jsx index a9bdb0f744..7307dd316a 100644 --- a/superset/assets/javascripts/SqlLab/components/SqlEditor.jsx +++ b/superset/assets/javascripts/SqlLab/components/SqlEditor.jsx @@ -15,10 +15,10 @@ import { } from 'react-bootstrap'; import SouthPane from './SouthPane'; -import Timer from './Timer'; - +import Timer from '../../components/Timer'; import SqlEditorLeftBar from './SqlEditorLeftBar'; import AceEditorWrapper from './AceEditorWrapper'; +import { STATE_BSSTYLE_MAP } from '../constants.js'; const propTypes = { actions: React.PropTypes.object.isRequired, @@ -208,7 +208,14 @@ class SqlEditor extends React.PureComponent {
{limitWarning} - + {this.props.latestQuery && + + }
); diff --git a/superset/assets/javascripts/SqlLab/components/Timer.jsx b/superset/assets/javascripts/SqlLab/components/Timer.jsx deleted file mode 100644 index 47c56ce825..0000000000 --- a/superset/assets/javascripts/SqlLab/components/Timer.jsx +++ /dev/null @@ -1,61 +0,0 @@ -import React from 'react'; -import { now, fDuration } from '../../modules/dates'; - -import { STATE_BSSTYLE_MAP } from '../constants.js'; - -class Timer extends React.PureComponent { - constructor(props) { - super(props); - this.state = { - clockStr: '', - }; - } - componentWillMount() { - this.startTimer(); - } - componentWillUnmount() { - this.stopTimer(); - } - startTimer() { - if (!(this.timer)) { - this.timer = setInterval(this.stopwatch.bind(this), 30); - } - } - stopTimer() { - clearInterval(this.timer); - this.timer = null; - } - stopwatch() { - if (this.props && this.props.query) { - const endDttm = this.props.query.endDttm || now(); - const clockStr = fDuration(this.props.query.startDttm, endDttm); - this.setState({ clockStr }); - if (this.props.query.state !== 'running') { - this.stopTimer(); - } - } - } - render() { - if (this.props.query && this.props.query.state === 'running') { - this.startTimer(); - } - let timerSpan = null; - if (this.props && this.props.query) { - const bsStyle = STATE_BSSTYLE_MAP[this.props.query.state]; - timerSpan = ( - - {this.state.clockStr} - - ); - } - return timerSpan; - } -} -Timer.propTypes = { - query: React.PropTypes.object, -}; -Timer.defaultProps = { - query: null, -}; - -export default Timer; diff --git a/superset/assets/javascripts/components/Timer.jsx b/superset/assets/javascripts/components/Timer.jsx new file mode 100644 index 0000000000..98b5883a63 --- /dev/null +++ b/superset/assets/javascripts/components/Timer.jsx @@ -0,0 +1,71 @@ +import React from 'react'; +import { now, fDuration } from '../modules/dates'; + +class Timer extends React.PureComponent { + constructor(props) { + super(props); + this.state = { + clockStr: '', + }; + } + componentWillMount() { + this.startTimer(); + } + componentWillUnmount() { + this.stopTimer(); + } + startTimer() { + if (!(this.timer)) { + this.timer = setInterval(this.stopwatch.bind(this), 30); + } + } + stopTimer() { + clearInterval(this.timer); + this.timer = null; + } + stopwatch() { + if (this.props && this.props.startTime) { + const endDttm = this.props.endTime || now(); + if (this.props.startTime < endDttm) { + const clockStr = fDuration(this.props.startTime, endDttm); + this.setState({ clockStr }); + } + if (!this.props.isRunning) { + this.stopTimer(); + } + } + } + render() { + if (this.props && this.props.isRunning) { + this.startTimer(); + } + let timerSpan = null; + if (this.props) { + timerSpan = ( + + {this.state.clockStr} + + ); + } + return timerSpan; + } +} +Timer.propTypes = { + startTime: React.PropTypes.number, + endTime: React.PropTypes.number, + isRunning: React.PropTypes.bool.isRequired, + status: React.PropTypes.string, + style: React.PropTypes.object, +}; + +Timer.defaultProps = { + startTime: null, + endTime: null, + status: 'success', + style: null, +}; + +export default Timer; diff --git a/superset/assets/javascripts/explorev2/actions/exploreActions.js b/superset/assets/javascripts/explorev2/actions/exploreActions.js index 1d48975e8a..08849e9b2f 100644 --- a/superset/assets/javascripts/explorev2/actions/exploreActions.js +++ b/superset/assets/javascripts/explorev2/actions/exploreActions.js @@ -115,7 +115,7 @@ export function chartUpdateFailed(error) { export function updateExplore(datasource_type, datasource_id, form_data) { return function (dispatch) { - dispatch(chartUpdateStarted); + dispatch(chartUpdateStarted()); const updateUrl = `/superset/update_explore/${datasource_type}/${datasource_id}/`; @@ -194,3 +194,8 @@ export function saveSlice(url) { }); }; } + +export const UPDATE_CHART_STATUS = 'UPDATE_CHART_STATUS'; +export function updateChartStatus(status) { + return { type: UPDATE_CHART_STATUS, status }; +} diff --git a/superset/assets/javascripts/explorev2/components/ChartContainer.jsx b/superset/assets/javascripts/explorev2/components/ChartContainer.jsx index 52f9692646..7cb2711482 100644 --- a/superset/assets/javascripts/explorev2/components/ChartContainer.jsx +++ b/superset/assets/javascripts/explorev2/components/ChartContainer.jsx @@ -7,6 +7,13 @@ import { d3format } from '../../modules/utils'; import ExploreActionButtons from '../../explore/components/ExploreActionButtons'; import FaveStar from '../../components/FaveStar'; import TooltipWrapper from '../../components/TooltipWrapper'; +import Timer from '../../components/Timer'; + +const CHART_STATUS_MAP = { + failed: 'danger', + loading: 'warning', + success: 'success', +}; const propTypes = { actions: PropTypes.object.isRequired, @@ -22,8 +29,10 @@ const propTypes = { query: PropTypes.string.isRequired, column_formats: PropTypes.object, data: PropTypes.any, - isChartLoading: PropTypes.bool, + chartStatus: PropTypes.bool, isStarred: PropTypes.bool.isRequired, + chartUpdateStartTime: PropTypes.string.isRequired, + chartUpdateEndTime: PropTypes.string.isRequired, alert: PropTypes.string, table_name: PropTypes.string, }; @@ -157,7 +166,7 @@ class ChartContainer extends React.Component { ); } - if (this.props.isChartLoading) { + if (this.props.chartStatus === 'loading') { return (loading); } return ( @@ -205,6 +214,13 @@ class ChartContainer extends React.Component { }
+ { const mockedProps = { - query: queries[0], + startTime: now(), + endTime: null, + isRunning: true, + state: 'warning', }; it('renders', () => { expect(React.isValidElement()).to.equal(true);