grafana/public/app/features/explore/QueryRow.tsx

224 lines
6.6 KiB
TypeScript
Raw Normal View History

2019-01-17 10:59:47 -06:00
// Libraries
import React, { PureComponent } from 'react';
import debounce from 'lodash/debounce';
import has from 'lodash/has';
import { hot } from 'react-hot-loader';
// @ts-ignore
import { connect } from 'react-redux';
2019-01-17 10:59:47 -06:00
// Components
import AngularQueryEditor from './QueryEditor';
import { QueryRowActions } from './QueryRowActions';
2019-01-17 10:59:47 -06:00
// Actions
import { changeQuery, modifyQueries, runQueries } from './state/actions';
2019-01-17 10:59:47 -06:00
// Types
import { StoreState } from 'app/types';
import {
DataQuery,
DataSourceApi,
PanelData,
HistoryItem,
TimeRange,
AbsoluteTimeRange,
LoadingState,
} from '@grafana/data';
Explore: Adds Loki explore query editor (#21497) * Explore: updates grafana-data explore query field props with explore mode * Explore: updates query row to pass down explore mode to query fields * Explore: adds LokiExploreQueryEditor * Explore: updates loki query field form to render children * Explore: adds loki explore extra field component * Explore: adds extra field element to loki query field form * Explore: updates loki explore query editor to use extra field element * Explore: moves ExploreMode to grafana-data * Explore: updates query row limit string * Explore: adds maxLines to DataQuery * Explore: adds maxLines to loki datasource runRangeQueryWithFallback * Explore: adds onChangeQueryLimit to LokiExploreQueryEditor * Explore: updates loki explore query editor to render extra field only in logs mode * Explore: fixes query limits for live and legacy queries * Explore: fixes result processor max lines limit in get logs result * Explore: fixes Loki datasource limit test * Explore: removes unnecessary ExploreMode from Loki language provider * Explore: fixes formatting * Explore: updates grafana-data datasource types - replaces strings with explore mode enum * Explore: updates loki explore query field props to take ReactNode * Explore: updates the way we calculate loki query lines limit to fall back to 0 lines on negative or invalid input instead of datasource maxLines * Explore: updates result processor get logs result method to avoid counting invalid/negative line limits * Explore: updates loki result transformer to process only an appropriate slice of a result instead of an entire one * Explore: adds a method for query limit preprocessing/mapping * Explore: updates loki datasource run range query with fallback method to use options.maxDataPoints in dashboards * Explore: removes unnecessary maxlineslimt from getLogsResult in resultProcessor * Explore: moves line limit to metadata * Explore: adds an ability to specify input type of extra field * Explore: updates LokiExploreQueryEditor - adds an input type * Explore: updates LokiExploreQueryEditor to run queries when maxLines is positive * Explore: fixes failing import of ExploreMode * Explore: fixes reducers test imports formatting * Explore: updates Loki extra field with min value set to 0 * Explore: exports LokiExploreExtraFieldProps * Explore: adds render test of LokiExploreQueryEditor * Explore: adds LokiExploreQueryEditor snapshot * Explore: updates LokiExploreQueryEditor onChangeQueryLimit method to prevent it from running when query input is empty - fixes cheatsheet display issue * Explore: updates Loki editor snapshots * Explore: fixes typo in test set name in LokiExploreQueryEditor * Explore: adds a render test of LokiExploreExtraField * Explore: fixes typo in LokiExploreQueryEditor * Explore: updates LokiExploreQueryEditor snapshot due to timezone issues * Explore: updates LokiExploreExtraField to export both functional component and a version using memo * Explore: updates LokiExploreQueryEditor to export both functional component and memoized function * Explore: updates LokiExploreQueryEditor - removes unnecessary react fragment * Explore: updates LokiExploreQueryEditor snapshot * Explore: adds LokiExploreQueryEditor tests for different explore mode cases * Explore: fixes Loki datasource and result transformer * Explore: updates LokiExploreQueryEditor snapshot * Explore: updates LokiExploreQueryEditor tests and test setup * Explore: updates LokiExploreQueryEditor - refactors component * Explore: updates LokiExploreQueryEditor to use default import from LokiExploreExtraField * Explore: updates LokiExploreQueryEditor snapshot * Explore: fixes formatting * Explore: updates LokiExploreQueryEditor max lines change * Explore: updates LokiExploreQueryEditor tests checking ExtraFieldElement * Explore: adds mock loki datasource to LokiExploreQueryEditor * Explore: updates LokiExploreQueryEditor test mock - adds language provider * Explore: updates LokiExploreQueryEditor snapshot * Explore: updates Loki ResultTransformer to filter out rows on limit - logic to be moved into a component with new form styles * Explore: updates LokiExploreQueryEditor tests
2020-02-06 06:34:52 -06:00
import { ExploreItemState, ExploreId } from 'app/types/explore';
2019-01-17 10:59:47 -06:00
import { Emitter } from 'app/core/utils/emitter';
import { highlightLogsExpressionAction, removeQueryRowAction } from './state/actionTypes';
import { ErrorContainer } from './ErrorContainer';
2019-05-13 02:38:19 -05:00
interface PropsFromParent {
exploreId: ExploreId;
index: number;
exploreEvents: Emitter;
}
export interface QueryRowProps extends PropsFromParent {
changeQuery: typeof changeQuery;
className?: string;
exploreId: ExploreId;
datasourceInstance: DataSourceApi;
highlightLogsExpressionAction: typeof highlightLogsExpressionAction;
history: HistoryItem[];
2019-02-04 23:19:40 -06:00
query: DataQuery;
modifyQueries: typeof modifyQueries;
range: TimeRange;
absoluteRange: AbsoluteTimeRange;
removeQueryRowAction: typeof removeQueryRowAction;
runQueries: typeof runQueries;
queryResponse: PanelData;
latency: number;
}
interface QueryRowState {
textEditModeEnabled: boolean;
}
// Empty function to override blur execution on query field
const noopOnBlur = () => {};
export class QueryRow extends PureComponent<QueryRowProps, QueryRowState> {
state: QueryRowState = {
textEditModeEnabled: false,
};
onRunQuery = () => {
const { exploreId } = this.props;
this.props.runQueries(exploreId);
};
onChange = (query: DataQuery, override?: boolean) => {
const { datasourceInstance, exploreId, index } = this.props;
this.props.changeQuery(exploreId, query, index, override);
if (query && !override && datasourceInstance.getHighlighterExpression && index === 0) {
// Live preview of log search matches. Only use on first row for now
this.updateLogsHighlights(query);
}
};
onClickToggleDisabled = () => {
const { exploreId, index, query } = this.props;
const newQuery = {
...query,
hide: !query.hide,
};
this.props.changeQuery(exploreId, newQuery, index, true);
};
onClickRemoveButton = () => {
const { exploreId, index } = this.props;
this.props.removeQueryRowAction({ exploreId, index });
this.props.runQueries(exploreId);
};
onClickToggleEditorMode = () => {
this.setState({ textEditModeEnabled: !this.state.textEditModeEnabled });
};
setReactQueryEditor = () => {
const { datasourceInstance } = this.props;
let QueryEditor;
// TODO:unification
if (datasourceInstance.components?.ExploreMetricsQueryField) {
QueryEditor = datasourceInstance.components.ExploreMetricsQueryField;
} else if (datasourceInstance.components?.ExploreLogsQueryField) {
QueryEditor = datasourceInstance.components.ExploreLogsQueryField;
} else if (datasourceInstance.components?.ExploreQueryField) {
QueryEditor = datasourceInstance.components.ExploreQueryField;
} else {
QueryEditor = datasourceInstance.components?.QueryEditor;
}
return QueryEditor;
};
renderQueryEditor = () => {
const {
datasourceInstance,
history,
query,
exploreEvents,
range,
absoluteRange,
queryResponse,
exploreId,
} = this.props;
const queryErrors = queryResponse.error && queryResponse.error.refId === query.refId ? [queryResponse.error] : [];
const ReactQueryEditor = this.setReactQueryEditor();
if (ReactQueryEditor) {
return (
<ReactQueryEditor
datasource={datasourceInstance}
query={query}
history={history}
onRunQuery={this.onRunQuery}
onBlur={noopOnBlur}
onChange={this.onChange}
data={queryResponse}
absoluteRange={absoluteRange}
exploreId={exploreId}
/>
);
}
return (
<AngularQueryEditor
error={queryErrors}
datasource={datasourceInstance}
onQueryChange={this.onChange}
onExecuteQuery={this.onRunQuery}
initialQuery={query}
exploreEvents={exploreEvents}
range={range}
textEditModeEnabled={this.state.textEditModeEnabled}
/>
);
};
updateLogsHighlights = debounce((value: DataQuery) => {
const { datasourceInstance } = this.props;
if (datasourceInstance.getHighlighterExpression) {
const { exploreId } = this.props;
const expressions = datasourceInstance.getHighlighterExpression(value);
this.props.highlightLogsExpressionAction({ exploreId, expressions });
}
}, 500);
render() {
const { datasourceInstance, query, queryResponse, latency } = this.props;
const canToggleEditorModes = has(datasourceInstance, 'components.QueryCtrl.prototype.toggleEditorMode');
const isNotStarted = queryResponse.state === LoadingState.NotStarted;
const queryErrors = queryResponse.error && queryResponse.error.refId === query.refId ? [queryResponse.error] : [];
return (
<>
<div className="query-row">
<div className="query-row-field flex-shrink-1">{this.renderQueryEditor()}</div>
<QueryRowActions
canToggleEditorModes={canToggleEditorModes}
isDisabled={query.hide}
isNotStarted={isNotStarted}
latency={latency}
onClickToggleEditorMode={this.onClickToggleEditorMode}
onClickToggleDisabled={this.onClickToggleDisabled}
onClickRemoveButton={this.onClickRemoveButton}
/>
</div>
{queryErrors.length > 0 && <ErrorContainer queryError={queryErrors[0]} />}
</>
);
}
}
function mapStateToProps(state: StoreState, { exploreId, index }: QueryRowProps) {
const explore = state.explore;
const item: ExploreItemState = explore[exploreId];
const { datasourceInstance, history, queries, range, absoluteRange, queryResponse, latency } = item;
2019-02-04 23:19:40 -06:00
const query = queries[index];
return {
datasourceInstance,
history,
query,
range,
absoluteRange,
queryResponse,
latency,
};
}
const mapDispatchToProps = {
changeQuery,
highlightLogsExpressionAction,
modifyQueries,
removeQueryRowAction,
runQueries,
};
export default hot(module)(
connect(mapStateToProps, mapDispatchToProps)(QueryRow) as React.ComponentType<PropsFromParent>
);