grafana/public/app/features/explore/QueryRow.tsx
Jack Westbrook 8d3b31ff23
Build: Upgrade Webpack 5 (#36444)
* build(webpack): bump to v5 and successful yarn start compilation

* build(webpack): update postcss dependencies

* build(webpack): silence warnings about hash renamed to fullhash

* build(webpack): enable persistent cache to store generated webpack modules / chunks

* build(webpack): prefer eslintWebpackPlugin over tschecker so eslint doesn't block typechecking

* chore(yarn): run yarn-deduplicate to clean up dependencies

* chore(yarn): refresh lock file after clean install

* build(webpack): prefer output.clean over CleanWebpackPlugin

* build(webpack): prefer esbuild over babel-loader for dev config

* build(babel): turn off cache compression to improve build performance

* build(webpack): get production builds working

* build(webpack): remove phantomJS (removed from grafana in v7) specific loader

* build(webpack): put back babel for dev builds no performance gain in using esbuild in webpack

* build(webpack): prefer terser and optimise css plugins for prod. slower but smaller bundles

* build(webpack): clean up redundant code. inform postcss about node_modules

* build(webpack): remove deprecation warnings flag

* build(webpack): bump packages, dev performance optimisations, attempt to get hot working

* chore(storybook): use webpack 5 for dev and production builds

* build(storybook): speed up dev build

* chore(yarn): refresh lock file

* chore(webpack): bump webpack and related deps to latest

* refactor(webpack): put back inline-source-map, move start scripts out of grafana toolkit

* feat(webpack): prefer react-refresh over react-hot-loader

* build(webpack): update webpack.hot to use react-refresh

* chore: remove react-hot-loader from codebase

* refactor(queryeditorrow): fix circular dependency causing react-fast-refresh errors

* revert(webpack): remove stats.errorDetails from common config

* build(webpack): bump to v5 and successful yarn start compilation

* build(webpack): update postcss dependencies

* build(webpack): silence warnings about hash renamed to fullhash

* build(webpack): enable persistent cache to store generated webpack modules / chunks

* build(webpack): prefer eslintWebpackPlugin over tschecker so eslint doesn't block typechecking

* chore(yarn): run yarn-deduplicate to clean up dependencies

* chore(yarn): refresh lock file after clean install

* build(webpack): prefer output.clean over CleanWebpackPlugin

* build(webpack): prefer esbuild over babel-loader for dev config

* build(babel): turn off cache compression to improve build performance

* build(webpack): get production builds working

* build(webpack): remove phantomJS (removed from grafana in v7) specific loader

* build(webpack): put back babel for dev builds no performance gain in using esbuild in webpack

* build(webpack): prefer terser and optimise css plugins for prod. slower but smaller bundles

* build(webpack): clean up redundant code. inform postcss about node_modules

* build(webpack): remove deprecation warnings flag

* build(webpack): bump packages, dev performance optimisations, attempt to get hot working

* chore(storybook): use webpack 5 for dev and production builds

* build(storybook): speed up dev build

* chore(yarn): refresh lock file

* chore(webpack): bump webpack and related deps to latest

* refactor(webpack): put back inline-source-map, move start scripts out of grafana toolkit

* feat(webpack): prefer react-refresh over react-hot-loader

* build(webpack): update webpack.hot to use react-refresh

* chore: remove react-hot-loader from codebase

* refactor(queryeditorrow): fix circular dependency causing react-fast-refresh errors

* revert(webpack): remove stats.errorDetails from common config

* revert(webpack): remove include from babel-loader so symlinks (enterprise) work as before

* refactor(webpack): fix deprecation warnings in prod builds

* fix(storybook): fix failing builds due to replacing css-optimise webpack plugin

* fix(storybook): use raw-loader for svg icons

* build(webpack): fix dev script colors error

* chore(webpack): bump css-loader and react-refresh-webpack-plugin to latest versions

Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
2021-08-31 12:55:05 +02:00

204 lines
6.6 KiB
TypeScript

// Libraries
import React, { PureComponent } from 'react';
import { debounce, has } from 'lodash';
import { connect, ConnectedProps } from 'react-redux';
import AngularQueryEditor from './QueryEditor';
import { QueryRowActions } from './QueryRowActions';
import { StoreState } from 'app/types';
import { DataQuery, LoadingState, DataSourceApi } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { ExploreItemState, ExploreId } from 'app/types/explore';
import { highlightLogsExpressionAction } from './state/explorePane';
import { ErrorContainer } from './ErrorContainer';
import { changeQuery, modifyQueries, removeQueryRowAction, runQueries } from './state/query';
import { HelpToggle } from '../query/components/HelpToggle';
interface OwnProps {
exploreId: ExploreId;
index: number;
}
type QueryRowProps = OwnProps & ConnectedProps<typeof connector>;
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 = (datasourceInstance: DataSourceApi) => {
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 = (datasourceInstance: DataSourceApi) => {
const { history, query, exploreEvents, range, queryResponse, exploreId } = this.props;
const queryErrors = queryResponse.error && queryResponse.error.refId === query.refId ? [queryResponse.error] : [];
const ReactQueryEditor = this.setReactQueryEditor(datasourceInstance);
let QueryEditor: JSX.Element;
if (ReactQueryEditor) {
QueryEditor = (
<ReactQueryEditor
datasource={datasourceInstance}
query={query}
history={history}
onRunQuery={this.onRunQuery}
onBlur={noopOnBlur}
onChange={this.onChange}
data={queryResponse}
range={range}
exploreId={exploreId}
/>
);
} else {
QueryEditor = (
<AngularQueryEditor
error={queryErrors}
datasource={datasourceInstance}
onQueryChange={this.onChange}
onExecuteQuery={this.onRunQuery}
initialQuery={query}
exploreEvents={exploreEvents}
range={range}
textEditModeEnabled={this.state.textEditModeEnabled}
/>
);
}
const DatasourceCheatsheet = datasourceInstance.components?.QueryEditorHelp;
return (
<>
{QueryEditor}
{DatasourceCheatsheet && (
<HelpToggle>
<DatasourceCheatsheet onClickExample={(query) => this.onChange(query)} datasource={datasourceInstance!} />
</HelpToggle>
)}
</>
);
};
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;
if (!datasourceInstance) {
return <>Loading data source</>;
}
const canToggleEditorModes = has(datasourceInstance, 'components.QueryCtrl.prototype.toggleEditorMode');
const isNotStarted = queryResponse.state === LoadingState.NotStarted;
// We show error without refId in ResponseErrorContainer so this condition needs to match se we don't loose errors.
const queryErrors = queryResponse.error && queryResponse.error.refId === query.refId ? [queryResponse.error] : [];
return (
<>
<div className="query-row" aria-label={selectors.components.QueryEditorRows.rows}>
<div className="query-row-field flex-shrink-1">{this.renderQueryEditor(datasourceInstance)}</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 }: OwnProps) {
const explore = state.explore;
const item: ExploreItemState = explore[exploreId]!;
const { datasourceInstance, history, queries, range, absoluteRange, queryResponse, latency, eventBridge } = item;
const query = queries[index];
return {
datasourceInstance,
history,
query,
range,
absoluteRange,
queryResponse,
latency,
exploreEvents: eventBridge,
};
}
const mapDispatchToProps = {
changeQuery,
highlightLogsExpressionAction,
modifyQueries,
removeQueryRowAction,
runQueries,
};
const connector = connect(mapStateToProps, mapDispatchToProps);
export default connector(QueryRow);