mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Connect Explore child components to store
This commit is contained in:
parent
607f7c25de
commit
546a3a9d98
@ -6,86 +6,58 @@ import { AutoSizer } from 'react-virtualized';
|
||||
import { RawTimeRange, TimeRange } from '@grafana/ui';
|
||||
|
||||
import { DataSourceSelectItem } from 'app/types/datasources';
|
||||
import {
|
||||
ExploreItemState,
|
||||
ExploreUrlState,
|
||||
HistoryItem,
|
||||
QueryTransaction,
|
||||
RangeScanner,
|
||||
ExploreId,
|
||||
} from 'app/types/explore';
|
||||
import { ExploreItemState, ExploreUrlState, RangeScanner, ExploreId } from 'app/types/explore';
|
||||
import { DataQuery } from 'app/types/series';
|
||||
import { StoreState } from 'app/types';
|
||||
import store from 'app/core/store';
|
||||
import { LAST_USED_DATASOURCE_KEY, ensureQueries, DEFAULT_RANGE } from 'app/core/utils/explore';
|
||||
import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker';
|
||||
import { Emitter } from 'app/core/utils/emitter';
|
||||
import { LogsModel } from 'app/core/logs_model';
|
||||
import TableModel from 'app/core/table_model';
|
||||
|
||||
import {
|
||||
addQueryRow,
|
||||
changeDatasource,
|
||||
changeQuery,
|
||||
changeSize,
|
||||
changeTime,
|
||||
clickClear,
|
||||
clickCloseSplit,
|
||||
clickExample,
|
||||
clickGraphButton,
|
||||
clickLogsButton,
|
||||
clickSplit,
|
||||
clickTableButton,
|
||||
highlightLogsExpression,
|
||||
initializeExplore,
|
||||
modifyQueries,
|
||||
removeQueryRow,
|
||||
runQueries,
|
||||
scanStart,
|
||||
scanStop,
|
||||
} from './state/actions';
|
||||
|
||||
import Panel from './Panel';
|
||||
import QueryRows from './QueryRows';
|
||||
import Graph from './Graph';
|
||||
import Logs from './Logs';
|
||||
import Table from './Table';
|
||||
import ErrorBoundary from './ErrorBoundary';
|
||||
import { Alert } from './Error';
|
||||
import ErrorBoundary from './ErrorBoundary';
|
||||
import GraphContainer from './GraphContainer';
|
||||
import LogsContainer from './LogsContainer';
|
||||
import QueryRows from './QueryRows';
|
||||
import TableContainer from './TableContainer';
|
||||
import TimePicker, { parseTime } from './TimePicker';
|
||||
|
||||
interface ExploreProps {
|
||||
StartPage?: any;
|
||||
addQueryRow: typeof addQueryRow;
|
||||
changeDatasource: typeof changeDatasource;
|
||||
changeQuery: typeof changeQuery;
|
||||
changeSize: typeof changeSize;
|
||||
changeTime: typeof changeTime;
|
||||
clickClear: typeof clickClear;
|
||||
clickCloseSplit: typeof clickCloseSplit;
|
||||
clickExample: typeof clickExample;
|
||||
clickGraphButton: typeof clickGraphButton;
|
||||
clickLogsButton: typeof clickLogsButton;
|
||||
clickSplit: typeof clickSplit;
|
||||
clickTableButton: typeof clickTableButton;
|
||||
datasourceError: string;
|
||||
datasourceInstance: any;
|
||||
datasourceLoading: boolean | null;
|
||||
datasourceMissing: boolean;
|
||||
exploreDatasources: DataSourceSelectItem[];
|
||||
exploreId: ExploreId;
|
||||
graphResult?: any[];
|
||||
highlightLogsExpression: typeof highlightLogsExpression;
|
||||
history: HistoryItem[];
|
||||
initialDatasource?: string;
|
||||
initialQueries: DataQuery[];
|
||||
initializeExplore: typeof initializeExplore;
|
||||
initialized: boolean;
|
||||
logsHighlighterExpressions?: string[];
|
||||
logsResult?: LogsModel;
|
||||
loading: boolean;
|
||||
modifyQueries: typeof modifyQueries;
|
||||
queryTransactions: QueryTransaction[];
|
||||
removeQueryRow: typeof removeQueryRow;
|
||||
range: RawTimeRange;
|
||||
runQueries: typeof runQueries;
|
||||
scanner?: RangeScanner;
|
||||
@ -94,14 +66,10 @@ interface ExploreProps {
|
||||
scanStart: typeof scanStart;
|
||||
scanStop: typeof scanStop;
|
||||
split: boolean;
|
||||
showingGraph: boolean;
|
||||
showingLogs: boolean;
|
||||
showingStartPage?: boolean;
|
||||
showingTable: boolean;
|
||||
supportsGraph: boolean | null;
|
||||
supportsLogs: boolean | null;
|
||||
supportsTable: boolean | null;
|
||||
tableResult?: TableModel;
|
||||
urlState: ExploreUrlState;
|
||||
}
|
||||
|
||||
@ -172,24 +140,10 @@ export class Explore extends React.PureComponent<ExploreProps> {
|
||||
this.el = el;
|
||||
};
|
||||
|
||||
onAddQueryRow = index => {
|
||||
this.props.addQueryRow(this.props.exploreId, index);
|
||||
};
|
||||
|
||||
onChangeDatasource = async option => {
|
||||
this.props.changeDatasource(this.props.exploreId, option.value);
|
||||
};
|
||||
|
||||
onChangeQuery = (query: DataQuery, index: number, override?: boolean) => {
|
||||
const { changeQuery, datasourceInstance, exploreId } = 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);
|
||||
}
|
||||
};
|
||||
|
||||
onChangeTime = (range: TimeRange, changedByScanner?: boolean) => {
|
||||
if (this.props.scanning && !changedByScanner) {
|
||||
this.onStopScanning();
|
||||
@ -205,14 +159,6 @@ export class Explore extends React.PureComponent<ExploreProps> {
|
||||
this.props.clickCloseSplit();
|
||||
};
|
||||
|
||||
onClickGraphButton = () => {
|
||||
this.props.clickGraphButton(this.props.exploreId);
|
||||
};
|
||||
|
||||
onClickLogsButton = () => {
|
||||
this.props.clickLogsButton(this.props.exploreId);
|
||||
};
|
||||
|
||||
// Use this in help pages to set page to a single query
|
||||
onClickExample = (query: DataQuery) => {
|
||||
this.props.clickExample(this.props.exploreId, query);
|
||||
@ -222,10 +168,6 @@ export class Explore extends React.PureComponent<ExploreProps> {
|
||||
this.props.clickSplit();
|
||||
};
|
||||
|
||||
onClickTableButton = () => {
|
||||
this.props.clickTableButton(this.props.exploreId);
|
||||
};
|
||||
|
||||
onClickLabel = (key: string, value: string) => {
|
||||
this.onModifyQueries({ type: 'ADD_FILTER', key, value });
|
||||
};
|
||||
@ -238,10 +180,6 @@ export class Explore extends React.PureComponent<ExploreProps> {
|
||||
}
|
||||
};
|
||||
|
||||
onRemoveQueryRow = index => {
|
||||
this.props.removeQueryRow(this.props.exploreId, index);
|
||||
};
|
||||
|
||||
onResize = (size: { height: number; width: number }) => {
|
||||
this.props.changeSize(this.props.exploreId, size);
|
||||
};
|
||||
@ -265,14 +203,6 @@ export class Explore extends React.PureComponent<ExploreProps> {
|
||||
this.props.runQueries(this.props.exploreId);
|
||||
};
|
||||
|
||||
updateLogsHighlights = _.debounce((value: DataQuery) => {
|
||||
const { datasourceInstance } = this.props;
|
||||
if (datasourceInstance.getHighlighterExpression) {
|
||||
const expressions = [datasourceInstance.getHighlighterExpression(value)];
|
||||
this.props.highlightLogsExpression(this.props.exploreId, expressions);
|
||||
}
|
||||
}, 500);
|
||||
|
||||
render() {
|
||||
const {
|
||||
StartPage,
|
||||
@ -282,34 +212,19 @@ export class Explore extends React.PureComponent<ExploreProps> {
|
||||
datasourceMissing,
|
||||
exploreDatasources,
|
||||
exploreId,
|
||||
graphResult,
|
||||
history,
|
||||
loading,
|
||||
initialQueries,
|
||||
logsHighlighterExpressions,
|
||||
logsResult,
|
||||
queryTransactions,
|
||||
range,
|
||||
scanning,
|
||||
scanRange,
|
||||
showingGraph,
|
||||
showingLogs,
|
||||
showingStartPage,
|
||||
showingTable,
|
||||
split,
|
||||
supportsGraph,
|
||||
supportsLogs,
|
||||
supportsTable,
|
||||
tableResult,
|
||||
} = this.props;
|
||||
const graphHeight = showingGraph && showingTable ? '200px' : '400px';
|
||||
const exploreClass = split ? 'explore explore-split' : 'explore';
|
||||
const selectedDatasource = datasourceInstance
|
||||
? exploreDatasources.find(d => d.name === datasourceInstance.name)
|
||||
: undefined;
|
||||
const graphLoading = queryTransactions.some(qt => qt.resultType === 'Graph' && !qt.done);
|
||||
const tableLoading = queryTransactions.some(qt => qt.resultType === 'Table' && !qt.done);
|
||||
const logsLoading = queryTransactions.some(qt => qt.resultType === 'Logs' && !qt.done);
|
||||
const loading = queryTransactions.some(qt => !qt.done);
|
||||
|
||||
return (
|
||||
<div className={exploreClass} ref={this.getRef}>
|
||||
@ -372,19 +287,7 @@ export class Explore extends React.PureComponent<ExploreProps> {
|
||||
{datasourceInstance &&
|
||||
!datasourceError && (
|
||||
<div className="explore-container">
|
||||
<QueryRows
|
||||
datasource={datasourceInstance}
|
||||
history={history}
|
||||
initialQueries={initialQueries}
|
||||
onAddQueryRow={this.onAddQueryRow}
|
||||
onChangeQuery={this.onChangeQuery}
|
||||
onClickHintFix={this.onModifyQueries}
|
||||
onExecuteQuery={this.onSubmit}
|
||||
onRemoveQueryRow={this.onRemoveQueryRow}
|
||||
transactions={queryTransactions}
|
||||
exploreEvents={this.exploreEvents}
|
||||
range={range}
|
||||
/>
|
||||
<QueryRows exploreEvents={this.exploreEvents} exploreId={exploreId} initialQueries={initialQueries} />
|
||||
<AutoSizer onResize={this.onResize} disableHeight>
|
||||
{({ width }) => (
|
||||
<main className="m-t-2" style={{ width }}>
|
||||
@ -392,55 +295,16 @@ export class Explore extends React.PureComponent<ExploreProps> {
|
||||
{showingStartPage && <StartPage onClickExample={this.onClickExample} />}
|
||||
{!showingStartPage && (
|
||||
<>
|
||||
{supportsGraph && (
|
||||
<Panel
|
||||
label="Graph"
|
||||
isOpen={showingGraph}
|
||||
loading={graphLoading}
|
||||
onToggle={this.onClickGraphButton}
|
||||
>
|
||||
<Graph
|
||||
data={graphResult}
|
||||
height={graphHeight}
|
||||
id={`explore-graph-${exploreId}`}
|
||||
onChangeTime={this.onChangeTime}
|
||||
range={range}
|
||||
split={split}
|
||||
/>
|
||||
</Panel>
|
||||
)}
|
||||
{supportsTable && (
|
||||
<Panel
|
||||
label="Table"
|
||||
loading={tableLoading}
|
||||
isOpen={showingTable}
|
||||
onToggle={this.onClickTableButton}
|
||||
>
|
||||
<Table data={tableResult} loading={tableLoading} onClickCell={this.onClickLabel} />
|
||||
</Panel>
|
||||
)}
|
||||
{supportsGraph && <GraphContainer exploreId={exploreId} />}
|
||||
{supportsTable && <TableContainer exploreId={exploreId} onClickCell={this.onClickLabel} />}
|
||||
{supportsLogs && (
|
||||
<Panel
|
||||
label="Logs"
|
||||
loading={logsLoading}
|
||||
isOpen={showingLogs}
|
||||
onToggle={this.onClickLogsButton}
|
||||
>
|
||||
<Logs
|
||||
data={logsResult}
|
||||
exploreId={exploreId}
|
||||
key={logsResult.id}
|
||||
highlighterExpressions={logsHighlighterExpressions}
|
||||
loading={logsLoading}
|
||||
onChangeTime={this.onChangeTime}
|
||||
onClickLabel={this.onClickLabel}
|
||||
onStartScanning={this.onStartScanning}
|
||||
onStopScanning={this.onStopScanning}
|
||||
range={range}
|
||||
scanning={scanning}
|
||||
scanRange={scanRange}
|
||||
/>
|
||||
</Panel>
|
||||
<LogsContainer
|
||||
exploreId={exploreId}
|
||||
onChangeTime={this.onChangeTime}
|
||||
onClickLabel={this.onClickLabel}
|
||||
onStartScanning={this.onStartScanning}
|
||||
onStopScanning={this.onStopScanning}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
@ -466,26 +330,17 @@ function mapStateToProps(state: StoreState, { exploreId }) {
|
||||
datasourceLoading,
|
||||
datasourceMissing,
|
||||
exploreDatasources,
|
||||
graphResult,
|
||||
initialDatasource,
|
||||
initialQueries,
|
||||
initialized,
|
||||
history,
|
||||
logsHighlighterExpressions,
|
||||
logsResult,
|
||||
queryTransactions,
|
||||
range,
|
||||
scanning,
|
||||
scanRange,
|
||||
showingGraph,
|
||||
showingLogs,
|
||||
showingStartPage,
|
||||
showingTable,
|
||||
supportsGraph,
|
||||
supportsLogs,
|
||||
supportsTable,
|
||||
tableResult,
|
||||
} = item;
|
||||
const loading = queryTransactions.some(qt => !qt.done);
|
||||
return {
|
||||
StartPage,
|
||||
datasourceError,
|
||||
@ -493,46 +348,30 @@ function mapStateToProps(state: StoreState, { exploreId }) {
|
||||
datasourceLoading,
|
||||
datasourceMissing,
|
||||
exploreDatasources,
|
||||
graphResult,
|
||||
initialDatasource,
|
||||
initialQueries,
|
||||
initialized,
|
||||
history,
|
||||
logsHighlighterExpressions,
|
||||
logsResult,
|
||||
loading,
|
||||
queryTransactions,
|
||||
range,
|
||||
scanning,
|
||||
scanRange,
|
||||
showingGraph,
|
||||
showingLogs,
|
||||
showingStartPage,
|
||||
showingTable,
|
||||
split,
|
||||
supportsGraph,
|
||||
supportsLogs,
|
||||
supportsTable,
|
||||
tableResult,
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
addQueryRow,
|
||||
changeDatasource,
|
||||
changeQuery,
|
||||
changeSize,
|
||||
changeTime,
|
||||
clickClear,
|
||||
clickCloseSplit,
|
||||
clickExample,
|
||||
clickGraphButton,
|
||||
clickLogsButton,
|
||||
clickSplit,
|
||||
clickTableButton,
|
||||
highlightLogsExpression,
|
||||
initializeExplore,
|
||||
modifyQueries,
|
||||
removeQueryRow,
|
||||
runQueries,
|
||||
scanStart,
|
||||
scanStop,
|
||||
|
61
public/app/features/explore/GraphContainer.tsx
Normal file
61
public/app/features/explore/GraphContainer.tsx
Normal file
@ -0,0 +1,61 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { hot } from 'react-hot-loader';
|
||||
import { connect } from 'react-redux';
|
||||
import { RawTimeRange, TimeRange } from '@grafana/ui';
|
||||
|
||||
import { ExploreId, ExploreItemState } from 'app/types/explore';
|
||||
import { StoreState } from 'app/types';
|
||||
|
||||
import { clickGraphButton } from './state/actions';
|
||||
import Graph from './Graph';
|
||||
import Panel from './Panel';
|
||||
|
||||
interface GraphContainerProps {
|
||||
onChangeTime: (range: TimeRange) => void;
|
||||
clickGraphButton: typeof clickGraphButton;
|
||||
exploreId: ExploreId;
|
||||
graphResult?: any[];
|
||||
loading: boolean;
|
||||
range: RawTimeRange;
|
||||
showingGraph: boolean;
|
||||
showingTable: boolean;
|
||||
split: boolean;
|
||||
}
|
||||
|
||||
export class GraphContainer extends PureComponent<GraphContainerProps> {
|
||||
onClickGraphButton = () => {
|
||||
this.props.clickGraphButton(this.props.exploreId);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { exploreId, graphResult, loading, onChangeTime, showingGraph, showingTable, range, split } = this.props;
|
||||
const graphHeight = showingGraph && showingTable ? '200px' : '400px';
|
||||
return (
|
||||
<Panel label="Graph" isOpen={showingGraph} loading={loading} onToggle={this.onClickGraphButton}>
|
||||
<Graph
|
||||
data={graphResult}
|
||||
height={graphHeight}
|
||||
id={`explore-graph-${exploreId}`}
|
||||
onChangeTime={onChangeTime}
|
||||
range={range}
|
||||
split={split}
|
||||
/>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state: StoreState, { exploreId }) {
|
||||
const explore = state.explore;
|
||||
const { split } = explore;
|
||||
const item: ExploreItemState = explore[exploreId];
|
||||
const { graphResult, queryTransactions, range, showingGraph, showingTable } = item;
|
||||
const loading = queryTransactions.some(qt => qt.resultType === 'Graph' && !qt.done);
|
||||
return { graphResult, loading, range, showingGraph, showingTable, split };
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
clickGraphButton,
|
||||
};
|
||||
|
||||
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(GraphContainer));
|
91
public/app/features/explore/LogsContainer.tsx
Normal file
91
public/app/features/explore/LogsContainer.tsx
Normal file
@ -0,0 +1,91 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { hot } from 'react-hot-loader';
|
||||
import { connect } from 'react-redux';
|
||||
import { RawTimeRange, TimeRange } from '@grafana/ui';
|
||||
|
||||
import { ExploreId, ExploreItemState } from 'app/types/explore';
|
||||
import { LogsModel } from 'app/core/logs_model';
|
||||
import { StoreState } from 'app/types';
|
||||
|
||||
import { clickLogsButton } from './state/actions';
|
||||
import Logs from './Logs';
|
||||
import Panel from './Panel';
|
||||
|
||||
interface LogsContainerProps {
|
||||
clickLogsButton: typeof clickLogsButton;
|
||||
exploreId: ExploreId;
|
||||
loading: boolean;
|
||||
logsHighlighterExpressions?: string[];
|
||||
logsResult?: LogsModel;
|
||||
onChangeTime: (range: TimeRange) => void;
|
||||
onClickLabel: (key: string, value: string) => void;
|
||||
onStartScanning: () => void;
|
||||
onStopScanning: () => void;
|
||||
range: RawTimeRange;
|
||||
scanning?: boolean;
|
||||
scanRange?: RawTimeRange;
|
||||
showingLogs: boolean;
|
||||
}
|
||||
|
||||
export class LogsContainer extends PureComponent<LogsContainerProps> {
|
||||
onClickLogsButton = () => {
|
||||
this.props.clickLogsButton(this.props.exploreId);
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
exploreId,
|
||||
loading,
|
||||
logsHighlighterExpressions,
|
||||
logsResult,
|
||||
onChangeTime,
|
||||
onClickLabel,
|
||||
onStartScanning,
|
||||
onStopScanning,
|
||||
range,
|
||||
showingLogs,
|
||||
scanning,
|
||||
scanRange,
|
||||
} = this.props;
|
||||
return (
|
||||
<Panel label="Logs" loading={loading} isOpen={showingLogs} onToggle={this.onClickLogsButton}>
|
||||
<Logs
|
||||
data={logsResult}
|
||||
exploreId={exploreId}
|
||||
key={logsResult.id}
|
||||
highlighterExpressions={logsHighlighterExpressions}
|
||||
loading={loading}
|
||||
onChangeTime={onChangeTime}
|
||||
onClickLabel={onClickLabel}
|
||||
onStartScanning={onStartScanning}
|
||||
onStopScanning={onStopScanning}
|
||||
range={range}
|
||||
scanning={scanning}
|
||||
scanRange={scanRange}
|
||||
/>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state: StoreState, { exploreId }) {
|
||||
const explore = state.explore;
|
||||
const item: ExploreItemState = explore[exploreId];
|
||||
const { logsHighlighterExpressions, logsResult, queryTransactions, scanning, scanRange, showingLogs, range } = item;
|
||||
const loading = queryTransactions.some(qt => qt.resultType === 'Logs' && !qt.done);
|
||||
return {
|
||||
loading,
|
||||
logsHighlighterExpressions,
|
||||
logsResult,
|
||||
scanning,
|
||||
scanRange,
|
||||
showingLogs,
|
||||
range,
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
clickLogsButton,
|
||||
};
|
||||
|
||||
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(LogsContainer));
|
163
public/app/features/explore/QueryRow.tsx
Normal file
163
public/app/features/explore/QueryRow.tsx
Normal file
@ -0,0 +1,163 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { hot } from 'react-hot-loader';
|
||||
import { connect } from 'react-redux';
|
||||
import { RawTimeRange } from '@grafana/ui';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { QueryTransaction, HistoryItem, QueryHint, ExploreItemState, ExploreId } from 'app/types/explore';
|
||||
import { Emitter } from 'app/core/utils/emitter';
|
||||
import { DataQuery, StoreState } from 'app/types';
|
||||
|
||||
// import DefaultQueryField from './QueryField';
|
||||
import QueryEditor from './QueryEditor';
|
||||
import QueryTransactionStatus from './QueryTransactionStatus';
|
||||
import {
|
||||
addQueryRow,
|
||||
changeQuery,
|
||||
highlightLogsExpression,
|
||||
modifyQueries,
|
||||
removeQueryRow,
|
||||
runQueries,
|
||||
} from './state/actions';
|
||||
|
||||
function getFirstHintFromTransactions(transactions: QueryTransaction[]): QueryHint {
|
||||
const transaction = transactions.find(qt => qt.hints && qt.hints.length > 0);
|
||||
if (transaction) {
|
||||
return transaction.hints[0];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
interface QueryRowProps {
|
||||
addQueryRow: typeof addQueryRow;
|
||||
changeQuery: typeof changeQuery;
|
||||
className?: string;
|
||||
exploreId: ExploreId;
|
||||
datasourceInstance: any;
|
||||
highlightLogsExpression: typeof highlightLogsExpression;
|
||||
history: HistoryItem[];
|
||||
index: number;
|
||||
initialQuery: DataQuery;
|
||||
modifyQueries: typeof modifyQueries;
|
||||
queryTransactions: QueryTransaction[];
|
||||
exploreEvents: Emitter;
|
||||
range: RawTimeRange;
|
||||
removeQueryRow: typeof removeQueryRow;
|
||||
runQueries: typeof runQueries;
|
||||
}
|
||||
|
||||
export class QueryRow extends PureComponent<QueryRowProps> {
|
||||
onExecuteQuery = () => {
|
||||
const { exploreId } = this.props;
|
||||
this.props.runQueries(exploreId);
|
||||
};
|
||||
|
||||
onChangeQuery = (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);
|
||||
}
|
||||
};
|
||||
|
||||
onClickAddButton = () => {
|
||||
const { exploreId, index } = this.props;
|
||||
this.props.addQueryRow(exploreId, index);
|
||||
};
|
||||
|
||||
onClickClearButton = () => {
|
||||
this.onChangeQuery(null, true);
|
||||
};
|
||||
|
||||
onClickHintFix = action => {
|
||||
const { datasourceInstance, exploreId, index } = this.props;
|
||||
if (datasourceInstance && datasourceInstance.modifyQuery) {
|
||||
const modifier = (queries: DataQuery, action: any) => datasourceInstance.modifyQuery(queries, action);
|
||||
this.props.modifyQueries(exploreId, action, index, modifier);
|
||||
}
|
||||
};
|
||||
|
||||
onClickRemoveButton = () => {
|
||||
const { exploreId, index } = this.props;
|
||||
this.props.removeQueryRow(exploreId, index);
|
||||
};
|
||||
|
||||
updateLogsHighlights = _.debounce((value: DataQuery) => {
|
||||
const { datasourceInstance } = this.props;
|
||||
if (datasourceInstance.getHighlighterExpression) {
|
||||
const expressions = [datasourceInstance.getHighlighterExpression(value)];
|
||||
this.props.highlightLogsExpression(this.props.exploreId, expressions);
|
||||
}
|
||||
}, 500);
|
||||
|
||||
render() {
|
||||
const { datasourceInstance, history, index, initialQuery, queryTransactions, exploreEvents, range } = this.props;
|
||||
const transactions = queryTransactions.filter(t => t.rowIndex === index);
|
||||
const transactionWithError = transactions.find(t => t.error !== undefined);
|
||||
const hint = getFirstHintFromTransactions(transactions);
|
||||
const queryError = transactionWithError ? transactionWithError.error : null;
|
||||
const QueryField = datasourceInstance.pluginExports.ExploreQueryField;
|
||||
return (
|
||||
<div className="query-row">
|
||||
<div className="query-row-status">
|
||||
<QueryTransactionStatus transactions={transactions} />
|
||||
</div>
|
||||
<div className="query-row-field">
|
||||
{QueryField ? (
|
||||
<QueryField
|
||||
datasource={datasourceInstance}
|
||||
error={queryError}
|
||||
hint={hint}
|
||||
initialQuery={initialQuery}
|
||||
history={history}
|
||||
onClickHintFix={this.onClickHintFix}
|
||||
onPressEnter={this.onExecuteQuery}
|
||||
onQueryChange={this.onChangeQuery}
|
||||
/>
|
||||
) : (
|
||||
<QueryEditor
|
||||
datasource={datasourceInstance}
|
||||
error={queryError}
|
||||
onQueryChange={this.onChangeQuery}
|
||||
onExecuteQuery={this.onExecuteQuery}
|
||||
initialQuery={initialQuery}
|
||||
exploreEvents={exploreEvents}
|
||||
range={range}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="query-row-tools">
|
||||
<button className="btn navbar-button navbar-button--tight" onClick={this.onClickClearButton}>
|
||||
<i className="fa fa-times" />
|
||||
</button>
|
||||
<button className="btn navbar-button navbar-button--tight" onClick={this.onClickAddButton}>
|
||||
<i className="fa fa-plus" />
|
||||
</button>
|
||||
<button className="btn navbar-button navbar-button--tight" onClick={this.onClickRemoveButton}>
|
||||
<i className="fa fa-minus" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state: StoreState, { exploreId, index }) {
|
||||
const explore = state.explore;
|
||||
const item: ExploreItemState = explore[exploreId];
|
||||
const { datasourceInstance, history, initialQueries, queryTransactions, range } = item;
|
||||
const initialQuery = initialQueries[index];
|
||||
return { datasourceInstance, history, initialQuery, queryTransactions, range };
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
addQueryRow,
|
||||
changeQuery,
|
||||
highlightLogsExpression,
|
||||
modifyQueries,
|
||||
removeQueryRow,
|
||||
runQueries,
|
||||
};
|
||||
|
||||
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(QueryRow));
|
@ -1,159 +1,25 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
import { QueryTransaction, HistoryItem, QueryHint } from 'app/types/explore';
|
||||
import { Emitter } from 'app/core/utils/emitter';
|
||||
import { DataQuery } from 'app/types';
|
||||
import { ExploreId } from 'app/types/explore';
|
||||
|
||||
// import DefaultQueryField from './QueryField';
|
||||
import QueryEditor from './QueryEditor';
|
||||
import QueryTransactionStatus from './QueryTransactionStatus';
|
||||
import { DataSource, DataQuery } from 'app/types';
|
||||
import { RawTimeRange } from '@grafana/ui';
|
||||
import QueryRow from './QueryRow';
|
||||
|
||||
function getFirstHintFromTransactions(transactions: QueryTransaction[]): QueryHint {
|
||||
const transaction = transactions.find(qt => qt.hints && qt.hints.length > 0);
|
||||
if (transaction) {
|
||||
return transaction.hints[0];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
interface QueryRowEventHandlers {
|
||||
onAddQueryRow: (index: number) => void;
|
||||
onChangeQuery: (value: DataQuery, index: number, override?: boolean) => void;
|
||||
onClickHintFix: (action: object, index?: number) => void;
|
||||
onExecuteQuery: () => void;
|
||||
onRemoveQueryRow: (index: number) => void;
|
||||
}
|
||||
|
||||
interface QueryRowCommonProps {
|
||||
interface QueryRowsProps {
|
||||
className?: string;
|
||||
datasource: DataSource;
|
||||
history: HistoryItem[];
|
||||
transactions: QueryTransaction[];
|
||||
exploreEvents: Emitter;
|
||||
range: RawTimeRange;
|
||||
exploreId: ExploreId;
|
||||
initialQueries: DataQuery[];
|
||||
}
|
||||
|
||||
type QueryRowProps = QueryRowCommonProps &
|
||||
QueryRowEventHandlers & {
|
||||
index: number;
|
||||
initialQuery: DataQuery;
|
||||
};
|
||||
|
||||
class QueryRow extends PureComponent<QueryRowProps> {
|
||||
onExecuteQuery = () => {
|
||||
const { onExecuteQuery } = this.props;
|
||||
onExecuteQuery();
|
||||
};
|
||||
|
||||
onChangeQuery = (value: DataQuery, override?: boolean) => {
|
||||
const { index, onChangeQuery } = this.props;
|
||||
if (onChangeQuery) {
|
||||
onChangeQuery(value, index, override);
|
||||
}
|
||||
};
|
||||
|
||||
onClickAddButton = () => {
|
||||
const { index, onAddQueryRow } = this.props;
|
||||
if (onAddQueryRow) {
|
||||
onAddQueryRow(index);
|
||||
}
|
||||
};
|
||||
|
||||
onClickClearButton = () => {
|
||||
this.onChangeQuery(null, true);
|
||||
};
|
||||
|
||||
onClickHintFix = action => {
|
||||
const { index, onClickHintFix } = this.props;
|
||||
if (onClickHintFix) {
|
||||
onClickHintFix(action, index);
|
||||
}
|
||||
};
|
||||
|
||||
onClickRemoveButton = () => {
|
||||
const { index, onRemoveQueryRow } = this.props;
|
||||
if (onRemoveQueryRow) {
|
||||
onRemoveQueryRow(index);
|
||||
}
|
||||
};
|
||||
|
||||
onPressEnter = () => {
|
||||
const { onExecuteQuery } = this.props;
|
||||
if (onExecuteQuery) {
|
||||
onExecuteQuery();
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { datasource, history, initialQuery, transactions, exploreEvents, range } = this.props;
|
||||
const transactionWithError = transactions.find(t => t.error !== undefined);
|
||||
const hint = getFirstHintFromTransactions(transactions);
|
||||
const queryError = transactionWithError ? transactionWithError.error : null;
|
||||
const QueryField = datasource.pluginExports.ExploreQueryField;
|
||||
return (
|
||||
<div className="query-row">
|
||||
<div className="query-row-status">
|
||||
<QueryTransactionStatus transactions={transactions} />
|
||||
</div>
|
||||
<div className="query-row-field">
|
||||
{QueryField ? (
|
||||
<QueryField
|
||||
datasource={datasource}
|
||||
error={queryError}
|
||||
hint={hint}
|
||||
initialQuery={initialQuery}
|
||||
history={history}
|
||||
onClickHintFix={this.onClickHintFix}
|
||||
onPressEnter={this.onPressEnter}
|
||||
onQueryChange={this.onChangeQuery}
|
||||
/>
|
||||
) : (
|
||||
<QueryEditor
|
||||
datasource={datasource}
|
||||
error={queryError}
|
||||
onQueryChange={this.onChangeQuery}
|
||||
onExecuteQuery={this.onExecuteQuery}
|
||||
initialQuery={initialQuery}
|
||||
exploreEvents={exploreEvents}
|
||||
range={range}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="query-row-tools">
|
||||
<button className="btn navbar-button navbar-button--tight" onClick={this.onClickClearButton}>
|
||||
<i className="fa fa-times" />
|
||||
</button>
|
||||
<button className="btn navbar-button navbar-button--tight" onClick={this.onClickAddButton}>
|
||||
<i className="fa fa-plus" />
|
||||
</button>
|
||||
<button className="btn navbar-button navbar-button--tight" onClick={this.onClickRemoveButton}>
|
||||
<i className="fa fa-minus" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
type QueryRowsProps = QueryRowCommonProps &
|
||||
QueryRowEventHandlers & {
|
||||
initialQueries: DataQuery[];
|
||||
};
|
||||
|
||||
export default class QueryRows extends PureComponent<QueryRowsProps> {
|
||||
render() {
|
||||
const { className = '', initialQueries, transactions, ...handlers } = this.props;
|
||||
const { className = '', exploreEvents, exploreId, initialQueries } = this.props;
|
||||
return (
|
||||
<div className={className}>
|
||||
{initialQueries.map((query, index) => (
|
||||
<QueryRow
|
||||
key={query.key}
|
||||
index={index}
|
||||
initialQuery={query}
|
||||
transactions={transactions.filter(t => t.rowIndex === index)}
|
||||
{...handlers}
|
||||
/>
|
||||
// TODO instead of relying on initialQueries, move to react key list in redux
|
||||
<QueryRow key={query.key} exploreEvents={exploreEvents} exploreId={exploreId} index={index} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
49
public/app/features/explore/TableContainer.tsx
Normal file
49
public/app/features/explore/TableContainer.tsx
Normal file
@ -0,0 +1,49 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { hot } from 'react-hot-loader';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { ExploreId, ExploreItemState } from 'app/types/explore';
|
||||
import { StoreState } from 'app/types';
|
||||
|
||||
import { clickTableButton } from './state/actions';
|
||||
import Table from './Table';
|
||||
import Panel from './Panel';
|
||||
import TableModel from 'app/core/table_model';
|
||||
|
||||
interface TableContainerProps {
|
||||
clickTableButton: typeof clickTableButton;
|
||||
exploreId: ExploreId;
|
||||
loading: boolean;
|
||||
onClickLabel: (key: string, value: string) => void;
|
||||
showingTable: boolean;
|
||||
tableResult?: TableModel;
|
||||
}
|
||||
|
||||
export class TableContainer extends PureComponent<TableContainerProps> {
|
||||
onClickTableButton = () => {
|
||||
this.props.clickTableButton(this.props.exploreId);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { loading, onClickLabel, showingTable, tableResult } = this.props;
|
||||
return (
|
||||
<Panel label="Table" loading={loading} isOpen={showingTable} onToggle={this.onClickTableButton}>
|
||||
<Table data={tableResult} loading={loading} onClickCell={onClickLabel} />
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state: StoreState, { exploreId }) {
|
||||
const explore = state.explore;
|
||||
const item: ExploreItemState = explore[exploreId];
|
||||
const { queryTransactions, showingTable, tableResult } = item;
|
||||
const loading = queryTransactions.some(qt => qt.resultType === 'Table' && !qt.done);
|
||||
return { loading, showingTable, tableResult };
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
clickTableButton,
|
||||
};
|
||||
|
||||
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(TableContainer));
|
@ -232,6 +232,7 @@ const itemReducer = (state, action: Action): ExploreItemState => {
|
||||
initialQueries: action.initialQueries,
|
||||
logsHighlighterExpressions: undefined,
|
||||
modifiedQueries: action.initialQueries.slice(),
|
||||
queryTransactions: [],
|
||||
showingStartPage: action.showingStartPage,
|
||||
supportsGraph: action.supportsGraph,
|
||||
supportsLogs: action.supportsLogs,
|
||||
|
Loading…
Reference in New Issue
Block a user