mirror of
https://github.com/getredash/redash.git
synced 2026-03-21 16:00:09 -04:00
* stop testing `collect_query_parameters`, it's an implementation detail * add tests for `missing_query_params` * rename SQLQuery -> ParameterizedSqlQuery * rename sql_query.py to parameterized_query.py * split to parameterized queries and parameterized SQL queries, where parameterized queries only do templating and parameterized SQL queries add tree validation on top of it * move missing parameter detection to ParameterizedQuery * get rid of some old code * fix tests * set syntax to `custom` * revert the max-age-related refactoring * 👋 tree validations 😢 * BaseQueryRunner is no longer a factory for ParameterizedQuery, for now * add an endpoint for running a query by its id and (optional) parameters without having to provide the query text * adds parameter schema to ParameterizedQuery * adds parameter schema validation (currently for strings) * validate number parameters * validate date parameters * validate parameters on POST /api/queries/<id>/results * validate enum parameters * validate date range parameters * validate query-based dropdowns by preprocessing them at the handler level and converting them to a populated enum * change _is_date_range to be a tad more succinct * a single assignment with a `map` is sufficiently explanatory * Update redash/utils/parameterized_query.py Co-Authored-By: rauchy <omer@rauchy.net> * Update redash/utils/parameterized_query.py Co-Authored-By: rauchy <omer@rauchy.net> * Update redash/utils/parameterized_query.py Co-Authored-By: rauchy <omer@rauchy.net> * Update redash/utils/parameterized_query.py Co-Authored-By: rauchy <omer@rauchy.net> * Update redash/handlers/query_results.py Co-Authored-By: rauchy <omer@rauchy.net> * Update redash/utils/parameterized_query.py Co-Authored-By: rauchy <omer@rauchy.net> * build error message inside the error * support all types of numbers as number parameters * check for permissions when populating query-based dropdowns * check for access to query before running it * check for empty rows when populating query-based enums * don't bother loading query results if user doesn't have access * 💥 on unexpected parameter types * parameter schema default is a list, not a dictionary * fix a totally unrelated typo * remove redundant null guards * introduce /dropdown.json endpoint with dummy data * wire frontend to /dropdown.json * always return name/value combos from /dropdown.json * load actual data into /dropdown.json * pluck correct values for `name` and `value` * reuse dropdwon plucking logic in QueryResultResource * simplify _get_dropdown_values * when doing parameter validation, we only care about the value and not the display name * rename dropdown to dropdownOptions * move dropdown_values to utils/parameterized_query.py * stop converting queries to enums and encapsulate the work inside ParameterizedQuery (almost - /dropdown.json would still access the dropdown_values method) * re-order arguments by importance * test query parameter validation * tests for dropdown_values logic * remove `.json` suffix to the dropdown endpoint * allow `BaseResource` to handle JSON stuff * move _pluck_name_and_value outside its containing method * case-insensitive lookup when plucking name and value * separate concerns and simplify test isolation for `dropdown_values` * pick the default column according to the order specified in the query result columns attribute * use `current_org` instead of passing `org` * test that user has access to the query when calling the /dropdown endpoint
86 lines
2.3 KiB
JavaScript
86 lines
2.3 KiB
JavaScript
import { find, isFunction } from 'lodash';
|
|
import React from 'react';
|
|
import PropTypes from 'prop-types';
|
|
import { react2angular } from 'react2angular';
|
|
import Select from 'antd/lib/select';
|
|
import { Query } from '@/services/query';
|
|
|
|
const { Option } = Select;
|
|
|
|
export class QueryBasedParameterInput extends React.Component {
|
|
static propTypes = {
|
|
value: PropTypes.any, // eslint-disable-line react/forbid-prop-types
|
|
queryId: PropTypes.number,
|
|
onSelect: PropTypes.func,
|
|
className: PropTypes.string,
|
|
};
|
|
|
|
static defaultProps = {
|
|
value: null,
|
|
queryId: null,
|
|
onSelect: () => {},
|
|
className: '',
|
|
};
|
|
|
|
constructor(props) {
|
|
super(props);
|
|
this.state = {
|
|
options: [],
|
|
loading: false,
|
|
};
|
|
}
|
|
|
|
componentDidMount() {
|
|
this._loadOptions(this.props.queryId);
|
|
}
|
|
|
|
// eslint-disable-next-line no-unused-vars
|
|
componentWillReceiveProps(nextProps) {
|
|
if (nextProps.queryId !== this.props.queryId) {
|
|
this._loadOptions(nextProps.queryId, nextProps.value);
|
|
}
|
|
}
|
|
|
|
_loadOptions(queryId) {
|
|
if (queryId && (queryId !== this.state.queryId)) {
|
|
this.setState({ loading: true });
|
|
Query.dropdownOptions({ id: queryId }, (options) => {
|
|
if (this.props.queryId === queryId) {
|
|
this.setState({ options, loading: false });
|
|
|
|
const found = find(options, option => option.value === this.props.value) !== undefined;
|
|
if (!found && isFunction(this.props.onSelect)) {
|
|
this.props.onSelect(options[0].value);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
render() {
|
|
const { className, value, onSelect } = this.props;
|
|
const { loading, options } = this.state;
|
|
return (
|
|
<span>
|
|
<Select
|
|
className={className}
|
|
disabled={loading || (options.length === 0)}
|
|
loading={loading}
|
|
defaultValue={value}
|
|
onChange={onSelect}
|
|
dropdownMatchSelectWidth={false}
|
|
dropdownClassName="ant-dropdown-in-bootstrap-modal"
|
|
>
|
|
{options.map(option => (<Option value={option.value} key={option.value}>{option.name}</Option>))}
|
|
</Select>
|
|
</span>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default function init(ngModule) {
|
|
ngModule.component('queryBasedParameterInput', react2angular(QueryBasedParameterInput));
|
|
}
|
|
|
|
init.init = true;
|