@ -2,7 +2,7 @@ import React from 'react';
import { hot } from 'react-hot-loader' ;
import Select from 'react-select' ;
import { ExploreState , ExploreUrlState } from 'app/types/explore' ;
import { ExploreState , ExploreUrlState , Query } from 'app/types/explore' ;
import kbn from 'app/core/utils/kbn' ;
import colors from 'app/core/utils/colors' ;
import store from 'app/core/store' ;
@ -61,38 +61,50 @@ interface ExploreProps {
export class Explore extends React . PureComponent < ExploreProps , ExploreState > {
el : any ;
/ * *
* Current query expressions of the rows including their modifications , used for running queries .
* Not kept in component state to prevent edit - render roundtrips .
* /
queryExpressions : string [ ] ;
constructor ( props ) {
super ( props ) ;
// Split state overrides everything
const splitState : ExploreState = props . splitState ;
const { datasource , queries , range } = props . urlState ;
this . state = {
datasource : null ,
datasourceError : null ,
datasourceLoading : null ,
datasourceMissing : false ,
datasourceName : datasource ,
exploreDatasources : [ ] ,
graphResult : null ,
history : [ ] ,
latency : 0 ,
loading : false ,
logsResult : null ,
queries : ensureQueries ( queries ) ,
queryErrors : [ ] ,
queryHints : [ ] ,
range : range || { . . . DEFAULT_RANGE } ,
requestOptions : null ,
showingGraph : true ,
showingLogs : true ,
showingTable : true ,
supportsGraph : null ,
supportsLogs : null ,
supportsTable : null ,
tableResult : null ,
. . . splitState ,
} ;
let initialQueries : Query [ ] ;
if ( splitState ) {
// Split state overrides everything
this . state = splitState ;
initialQueries = splitState . queries ;
} else {
const { datasource , queries , range } = props . urlState as ExploreUrlState ;
initialQueries = ensureQueries ( queries ) ;
this . state = {
datasource : null ,
datasourceError : null ,
datasourceLoading : null ,
datasourceMissing : false ,
datasourceName : datasource ,
exploreDatasources : [ ] ,
graphResult : null ,
history : [ ] ,
latency : 0 ,
loading : false ,
logsResult : null ,
queries : initialQueries ,
queryErrors : [ ] ,
queryHints : [ ] ,
range : range || { . . . DEFAULT_RANGE } ,
requestOptions : null ,
showingGraph : true ,
showingLogs : true ,
showingTable : true ,
supportsGraph : null ,
supportsLogs : null ,
supportsTable : null ,
tableResult : null ,
} ;
}
this . queryExpressions = initialQueries . map ( q = > q . query ) ;
}
async componentDidMount() {
@ -152,9 +164,10 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
}
// Keep queries but reset edit state
const nextQueries = this . state . queries . map ( q = > ( {
const nextQueries = this . state . queries . map ( ( q , i ) = > ( {
. . . q ,
edited : false ,
key : generateQueryKey ( i ) ,
query : this.queryExpressions [ i ] ,
} ) ) ;
this . setState (
@ -183,6 +196,7 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
onAddQueryRow = index = > {
const { queries } = this . state ;
this . queryExpressions [ index + 1 ] = '' ;
const nextQueries = [
. . . queries . slice ( 0 , index + 1 ) ,
{ query : '' , key : generateQueryKey ( ) } ,
@ -209,29 +223,28 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
} ;
onChangeQuery = ( value : string , index : number , override? : boolean ) = > {
const { queries } = this . state ;
let { queryErrors , queryHints } = this . state ;
const prevQuery = queries [ index ] ;
const edited = override ? false : prevQuery . query !== value ;
const nextQuery = {
. . . queries [ index ] ,
edited ,
query : value ,
} ;
const nextQueries = [ . . . queries ] ;
nextQueries [ index ] = nextQuery ;
// Keep current value in local cache
this . queryExpressions [ index ] = value ;
// Replace query row on override
if ( override ) {
queryErrors = [ ] ;
queryHints = [ ] ;
const { queries } = this . state ;
const nextQuery : Query = {
key : generateQueryKey ( index ) ,
query : value ,
} ;
const nextQueries = [ . . . queries ] ;
nextQueries [ index ] = nextQuery ;
this . setState (
{
queryErrors : [ ] ,
queryHints : [ ] ,
queries : nextQueries ,
} ,
this . onSubmit
) ;
}
this . setState (
{
queryErrors ,
queryHints ,
queries : nextQueries ,
} ,
override ? ( ) = > this . onSubmit ( ) : undefined
) ;
} ;
onChangeTime = nextRange = > {
@ -243,6 +256,7 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
} ;
onClickClear = ( ) = > {
this . queryExpressions = [ '' ] ;
this . setState (
{
graphResult : null ,
@ -275,9 +289,8 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
onClickSplit = ( ) = > {
const { onChangeSplit } = this . props ;
const state = { . . . this . state } ;
state . queries = state . queries . map ( ( { edited , . . . rest } ) = > rest ) ;
if ( onChangeSplit ) {
const state = this . cloneState ( ) ;
onChangeSplit ( true , state ) ;
this . saveState ( ) ;
}
@ -297,23 +310,22 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
let nextQueries ;
if ( index === undefined ) {
// Modify all queries
nextQueries = queries . map ( q = > ( {
. . . q ,
edited : false ,
query : datasource.modifyQuery ( q . query , action ) ,
nextQueries = queries . map ( ( q , i ) = > ( {
key : generateQueryKey ( i ) ,
query : datasource.modifyQuery ( this . queryExpressions [ i ] , action ) ,
} ) ) ;
} else {
// Modify query only at index
nextQueries = [
. . . queries . slice ( 0 , index ) ,
{
. . . queries [ index ] ,
edited : false ,
query : datasource.modifyQuery ( queries [ index ] . query , action ) ,
key : generateQueryKey ( index ) ,
query : datasource.modifyQuery ( this . queryExpressions [ index ] , action ) ,
} ,
. . . queries . slice ( index + 1 ) ,
] ;
}
this . queryExpressions = nextQueries . map ( q = > q . query ) ;
this . setState ( { queries : nextQueries } , ( ) = > this . onSubmit ( ) ) ;
}
} ;
@ -324,6 +336,7 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
return ;
}
const nextQueries = [ . . . queries . slice ( 0 , index ) , . . . queries . slice ( index + 1 ) ] ;
this . queryExpressions = nextQueries . map ( q = > q . query ) ;
this . setState ( { queries : nextQueries } , ( ) = > this . onSubmit ( ) ) ;
} ;
@ -341,7 +354,7 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
this . saveState ( ) ;
} ;
onQuerySuccess ( datasourceId : string , queries : any [ ] ) : void {
onQuerySuccess ( datasourceId : string , queries : string [ ] ) : void {
// save queries to history
let { history } = this . state ;
const { datasource } = this . state ;
@ -352,8 +365,7 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
}
const ts = Date . now ( ) ;
queries . forEach ( q = > {
const { query } = q ;
queries . forEach ( query = > {
history = [ { query , ts } , . . . history ] ;
} ) ;
@ -368,16 +380,16 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
}
buildQueryOptions ( targetOptions : { format : string ; hinting? : boolean ; instant? : boolean } ) {
const { datasource , queries , range } = this . state ;
const { datasource , range } = this . state ;
const resolution = this . el . offsetWidth ;
const absoluteRange = {
from : parseDate ( range . from , false ) ,
to : parseDate ( range . to , true ) ,
} ;
const { interval } = kbn . calculateInterval ( absoluteRange , resolution , datasource . interval ) ;
const targets = querie s. map ( q = > ( {
const targets = this . queryExpression s. map ( q = > ( {
. . . targetOptions ,
expr : q.query ,
expr : q ,
} ) ) ;
return {
interval ,
@ -387,7 +399,8 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
}
async runGraphQuery() {
const { datasource , queries } = this . state ;
const { datasource } = this . state ;
const queries = [ . . . this . queryExpressions ] ;
if ( ! hasQuery ( queries ) ) {
return ;
}
@ -409,7 +422,8 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
}
async runTableQuery() {
const { datasource , queries } = this . state ;
const queries = [ . . . this . queryExpressions ] ;
const { datasource } = this . state ;
if ( ! hasQuery ( queries ) ) {
return ;
}
@ -433,7 +447,8 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
}
async runLogsQuery() {
const { datasource , queries } = this . state ;
const queries = [ . . . this . queryExpressions ] ;
const { datasource } = this . state ;
if ( ! hasQuery ( queries ) ) {
return ;
}
@ -461,9 +476,17 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
return datasource . metadataRequest ( url ) ;
} ;
cloneState ( ) : ExploreState {
// Copy state, but copy queries including modifications
return {
. . . this . state ,
queries : ensureQueries ( this . queryExpressions . map ( query = > ( { query } ) ) ) ,
} ;
}
saveState = ( ) = > {
const { stateKey , onSaveState } = this . props ;
onSaveState ( stateKey , this . state ) ;
onSaveState ( stateKey , this . cloneState ( ) ) ;
} ;
render() {