Files
redash/client/app/components/QueryBasedParameterInput.jsx
Gabriel Dutra 8db1612689 Fix query based param with no results crashing page (#4707)
* Fix query based param with no results crashing page

* Add message for empty dropdown parameters

* Handle 500 no results case with empty result set

* Cypress: Make sure it shows the message

* Use .ant-select-selection to open dropdown
2020-03-24 14:48:14 +02:00

109 lines
3.0 KiB
JavaScript

import { find, isArray, get, first, map, intersection, isEqual, isEmpty } from "lodash";
import React from "react";
import PropTypes from "prop-types";
import Select from "antd/lib/select";
const { Option } = Select;
export default class QueryBasedParameterInput extends React.Component {
static propTypes = {
parameter: PropTypes.any, // eslint-disable-line react/forbid-prop-types
value: PropTypes.any, // eslint-disable-line react/forbid-prop-types
mode: PropTypes.oneOf(["default", "multiple"]),
queryId: PropTypes.number,
onSelect: PropTypes.func,
className: PropTypes.string,
};
static defaultProps = {
value: null,
mode: "default",
parameter: null,
queryId: null,
onSelect: () => {},
className: "",
};
constructor(props) {
super(props);
this.state = {
options: [],
value: null,
loading: false,
};
}
componentDidMount() {
this._loadOptions(this.props.queryId);
}
componentDidUpdate(prevProps) {
if (this.props.queryId !== prevProps.queryId) {
this._loadOptions(this.props.queryId);
}
if (this.props.value !== prevProps.value) {
this.setValue(this.props.value);
}
}
setValue(value) {
const { options } = this.state;
if (this.props.mode === "multiple") {
value = isArray(value) ? value : [value];
const optionValues = map(options, option => option.value);
const validValues = intersection(value, optionValues);
this.setState({ value: validValues });
return validValues;
}
const found = find(options, option => option.value === this.props.value) !== undefined;
value = found ? value : get(first(options), "value");
this.setState({ value });
return value;
}
async _loadOptions(queryId) {
if (queryId && queryId !== this.state.queryId) {
this.setState({ loading: true });
const options = await this.props.parameter.loadDropdownValues();
// stale queryId check
if (this.props.queryId === queryId) {
this.setState({ options, loading: false }, () => {
const updatedValue = this.setValue(this.props.value);
if (!isEqual(updatedValue, this.props.value)) {
this.props.onSelect(updatedValue);
}
});
}
}
}
render() {
const { className, value, mode, onSelect, ...otherProps } = this.props;
const { loading, options } = this.state;
return (
<span>
<Select
className={className}
disabled={loading}
loading={loading}
mode={mode}
value={this.state.value}
onChange={onSelect}
dropdownMatchSelectWidth={false}
optionFilterProp="children"
showSearch
showArrow
notFoundContent={isEmpty(options) ? "No options available" : null}
{...otherProps}>
{options.map(option => (
<Option value={option.value} key={option.value}>
{option.name}
</Option>
))}
</Select>
</span>
);
}
}