@ -19,6 +19,16 @@ import { ensureQueries, generateQueryKey, hasQuery } from './utils/query';
const MAX_HISTORY_ITEMS = 100 ;
function makeHints ( hints ) {
const hintsByIndex = [ ] ;
hints . forEach ( hint = > {
if ( hint ) {
hintsByIndex [ hint . index ] = hint ;
}
} ) ;
return hintsByIndex ;
}
function makeTimeSeriesList ( dataList , options ) {
return dataList . map ( ( seriesData , index ) = > {
const datapoints = seriesData . datapoints || [ ] ;
@ -37,7 +47,7 @@ function makeTimeSeriesList(dataList, options) {
} ) ;
}
function parseInitia lState ( initial : string | undefined ) {
function parseUr lState ( initial : string | undefined ) {
if ( initial ) {
try {
const parsed = JSON . parse ( decodePathComponent ( initial ) ) ;
@ -64,8 +74,9 @@ interface IExploreState {
latency : number ;
loading : any ;
logsResult : any ;
queries : any ;
queryError : any ;
queries : any [ ] ;
queryErrors : any [ ] ;
queryHints : any [ ] ;
range : any ;
requestOptions : any ;
showingGraph : boolean ;
@ -82,7 +93,8 @@ export class Explore extends React.Component<any, IExploreState> {
constructor ( props ) {
super ( props ) ;
const { datasource , queries , range } = parseInitialState ( props . routeParams . state ) ;
const initialState : IExploreState = props . initialState ;
const { datasource , queries , range } = parseUrlState ( props . routeParams . state ) ;
this . state = {
datasource : null ,
datasourceError : null ,
@ -95,7 +107,8 @@ export class Explore extends React.Component<any, IExploreState> {
loading : false ,
logsResult : null ,
queries : ensureQueries ( queries ) ,
queryError : null ,
queryErrors : [ ] ,
queryHints : [ ] ,
range : range || { . . . DEFAULT_RANGE } ,
requestOptions : null ,
showingGraph : true ,
@ -105,7 +118,7 @@ export class Explore extends React.Component<any, IExploreState> {
supportsLogs : null ,
supportsTable : null ,
tableResult : null ,
. . . props . initialState ,
. . . initialState ,
} ;
}
@ -191,6 +204,8 @@ export class Explore extends React.Component<any, IExploreState> {
datasourceLoading : true ,
graphResult : null ,
logsResult : null ,
queryErrors : [ ] ,
queryHints : [ ] ,
tableResult : null ,
} ) ;
const datasource = await this . props . datasourceSrv . get ( option . value ) ;
@ -199,6 +214,7 @@ export class Explore extends React.Component<any, IExploreState> {
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 = {
@ -208,7 +224,18 @@ export class Explore extends React.Component<any, IExploreState> {
} ;
const nextQueries = [ . . . queries ] ;
nextQueries [ index ] = nextQuery ;
this . setState ( { queries : nextQueries } , override ? ( ) = > this . onSubmit ( ) : undefined ) ;
if ( override ) {
queryErrors = [ ] ;
queryHints = [ ] ;
}
this . setState (
{
queryErrors ,
queryHints ,
queries : nextQueries ,
} ,
override ? ( ) = > this . onSubmit ( ) : undefined
) ;
} ;
onChangeTime = nextRange = > {
@ -255,13 +282,32 @@ export class Explore extends React.Component<any, IExploreState> {
} ;
onClickTableCell = ( columnKey : string , rowValue : string ) = > {
this . onModifyQueries ( { type : 'ADD_FILTER' , key : columnKey , value : rowValue } ) ;
} ;
onModifyQueries = ( action : object , index? : number ) = > {
const { datasource , queries } = this . state ;
if ( datasource && datasource . modifyQuery ) {
const nextQueries = queries . map ( q = > ( {
. . . q ,
edited : false ,
query : datasource.modifyQuery ( q . query , { addFilter : { key : columnKey , value : rowValue } } ) ,
} ) ) ;
let nextQueries ;
if ( index === undefined ) {
// Modify all queries
nextQueries = queries . map ( q = > ( {
. . . q ,
edited : false ,
query : datasource.modifyQuery ( q . query , action ) ,
} ) ) ;
} else {
// Modify query only at index
nextQueries = [
. . . queries . slice ( 0 , index ) ,
{
. . . queries [ index ] ,
edited : false ,
query : datasource.modifyQuery ( queries [ index ] . query , action ) ,
} ,
. . . queries . slice ( index + 1 ) ,
] ;
}
this . setState ( { queries : nextQueries } , ( ) = > this . onSubmit ( ) ) ;
}
} ;
@ -309,7 +355,7 @@ export class Explore extends React.Component<any, IExploreState> {
this . setState ( { history } ) ;
}
buildQueryOptions ( targetOptions : { format : string ; instant? : boolean } ) {
buildQueryOptions ( targetOptions : { format : string ; hinting? : boolean ; instant? : boolean } ) {
const { datasource , queries , range } = this . state ;
const resolution = this . el . offsetWidth ;
const absoluteRange = {
@ -333,19 +379,20 @@ export class Explore extends React.Component<any, IExploreState> {
if ( ! hasQuery ( queries ) ) {
return ;
}
this . setState ( { latency : 0 , loading : true , graphResult : null , queryError : null } ) ;
this . setState ( { latency : 0 , loading : true , graphResult : null , queryErrors : [ ] , queryHints : [ ] } ) ;
const now = Date . now ( ) ;
const options = this . buildQueryOptions ( { format : 'time_series' , instant : false } ) ;
const options = this . buildQueryOptions ( { format : 'time_series' , instant : false , hinting : true } ) ;
try {
const res = await datasource . query ( options ) ;
const result = makeTimeSeriesList ( res . data , options ) ;
const queryHints = res . hints ? makeHints ( res . hints ) : [ ] ;
const latency = Date . now ( ) - now ;
this . setState ( { latency , loading : false , graphResult : result , requestOptions : options } ) ;
this . setState ( { latency , loading : false , graphResult : result , queryHints , requestOptions : options } ) ;
this . onQuerySuccess ( datasource . meta . id , queries ) ;
} catch ( response ) {
console . error ( response ) ;
const queryError = response . data ? response.data.error : response ;
this . setState ( { loading : false , queryError } ) ;
this . setState ( { loading : false , queryErrors : [ queryError ] } ) ;
}
}
@ -354,7 +401,7 @@ export class Explore extends React.Component<any, IExploreState> {
if ( ! hasQuery ( queries ) ) {
return ;
}
this . setState ( { latency : 0 , loading : true , queryError : null , tableResult : null } ) ;
this . setState ( { latency : 0 , loading : true , queryErrors : [ ] , queryHints : [ ] , tableResult : null } ) ;
const now = Date . now ( ) ;
const options = this . buildQueryOptions ( {
format : 'table' ,
@ -369,7 +416,7 @@ export class Explore extends React.Component<any, IExploreState> {
} catch ( response ) {
console . error ( response ) ;
const queryError = response . data ? response.data.error : response ;
this . setState ( { loading : false , queryError } ) ;
this . setState ( { loading : false , queryErrors : [ queryError ] } ) ;
}
}
@ -378,7 +425,7 @@ export class Explore extends React.Component<any, IExploreState> {
if ( ! hasQuery ( queries ) ) {
return ;
}
this . setState ( { latency : 0 , loading : true , queryError : null , logsResult : null } ) ;
this . setState ( { latency : 0 , loading : true , queryErrors : [ ] , queryHints : [ ] , logsResult : null } ) ;
const now = Date . now ( ) ;
const options = this . buildQueryOptions ( {
format : 'logs' ,
@ -393,7 +440,7 @@ export class Explore extends React.Component<any, IExploreState> {
} catch ( response ) {
console . error ( response ) ;
const queryError = response . data ? response.data.error : response ;
this . setState ( { loading : false , queryError } ) ;
this . setState ( { loading : false , queryErrors : [ queryError ] } ) ;
}
}
@ -415,7 +462,8 @@ export class Explore extends React.Component<any, IExploreState> {
loading ,
logsResult ,
queries ,
queryError ,
queryErrors ,
queryHints ,
range ,
requestOptions ,
showingGraph ,
@ -449,12 +497,12 @@ export class Explore extends React.Component<any, IExploreState> {
< / a >
< / div >
) : (
< div className = "navbar-buttons explore-first-button" >
< button className = "btn navbar-button" onClick = { this . onClickCloseSplit } >
Close Split
< div className = "navbar-buttons explore-first-button" >
< button className = "btn navbar-button" onClick = { this . onClickCloseSplit } >
Close Split
< / button >
< / div >
) }
< / div >
) }
{ ! datasourceMissing ? (
< div className = "navbar-buttons" >
< Select
@ -504,14 +552,15 @@ export class Explore extends React.Component<any, IExploreState> {
< QueryRows
history = { history }
queries = { queries }
queryErrors = { queryErrors }
queryHints = { queryHints }
request = { this . request }
onAddQueryRow = { this . onAddQueryRow }
onChangeQuery = { this . onChangeQuery }
onClickHintFix = { this . onModifyQueries }
onExecuteQuery = { this . onSubmit }
onRemoveQueryRow = { this . onRemoveQueryRow }
/ >
{ queryError && ! loading ? < div className = "text-warning m-a-2" > { queryError } < / div > : null }
< div className = "result-options" >
{ supportsGraph ? (
< button className = { ` btn navbar-button ${ graphButtonActive } ` } onClick = { this . onClickGraphButton } >