2020-12-02 03:43:35 +08:00
// Libraries
2021-04-01 20:15:23 +08:00
import { css , cx } from '@emotion/css' ;
2021-08-16 20:02:13 +08:00
import { map } from 'lodash' ;
2022-04-22 21:33:13 +08:00
import React , { memo } from 'react' ;
2020-12-02 03:43:35 +08:00
// Types
2021-08-16 20:02:13 +08:00
import { SelectableValue } from '@grafana/data' ;
2022-03-02 06:46:52 +08:00
import { config } from '@grafana/runtime' ;
2022-04-22 21:33:13 +08:00
import { InlineFormLabel , RadioButtonGroup , InlineField , Input , Select } from '@grafana/ui' ;
2022-01-08 02:00:11 +08:00
import { LokiQuery , LokiQueryType } from '../types' ;
2020-12-02 03:43:35 +08:00
export interface LokiOptionFieldsProps {
lineLimitValue : string ;
2021-08-16 20:02:13 +08:00
resolution : number ;
2020-12-02 03:43:35 +08:00
query : LokiQuery ;
onChange : ( value : LokiQuery ) = > void ;
onRunQuery : ( ) = > void ;
runOnBlur? : boolean ;
}
2022-03-25 20:13:55 +08:00
export const queryTypeOptions : Array < SelectableValue < LokiQueryType > > = [
2022-01-08 02:00:11 +08:00
{ value : LokiQueryType.Range , label : 'Range' , description : 'Run query over a range of time.' } ,
2021-03-09 21:17:04 +08:00
{
2022-01-08 02:00:11 +08:00
value : LokiQueryType.Instant ,
2021-03-09 21:17:04 +08:00
label : 'Instant' ,
description : 'Run query against a single point in time. For this query, the "To" time is used.' ,
} ,
2020-12-02 03:43:35 +08:00
] ;
2022-03-02 06:46:52 +08:00
if ( config . featureToggles . lokiLive ) {
queryTypeOptions . push ( {
value : LokiQueryType.Stream ,
label : 'Stream' ,
description : 'Run a query and keep sending results on an interval' ,
} ) ;
}
2021-08-16 20:02:13 +08:00
export const DEFAULT_RESOLUTION : SelectableValue < number > = {
value : 1 ,
label : '1/1' ,
} ;
2022-03-25 20:13:55 +08:00
export const RESOLUTION_OPTIONS : Array < SelectableValue < number > > = [ DEFAULT_RESOLUTION ] . concat (
2021-08-16 20:02:13 +08:00
map ( [ 2 , 3 , 4 , 5 , 10 ] , ( value : number ) = > ( {
value ,
label : '1/' + value ,
} ) )
) ;
2020-12-02 03:43:35 +08:00
export function LokiOptionFields ( props : LokiOptionFieldsProps ) {
2022-01-08 02:00:11 +08:00
const { lineLimitValue , resolution , onRunQuery , runOnBlur , onChange } = props ;
const query = props . query ? ? { } ;
let queryType = query . queryType ? ? ( query . instant ? LokiQueryType.Instant : LokiQueryType.Range ) ;
2020-12-02 03:43:35 +08:00
function onChangeQueryLimit ( value : string ) {
const nextQuery = { . . . query , maxLines : preprocessMaxLines ( value ) } ;
onChange ( nextQuery ) ;
}
2022-01-08 02:00:11 +08:00
function onQueryTypeChange ( queryType : LokiQueryType ) {
const { instant , range , . . . rest } = query ;
onChange ( { . . . rest , queryType } ) ;
2020-12-02 03:43:35 +08:00
}
function onMaxLinesChange ( e : React.SyntheticEvent < HTMLInputElement > ) {
if ( query . maxLines !== preprocessMaxLines ( e . currentTarget . value ) ) {
onChangeQueryLimit ( e . currentTarget . value ) ;
}
}
function onReturnKeyDown ( e : React.KeyboardEvent < HTMLInputElement > ) {
if ( e . key === 'Enter' ) {
onRunQuery ( ) ;
}
}
2021-08-16 20:02:13 +08:00
function onResolutionChange ( option : SelectableValue < number > ) {
const nextQuery = { . . . query , resolution : option.value } ;
onChange ( nextQuery ) ;
}
2020-12-02 03:43:35 +08:00
return (
< div aria - label = "Loki extra field" className = "gf-form-inline" >
{ /*Query type field*/ }
< div
data - testid = "queryTypeField"
className = { cx (
'gf-form explore-input-margin' ,
css `
flex - wrap : nowrap ;
`
) }
aria - label = "Query type field"
>
2021-03-09 21:17:04 +08:00
< InlineFormLabel width = "auto" > Query type < / InlineFormLabel >
2020-12-02 03:43:35 +08:00
< RadioButtonGroup
options = { queryTypeOptions }
value = { queryType }
onChange = { ( type : LokiQueryType ) = > {
onQueryTypeChange ( type ) ;
if ( runOnBlur ) {
onRunQuery ( ) ;
}
} }
/ >
< / div >
{ /*Line limit field*/ }
< div
data - testid = "lineLimitField"
className = { cx (
'gf-form' ,
css `
flex - wrap : nowrap ;
`
) }
aria - label = "Line limit field"
>
2021-08-16 20:02:13 +08:00
< InlineField label = "Line limit" tooltip = { 'Upper limit for number of log lines returned by query.' } >
2021-03-01 23:08:53 +08:00
< Input
className = "width-4"
placeholder = "auto"
type = "number"
min = { 0 }
onChange = { onMaxLinesChange }
onKeyDown = { onReturnKeyDown }
value = { lineLimitValue }
onBlur = { ( ) = > {
if ( runOnBlur ) {
onRunQuery ( ) ;
}
} }
/ >
< / InlineField >
2021-08-16 20:02:13 +08:00
< InlineField
label = "Resolution"
tooltip = {
'Resolution 1/1 sets step parameter of Loki metrics range queries such that each pixel corresponds to one data point. For better performance, lower resolutions can be picked. 1/2 only retrieves a data point for every other pixel, and 1/10 retrieves one data point per 10 pixels.'
}
>
2021-12-03 21:14:51 +08:00
< Select
isSearchable = { false }
onChange = { onResolutionChange }
options = { RESOLUTION_OPTIONS }
value = { resolution }
aria - label = "Select resolution"
/ >
2021-08-16 20:02:13 +08:00
< / InlineField >
2020-12-02 03:43:35 +08:00
< / div >
< / div >
) ;
}
export default memo ( LokiOptionFields ) ;
2022-03-25 20:13:55 +08:00
export function preprocessMaxLines ( value : string ) : number {
if ( value . length === 0 ) {
// empty input - falls back to dataSource.maxLines limit
return NaN ;
} else if ( value . length > 0 && ( isNaN ( + value ) || + value < 0 ) ) {
// input with at least 1 character and that is either incorrect (value in the input field is not a number) or negative
// falls back to the limit of 0 lines
return 0 ;
} else {
// default case - correct input
return + value ;
}
}