grafana/public/app/containers/Explore/QueryRows.tsx
David 7699451d94 Refactor Explore query field (#12643)
* Refactor Explore query field

- extract typeahead field that only contains logic for the typeahead
  mechanics
- renamed QueryField to PromQueryField, a wrapper around TypeaheadField
  that deals with Prometheus-specific concepts
- PromQueryField creates a promql typeahead by providing the handlers
  for producing suggestions, and for applying suggestions
- The `refresher` promise is needed to trigger a render once an async
  action in the wrapper returns.

This is prep work for a composable query field to be used by Explore, as
well as editors in datasource plugins.

* Added typeahead handling tests

- extracted context-to-suggestion logic to make it testable
- kept DOM-dependent parts in main onTypeahead funtion

* simplified error handling in explore query field

* Refactor query suggestions

- use monaco's suggestion types (roughly), see
  https://github.com/Microsoft/monaco-editor/blob/f6fb545/monaco.d.ts#L4208
- suggest functions and metrics in empty field (ctrl+space)
- copy and expand prometheus function docs from prometheus datasource
  (will be migrated back to the datasource in the future)

* Added prop and state types, removed unused cwrp

* Split up suggestion processing for code readability
2018-07-26 15:04:12 +03:00

82 lines
2.1 KiB
TypeScript

import React, { PureComponent } from 'react';
import QueryField from './PromQueryField';
class QueryRow extends PureComponent<any, any> {
constructor(props) {
super(props);
this.state = {
edited: false,
query: props.query || '',
};
}
handleChangeQuery = value => {
const { index, onChangeQuery } = this.props;
const { query } = this.state;
const edited = query !== value;
this.setState({ edited, query: value });
if (onChangeQuery) {
onChangeQuery(value, index);
}
};
handleClickAddButton = () => {
const { index, onAddQueryRow } = this.props;
if (onAddQueryRow) {
onAddQueryRow(index);
}
};
handleClickRemoveButton = () => {
const { index, onRemoveQueryRow } = this.props;
if (onRemoveQueryRow) {
onRemoveQueryRow(index);
}
};
handlePressEnter = () => {
const { onExecuteQuery } = this.props;
if (onExecuteQuery) {
onExecuteQuery();
}
};
render() {
const { request } = this.props;
const { edited, query } = this.state;
return (
<div className="query-row">
<div className="query-row-tools">
<button className="btn navbar-button navbar-button--tight" onClick={this.handleClickAddButton}>
<i className="fa fa-plus" />
</button>
<button className="btn navbar-button navbar-button--tight" onClick={this.handleClickRemoveButton}>
<i className="fa fa-minus" />
</button>
</div>
<div className="slate-query-field-wrapper">
<QueryField
initialQuery={edited ? null : query}
portalPrefix="explore"
onPressEnter={this.handlePressEnter}
onQueryChange={this.handleChangeQuery}
request={request}
/>
</div>
</div>
);
}
}
export default class QueryRows extends PureComponent<any, any> {
render() {
const { className = '', queries, ...handlers } = this.props;
return (
<div className={className}>
{queries.map((q, index) => <QueryRow key={q.key} index={index} query={q.query} {...handlers} />)}
</div>
);
}
}