mirror of https://github.com/apache/superset.git
A few improvements to scheduling queries (#7585)
* Better message for scheduling queries * Only allow scheduling after success * Ask for query name and description * Use CSS instead of <br />
This commit is contained in:
parent
421183d3f4
commit
9c8f494c9d
|
@ -107,6 +107,17 @@ export function saveQuery(query) {
|
||||||
.catch(() => dispatch(addDangerToast(t('Your query could not be saved'))));
|
.catch(() => dispatch(addDangerToast(t('Your query could not be saved'))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function scheduleQuery(query) {
|
||||||
|
return dispatch =>
|
||||||
|
SupersetClient.post({
|
||||||
|
endpoint: '/savedqueryviewapi/api/create',
|
||||||
|
postPayload: query,
|
||||||
|
stringify: false,
|
||||||
|
})
|
||||||
|
.then(() => dispatch(addSuccessToast(t('Your query has been scheduled. To see details of your query, navigate to Saved Queries'))))
|
||||||
|
.catch(() => dispatch(addDangerToast(t('Your query could not be scheduled'))));
|
||||||
|
}
|
||||||
|
|
||||||
export function startQuery(query) {
|
export function startQuery(query) {
|
||||||
Object.assign(query, {
|
Object.assign(query, {
|
||||||
id: query.id ? query.id : shortid.generate(),
|
id: query.id ? query.id : shortid.generate(),
|
||||||
|
|
|
@ -20,6 +20,7 @@ import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Form from 'react-jsonschema-form';
|
import Form from 'react-jsonschema-form';
|
||||||
import chrono from 'chrono-node';
|
import chrono from 'chrono-node';
|
||||||
|
import { Col, FormControl, FormGroup, Row } from 'react-bootstrap';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
|
|
||||||
import Button from '../../components/Button';
|
import Button from '../../components/Button';
|
||||||
|
@ -76,11 +77,17 @@ const propTypes = {
|
||||||
dbId: PropTypes.number.isRequired,
|
dbId: PropTypes.number.isRequired,
|
||||||
animation: PropTypes.bool,
|
animation: PropTypes.bool,
|
||||||
onSchedule: PropTypes.func,
|
onSchedule: PropTypes.func,
|
||||||
|
scheduleQueryWarning: PropTypes.string,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
tooltip: PropTypes.string,
|
||||||
};
|
};
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
defaultLabel: t('Undefined'),
|
defaultLabel: t('Undefined'),
|
||||||
animation: true,
|
animation: true,
|
||||||
onSchedule: () => {},
|
onSchedule: () => {},
|
||||||
|
scheduleQueryWarning: null,
|
||||||
|
disabled: false,
|
||||||
|
tooltip: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
class ScheduleQueryButton extends React.PureComponent {
|
class ScheduleQueryButton extends React.PureComponent {
|
||||||
|
@ -123,12 +130,53 @@ class ScheduleQueryButton extends React.PureComponent {
|
||||||
}
|
}
|
||||||
renderModalBody() {
|
renderModalBody() {
|
||||||
return (
|
return (
|
||||||
|
<FormGroup>
|
||||||
|
<Row style={{ paddingBottom: '10px' }}>
|
||||||
|
<Col md={12}>
|
||||||
|
<label className="control-label" htmlFor="embed-height">
|
||||||
|
{t('Label')}
|
||||||
|
</label>
|
||||||
|
<FormControl
|
||||||
|
type="text"
|
||||||
|
placeholder={t('Label for your query')}
|
||||||
|
value={this.state.label}
|
||||||
|
onChange={this.onLabelChange}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{ paddingBottom: '10px' }}>
|
||||||
|
<Col md={12}>
|
||||||
|
<label className="control-label" htmlFor="embed-height">
|
||||||
|
{t('Description')}
|
||||||
|
</label>
|
||||||
|
<FormControl
|
||||||
|
componentClass="textarea"
|
||||||
|
placeholder={t('Write a description for your query')}
|
||||||
|
value={this.state.description}
|
||||||
|
onChange={this.onDescriptionChange}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Col md={12}>
|
||||||
<Form
|
<Form
|
||||||
schema={getJSONSchema()}
|
schema={getJSONSchema()}
|
||||||
uiSchema={getUISchema()}
|
uiSchema={getUISchema()}
|
||||||
onSubmit={this.onSchedule}
|
onSubmit={this.onSchedule}
|
||||||
validate={getValidator()}
|
validate={getValidator()}
|
||||||
/>
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
{this.props.scheduleQueryWarning && (
|
||||||
|
<Row>
|
||||||
|
<Col md={12}>
|
||||||
|
<small>
|
||||||
|
{this.props.scheduleQueryWarning}
|
||||||
|
</small>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
)}
|
||||||
|
</FormGroup>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
|
@ -139,7 +187,13 @@ class ScheduleQueryButton extends React.PureComponent {
|
||||||
modalTitle={t('Schedule Query')}
|
modalTitle={t('Schedule Query')}
|
||||||
modalBody={this.renderModalBody()}
|
modalBody={this.renderModalBody()}
|
||||||
triggerNode={
|
triggerNode={
|
||||||
<Button bsSize="small" className="toggleSchedule" onClick={this.toggleSchedule}>
|
<Button
|
||||||
|
bsSize="small"
|
||||||
|
className="toggleSchedule"
|
||||||
|
onClick={this.toggleSchedule}
|
||||||
|
disabled={this.props.disabled}
|
||||||
|
tooltip={this.props.tooltip}
|
||||||
|
>
|
||||||
<i className="fa fa-calendar" /> {t('Schedule Query')}
|
<i className="fa fa-calendar" /> {t('Schedule Query')}
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,13 +67,14 @@ const propTypes = {
|
||||||
defaultQueryLimit: PropTypes.number.isRequired,
|
defaultQueryLimit: PropTypes.number.isRequired,
|
||||||
maxRow: PropTypes.number.isRequired,
|
maxRow: PropTypes.number.isRequired,
|
||||||
saveQueryWarning: PropTypes.string,
|
saveQueryWarning: PropTypes.string,
|
||||||
|
scheduleQueryWarning: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
database: null,
|
database: null,
|
||||||
latestQuery: null,
|
latestQuery: null,
|
||||||
hideLeftBar: false,
|
hideLeftBar: false,
|
||||||
saveQueryWarning: null,
|
scheduleQueryWarning: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
class SqlEditor extends React.PureComponent {
|
class SqlEditor extends React.PureComponent {
|
||||||
|
@ -334,6 +335,10 @@ class SqlEditor extends React.PureComponent {
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
const successful = this.props.latestQuery && this.props.latestQuery.state === 'success';
|
||||||
|
const scheduleToolTip = successful
|
||||||
|
? t('Schedule the query periodically')
|
||||||
|
: t('You must run the query successfully first');
|
||||||
return (
|
return (
|
||||||
<div className="sql-toolbar" id="js-sql-toolbar">
|
<div className="sql-toolbar" id="js-sql-toolbar">
|
||||||
<div>
|
<div>
|
||||||
|
@ -355,9 +360,12 @@ class SqlEditor extends React.PureComponent {
|
||||||
defaultLabel={qe.title}
|
defaultLabel={qe.title}
|
||||||
sql={qe.sql}
|
sql={qe.sql}
|
||||||
className="m-r-5"
|
className="m-r-5"
|
||||||
onSchedule={this.props.actions.saveQuery}
|
onSchedule={this.props.actions.scheduleQuery}
|
||||||
schema={qe.schema}
|
schema={qe.schema}
|
||||||
dbId={qe.dbId}
|
dbId={qe.dbId}
|
||||||
|
scheduleQueryWarning={this.props.scheduleQueryWarning}
|
||||||
|
tooltip={scheduleToolTip}
|
||||||
|
disabled={!successful}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,11 +41,13 @@ const propTypes = {
|
||||||
tables: PropTypes.array.isRequired,
|
tables: PropTypes.array.isRequired,
|
||||||
offline: PropTypes.bool,
|
offline: PropTypes.bool,
|
||||||
saveQueryWarning: PropTypes.string,
|
saveQueryWarning: PropTypes.string,
|
||||||
|
scheduleQueryWarning: PropTypes.string,
|
||||||
};
|
};
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
queryEditors: [],
|
queryEditors: [],
|
||||||
offline: false,
|
offline: false,
|
||||||
saveQueryWarning: null,
|
saveQueryWarning: null,
|
||||||
|
scheduleQueryWarning: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
let queryCount = 1;
|
let queryCount = 1;
|
||||||
|
@ -250,6 +252,7 @@ class TabbedSqlEditors extends React.PureComponent {
|
||||||
defaultQueryLimit={this.props.defaultQueryLimit}
|
defaultQueryLimit={this.props.defaultQueryLimit}
|
||||||
maxRow={this.props.maxRow}
|
maxRow={this.props.maxRow}
|
||||||
saveQueryWarning={this.props.saveQueryWarning}
|
saveQueryWarning={this.props.saveQueryWarning}
|
||||||
|
scheduleQueryWarning={this.props.scheduleQueryWarning}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Tab>
|
</Tab>
|
||||||
|
@ -294,6 +297,7 @@ function mapStateToProps({ sqlLab, common }) {
|
||||||
defaultQueryLimit: common.conf.DEFAULT_SQLLAB_LIMIT,
|
defaultQueryLimit: common.conf.DEFAULT_SQLLAB_LIMIT,
|
||||||
maxRow: common.conf.SQL_MAX_ROW,
|
maxRow: common.conf.SQL_MAX_ROW,
|
||||||
saveQueryWarning: common.conf.SQLLAB_SAVE_WARNING_MESSAGE,
|
saveQueryWarning: common.conf.SQLLAB_SAVE_WARNING_MESSAGE,
|
||||||
|
scheduleQueryWarning: common.conf.SQLLAB_SCHEDULE_WARNING_MESSAGE,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
function mapDispatchToProps(dispatch) {
|
function mapDispatchToProps(dispatch) {
|
||||||
|
|
|
@ -357,8 +357,9 @@ DEFAULT_SQLLAB_LIMIT = 1000
|
||||||
# Maximum number of tables/views displayed in the dropdown window in SQL Lab.
|
# Maximum number of tables/views displayed in the dropdown window in SQL Lab.
|
||||||
MAX_TABLE_NAMES = 3000
|
MAX_TABLE_NAMES = 3000
|
||||||
|
|
||||||
# Adds a warning message on sqllab save query modal.
|
# Adds a warning message on sqllab save query and schedule query modals.
|
||||||
SQLLAB_SAVE_WARNING_MESSAGE = None
|
SQLLAB_SAVE_WARNING_MESSAGE = None
|
||||||
|
SQLLAB_SCHEDULE_WARNING_MESSAGE = None
|
||||||
|
|
||||||
# If defined, shows this text in an alert-warning box in the navbar
|
# If defined, shows this text in an alert-warning box in the navbar
|
||||||
# one example use case may be "STAGING" to make it clear that this is
|
# one example use case may be "STAGING" to make it clear that this is
|
||||||
|
|
Loading…
Reference in New Issue