Show histogram for log counts in log viewer
parent
6c0d7984e4
commit
58de6abd80
|
@ -56,6 +56,7 @@ export const saveToLocalStorage = ({
|
|||
timeRange,
|
||||
dataExplorer,
|
||||
dashTimeV1: {ranges},
|
||||
logs,
|
||||
script,
|
||||
}: LocalStorage): void => {
|
||||
try {
|
||||
|
@ -72,6 +73,7 @@ export const saveToLocalStorage = ({
|
|||
dataExplorer,
|
||||
dataExplorerQueryConfigs,
|
||||
script,
|
||||
logs,
|
||||
})
|
||||
)
|
||||
} catch (err) {
|
||||
|
|
|
@ -1,13 +1,22 @@
|
|||
import {Source, Namespace, TimeRange} from 'src/types'
|
||||
import {Source, Namespace, TimeRange, QueryConfig} from 'src/types'
|
||||
import {getSource} from 'src/shared/apis'
|
||||
import {getDatabasesWithRetentionPolicies} from 'src/shared/apis/databases'
|
||||
import {buildHistogramQueryConfig} from 'src/logs/utils'
|
||||
import {getDeep} from 'src/utils/wrappers'
|
||||
import buildQuery from 'src/utils/influxql'
|
||||
import {executeQueryAsync} from 'src/logs/api'
|
||||
import {LogsState} from 'src/types/localStorage'
|
||||
|
||||
type GetState = () => {logs: LogsState}
|
||||
|
||||
export enum ActionTypes {
|
||||
SetSource = 'LOGS_SET_SOURCE',
|
||||
SetNamespaces = 'LOGS_SET_NAMESPACES',
|
||||
SetTimeRange = 'LOGS_SET_TIMERANGE',
|
||||
SetNamespace = 'LOGS_SET_NAMESPACE',
|
||||
SetHistogramQueryConfig = 'LOGS_SET_HISTOGRAM_QUERY_CONFIG',
|
||||
SetHistogramData = 'LOGS_SET_HISTOGRAM_DATA',
|
||||
ChangeZoom = 'LOGS_CHANGE_ZOOM',
|
||||
}
|
||||
|
||||
interface SetSourceAction {
|
||||
|
@ -38,11 +47,36 @@ interface SetTimeRangeAction {
|
|||
}
|
||||
}
|
||||
|
||||
interface SetHistogramQueryConfig {
|
||||
type: ActionTypes.SetHistogramQueryConfig
|
||||
payload: {
|
||||
queryConfig: QueryConfig
|
||||
}
|
||||
}
|
||||
|
||||
interface SetHistogramData {
|
||||
type: ActionTypes.SetHistogramData
|
||||
payload: {
|
||||
data: object[]
|
||||
}
|
||||
}
|
||||
|
||||
interface ChangeZoomAction {
|
||||
type: ActionTypes.ChangeZoom
|
||||
payload: {
|
||||
data: object[]
|
||||
timeRange: TimeRange
|
||||
}
|
||||
}
|
||||
|
||||
export type Action =
|
||||
| SetSourceAction
|
||||
| SetNamespacesAction
|
||||
| SetTimeRangeAction
|
||||
| SetNamespaceAction
|
||||
| SetHistogramQueryConfig
|
||||
| SetHistogramData
|
||||
| ChangeZoomAction
|
||||
|
||||
export const setSource = (source: Source): SetSourceAction => ({
|
||||
type: ActionTypes.SetSource,
|
||||
|
@ -51,12 +85,75 @@ export const setSource = (source: Source): SetSourceAction => ({
|
|||
},
|
||||
})
|
||||
|
||||
export const setNamespace = (namespace: Namespace): SetNamespaceAction => ({
|
||||
type: ActionTypes.SetNamespace,
|
||||
payload: {
|
||||
namespace,
|
||||
},
|
||||
})
|
||||
export const executeHistogramQueryAsync = () => async (
|
||||
dispatch,
|
||||
getState: GetState
|
||||
): Promise<void> => {
|
||||
const state = getState()
|
||||
const queryConfig = getDeep<QueryConfig | null>(
|
||||
state,
|
||||
'logs.histogramQueryConfig',
|
||||
null
|
||||
)
|
||||
const timeRange = getDeep<TimeRange | null>(state, 'logs.timeRange', null)
|
||||
const namespace = getDeep<Namespace | null>(
|
||||
state,
|
||||
'logs.currentNamespace',
|
||||
null
|
||||
)
|
||||
const proxyLink = getDeep<string | null>(
|
||||
state,
|
||||
'logs.currentSource.links.proxy',
|
||||
null
|
||||
)
|
||||
|
||||
if (queryConfig && timeRange && namespace && proxyLink) {
|
||||
const query = buildQuery(timeRange, queryConfig)
|
||||
const response = await executeQueryAsync(proxyLink, namespace, query)
|
||||
|
||||
dispatch({
|
||||
type: ActionTypes.SetHistogramData,
|
||||
payload: {
|
||||
data: [{response}],
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const setHistogramQueryConfigAsync = () => async (
|
||||
dispatch,
|
||||
getState: GetState
|
||||
): Promise<void> => {
|
||||
const state = getState()
|
||||
const namespace = getDeep<Namespace | null>(
|
||||
state,
|
||||
'logs.currentNamespace',
|
||||
null
|
||||
)
|
||||
const timeRange = getDeep<TimeRange | null>(state, 'logs.timeRange', null)
|
||||
|
||||
if (timeRange && namespace) {
|
||||
const queryConfig = buildHistogramQueryConfig(namespace, timeRange)
|
||||
|
||||
dispatch({
|
||||
type: ActionTypes.SetHistogramQueryConfig,
|
||||
payload: {queryConfig},
|
||||
})
|
||||
|
||||
dispatch(executeHistogramQueryAsync())
|
||||
}
|
||||
}
|
||||
|
||||
export const setNamespaceAsync = (namespace: Namespace) => async (
|
||||
dispatch
|
||||
): Promise<void> => {
|
||||
dispatch({
|
||||
type: ActionTypes.SetNamespace,
|
||||
payload: {namespace},
|
||||
})
|
||||
|
||||
dispatch(setHistogramQueryConfigAsync())
|
||||
}
|
||||
|
||||
export const setNamespaces = (
|
||||
namespaces: Namespace[]
|
||||
|
@ -67,27 +164,70 @@ export const setNamespaces = (
|
|||
},
|
||||
})
|
||||
|
||||
export const setTimeRange = (timeRange: TimeRange): SetTimeRangeAction => ({
|
||||
type: ActionTypes.SetTimeRange,
|
||||
payload: {
|
||||
timeRange,
|
||||
},
|
||||
})
|
||||
export const setTimeRangeAsync = (timeRange: TimeRange) => async (
|
||||
dispatch
|
||||
): Promise<void> => {
|
||||
dispatch({
|
||||
type: ActionTypes.SetTimeRange,
|
||||
payload: {
|
||||
timeRange,
|
||||
},
|
||||
})
|
||||
dispatch(setHistogramQueryConfigAsync())
|
||||
}
|
||||
|
||||
export const getSourceAsync = (sourceID: string) => async dispatch => {
|
||||
export const populateNamespacesAsync = (proxyLink: string) => async (
|
||||
dispatch
|
||||
): Promise<void> => {
|
||||
const namespaces = await getDatabasesWithRetentionPolicies(proxyLink)
|
||||
|
||||
if (namespaces && namespaces.length > 0) {
|
||||
dispatch(setNamespaces(namespaces))
|
||||
dispatch(setNamespaceAsync(namespaces[0]))
|
||||
}
|
||||
}
|
||||
|
||||
export const getSourceAndPopulateNamespacesAsync = (sourceID: string) => async (
|
||||
dispatch
|
||||
): Promise<void> => {
|
||||
const response = await getSource(sourceID)
|
||||
const source = response.data
|
||||
|
||||
const proxyLink = getDeep<string | null>(source, 'links.proxy', null)
|
||||
|
||||
if (proxyLink) {
|
||||
const namespaces = await getDatabasesWithRetentionPolicies(proxyLink)
|
||||
|
||||
if (namespaces && namespaces.length > 0) {
|
||||
dispatch(setNamespaces(namespaces))
|
||||
dispatch(setNamespace(namespaces[0]))
|
||||
}
|
||||
|
||||
dispatch(setSource(source))
|
||||
dispatch(populateNamespacesAsync(proxyLink))
|
||||
}
|
||||
}
|
||||
|
||||
export const changeZoomAsync = (timeRange: TimeRange) => async (
|
||||
dispatch,
|
||||
getState: GetState
|
||||
): Promise<void> => {
|
||||
const state = getState()
|
||||
const namespace = getDeep<Namespace | null>(
|
||||
state,
|
||||
'logs.currentNamespace',
|
||||
null
|
||||
)
|
||||
const proxyLink = getDeep<string | null>(
|
||||
state,
|
||||
'logs.currentSource.links.proxy',
|
||||
null
|
||||
)
|
||||
|
||||
if (namespace && proxyLink) {
|
||||
const queryConfig = buildHistogramQueryConfig(namespace, timeRange)
|
||||
const query = buildQuery(timeRange, queryConfig)
|
||||
const response = await executeQueryAsync(proxyLink, namespace, query)
|
||||
|
||||
dispatch({
|
||||
type: ActionTypes.ChangeZoom,
|
||||
payload: {
|
||||
data: [{response}],
|
||||
timeRange,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
import {proxy} from 'src/utils/queryUrlGenerator'
|
||||
import {Namespace} from 'src/types'
|
||||
import {TimeSeriesResponse} from 'src/types/series'
|
||||
|
||||
export const executeQueryAsync = async (
|
||||
proxyLink: string,
|
||||
namespace: Namespace,
|
||||
query: string
|
||||
): Promise<TimeSeriesResponse> => {
|
||||
try {
|
||||
const {data} = await proxy({
|
||||
source: proxyLink,
|
||||
db: namespace.database,
|
||||
rp: namespace.retentionPolicy,
|
||||
query,
|
||||
tempVars: [],
|
||||
resolution: null,
|
||||
})
|
||||
|
||||
return data
|
||||
} catch (error) {
|
||||
throw error
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
import LineGraph from 'src/shared/components/LineGraph'
|
||||
import {DEFAULT_LINE_COLORS} from 'src/shared/constants/graphColorPalettes'
|
||||
|
||||
import {TimeRange} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
onZoom: (lower: string, upper: string) => void
|
||||
timeRange: TimeRange
|
||||
data: object[]
|
||||
}
|
||||
|
||||
class LogViewerChart extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {timeRange, data, onZoom} = this.props
|
||||
return (
|
||||
<LineGraph
|
||||
onZoom={onZoom}
|
||||
queries={[]}
|
||||
data={data}
|
||||
displayOptions={{animatedZooms: false}}
|
||||
setResolution={this.setResolution}
|
||||
isBarGraph={true}
|
||||
timeRange={timeRange}
|
||||
colors={DEFAULT_LINE_COLORS}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
private setResolution = () => {}
|
||||
}
|
||||
|
||||
export default LogViewerChart
|
|
@ -1,14 +1,10 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
|
||||
interface Props {
|
||||
thing: string
|
||||
}
|
||||
|
||||
class LogsGraphContainer extends PureComponent<Props> {
|
||||
class LogsGraphContainer extends PureComponent {
|
||||
public render() {
|
||||
return (
|
||||
<div className="logs-viewer--graph-container">
|
||||
<p>{this.props.thing}</p>
|
||||
<div className="logs-viewer--graph">{this.props.children}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,12 +1,20 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
import {getSourceAsync, setTimeRange, setNamespace} from 'src/logs/actions'
|
||||
import {
|
||||
getSourceAndPopulateNamespacesAsync,
|
||||
setTimeRangeAsync,
|
||||
setNamespaceAsync,
|
||||
executeHistogramQueryAsync,
|
||||
changeZoomAsync,
|
||||
} from 'src/logs/actions'
|
||||
import {getSourcesAsync} from 'src/shared/actions/sources'
|
||||
import {Source, Namespace, TimeRange} from 'src/types'
|
||||
import LogViewerHeader from 'src/logs/components/LogViewerHeader'
|
||||
import LogViewerChart from 'src/logs/components/LogViewerChart'
|
||||
import GraphContainer from 'src/logs/components/LogsGraphContainer'
|
||||
import TableContainer from 'src/logs/components/LogsTableContainer'
|
||||
|
||||
import {Source, Namespace, TimeRange} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
sources: Source[]
|
||||
currentSource: Source | null
|
||||
|
@ -14,9 +22,12 @@ interface Props {
|
|||
currentNamespace: Namespace
|
||||
getSource: (sourceID: string) => void
|
||||
getSources: () => void
|
||||
setTimeRange: (timeRange: TimeRange) => void
|
||||
setNamespace: (namespace: Namespace) => void
|
||||
setTimeRangeAsync: (timeRange: TimeRange) => void
|
||||
setNamespaceAsync: (namespace: Namespace) => void
|
||||
changeZoomAsync: (timeRange: TimeRange) => void
|
||||
executeHistogramQueryAsync: () => void
|
||||
timeRange: TimeRange
|
||||
histogramData: object[]
|
||||
}
|
||||
|
||||
class LogsPage extends PureComponent<Props> {
|
||||
|
@ -42,20 +53,31 @@ class LogsPage extends PureComponent<Props> {
|
|||
</div>
|
||||
</div>
|
||||
<div className="page-contents logs-viewer">
|
||||
<GraphContainer thing="wooo" />
|
||||
<GraphContainer>{this.chart}</GraphContainer>
|
||||
<TableContainer thing="snooo" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private get chart(): JSX.Element {
|
||||
const {histogramData, timeRange} = this.props
|
||||
return (
|
||||
<LogViewerChart
|
||||
timeRange={timeRange}
|
||||
data={histogramData}
|
||||
onZoom={this.handleChartZoom}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
private get header(): JSX.Element {
|
||||
const {
|
||||
sources,
|
||||
currentSource,
|
||||
currentNamespaces,
|
||||
timeRange,
|
||||
currentNamespace,
|
||||
timeRange,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
|
@ -73,7 +95,8 @@ class LogsPage extends PureComponent<Props> {
|
|||
}
|
||||
|
||||
private handleChooseTimerange = (timeRange: TimeRange) => {
|
||||
this.props.setTimeRange(timeRange)
|
||||
this.props.setTimeRangeAsync(timeRange)
|
||||
this.props.executeHistogramQueryAsync()
|
||||
}
|
||||
|
||||
private handleChooseSource = (sourceID: string) => {
|
||||
|
@ -81,27 +104,41 @@ class LogsPage extends PureComponent<Props> {
|
|||
}
|
||||
|
||||
private handleChooseNamespace = (namespace: Namespace) => {
|
||||
// Do flip
|
||||
this.props.setNamespace(namespace)
|
||||
this.props.setNamespaceAsync(namespace)
|
||||
}
|
||||
|
||||
private handleChartZoom = (lower, upper) => {
|
||||
if (lower) {
|
||||
this.props.changeZoomAsync({lower, upper})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = ({
|
||||
sources,
|
||||
logs: {currentSource, currentNamespaces, timeRange, currentNamespace},
|
||||
logs: {
|
||||
currentSource,
|
||||
currentNamespaces,
|
||||
timeRange,
|
||||
currentNamespace,
|
||||
histogramData,
|
||||
},
|
||||
}) => ({
|
||||
sources,
|
||||
currentSource,
|
||||
currentNamespaces,
|
||||
timeRange,
|
||||
currentNamespace,
|
||||
histogramData,
|
||||
})
|
||||
|
||||
const mapDispatchToProps = {
|
||||
getSource: getSourceAsync,
|
||||
getSource: getSourceAndPopulateNamespacesAsync,
|
||||
getSources: getSourcesAsync,
|
||||
setTimeRange,
|
||||
setNamespace,
|
||||
setTimeRangeAsync,
|
||||
setNamespaceAsync,
|
||||
executeHistogramQueryAsync,
|
||||
changeZoomAsync,
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(LogsPage)
|
||||
|
|
|
@ -1,18 +1,13 @@
|
|||
import {Source, Namespace, TimeRange} from 'src/types'
|
||||
import {ActionTypes, Action} from 'src/logs/actions'
|
||||
import {LogsState} from 'src/types/localStorage'
|
||||
|
||||
interface LogsState {
|
||||
currentSource: Source | null
|
||||
currentNamespaces: Namespace[]
|
||||
currentNamespace: Namespace | null
|
||||
timeRange: TimeRange
|
||||
}
|
||||
|
||||
const defaultState = {
|
||||
const defaultState: LogsState = {
|
||||
currentSource: null,
|
||||
currentNamespaces: [],
|
||||
timeRange: {lower: 'now() - 1m', upper: null},
|
||||
currentNamespace: null,
|
||||
histogramQueryConfig: null,
|
||||
histogramData: [],
|
||||
}
|
||||
|
||||
export default (state: LogsState = defaultState, action: Action) => {
|
||||
|
@ -25,6 +20,13 @@ export default (state: LogsState = defaultState, action: Action) => {
|
|||
return {...state, timeRange: action.payload.timeRange}
|
||||
case ActionTypes.SetNamespace:
|
||||
return {...state, currentNamespace: action.payload.namespace}
|
||||
case ActionTypes.SetHistogramQueryConfig:
|
||||
return {...state, histogramQueryConfig: action.payload.queryConfig}
|
||||
case ActionTypes.SetHistogramData:
|
||||
return {...state, histogramData: action.payload.data}
|
||||
case ActionTypes.ChangeZoom:
|
||||
const {timeRange, data} = action.payload
|
||||
return {...state, timeRange, histogramData: data}
|
||||
default:
|
||||
return state
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
import uuid from 'uuid'
|
||||
import {TimeRange, Namespace, QueryConfig} from 'src/types'
|
||||
|
||||
const fields = [
|
||||
{
|
||||
alias: '',
|
||||
args: [
|
||||
{
|
||||
alias: '',
|
||||
type: 'field',
|
||||
value: 'message',
|
||||
},
|
||||
],
|
||||
type: 'func',
|
||||
value: 'count',
|
||||
},
|
||||
]
|
||||
|
||||
const defaultQueryConfig = {
|
||||
areTagsAccepted: false,
|
||||
fields,
|
||||
fill: '0',
|
||||
groupBy: {time: '2m', tags: []},
|
||||
measurement: 'syslog',
|
||||
rawText: null,
|
||||
shifts: [],
|
||||
tags: {},
|
||||
}
|
||||
|
||||
export const buildHistogramQueryConfig = (
|
||||
namespace: Namespace,
|
||||
range: TimeRange
|
||||
): QueryConfig => {
|
||||
const id = uuid.v4()
|
||||
return {
|
||||
...defaultQueryConfig,
|
||||
id,
|
||||
range,
|
||||
database: namespace.database,
|
||||
retentionPolicy: namespace.retentionPolicy,
|
||||
}
|
||||
}
|
|
@ -88,8 +88,8 @@ class Dygraph extends Component {
|
|||
|
||||
this.dygraph = new Dygraphs(graphRef, timeSeries, {
|
||||
...defaultOptions,
|
||||
...options,
|
||||
...OPTIONS,
|
||||
...options,
|
||||
})
|
||||
|
||||
const {w} = this.dygraph.getArea()
|
||||
|
|
|
@ -199,6 +199,7 @@ LineGraph.propTypes = {
|
|||
displayOptions: shape({
|
||||
stepPlot: bool,
|
||||
stackedGraph: bool,
|
||||
animatedZooms: bool,
|
||||
}),
|
||||
activeQueryIndex: number,
|
||||
ruleValues: shape({}),
|
||||
|
|
|
@ -15,9 +15,10 @@ $logs-viewer-gutter: 60px;
|
|||
}
|
||||
|
||||
.logs-viewer--graph-container {
|
||||
padding: 30px $logs-viewer-gutter 18px $logs-viewer-gutter;
|
||||
padding: 22px ($logs-viewer-gutter - 16px) 10px ($logs-viewer-gutter - 16px);
|
||||
height: $logs-viewer-graph-height;
|
||||
@include gradient-v($g2-kevlar, $g0-obsidian);
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.logs-viewer--search-container {
|
||||
|
@ -30,4 +31,11 @@ $logs-viewer-gutter: 60px;
|
|||
padding: 12px $logs-viewer-gutter 30px $logs-viewer-gutter;
|
||||
height: calc(100% - #{$logs-viewer-graph-height + $logs-viewer-search-height});
|
||||
background-color: $g3-castle;
|
||||
}
|
||||
|
||||
.logs-viewer--graph {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 8px 16px;
|
||||
}
|
|
@ -1,4 +1,13 @@
|
|||
import {QueryConfig, TimeRange} from 'src/types'
|
||||
import {QueryConfig, TimeRange, Namespace, Source} from 'src/types'
|
||||
|
||||
export interface LogsState {
|
||||
currentSource: Source | null
|
||||
currentNamespaces: Namespace[]
|
||||
currentNamespace: Namespace | null
|
||||
timeRange: TimeRange
|
||||
histogramQueryConfig: QueryConfig | null
|
||||
histogramData: object[]
|
||||
}
|
||||
|
||||
export interface LocalStorage {
|
||||
VERSION: VERSION
|
||||
|
@ -8,6 +17,7 @@ export interface LocalStorage {
|
|||
dataExplorerQueryConfigs: DataExplorerQueryConfigs
|
||||
timeRange: TimeRange
|
||||
script: string
|
||||
logs: LogsState
|
||||
}
|
||||
|
||||
export type VERSION = string
|
||||
|
|
|
@ -8,15 +8,9 @@ import {
|
|||
TYPE_IFQL,
|
||||
} from 'src/dashboards/constants'
|
||||
import {shiftTimeRange} from 'src/shared/query/helpers'
|
||||
import {QueryConfig, Field, GroupBy, TimeShift} from 'src/types'
|
||||
import {QueryConfig, Field, GroupBy, TimeShift, TimeRange} from 'src/types'
|
||||
|
||||
export const quoteIfTimestamp = ({
|
||||
lower,
|
||||
upper,
|
||||
}: {
|
||||
lower: string
|
||||
upper: string
|
||||
}): {lower: string; upper: string} => {
|
||||
export const quoteIfTimestamp = ({lower, upper}: TimeRange): TimeRange => {
|
||||
if (lower && lower.includes('Z') && !lower.includes("'")) {
|
||||
lower = `'${lower}'`
|
||||
}
|
||||
|
@ -29,7 +23,7 @@ export const quoteIfTimestamp = ({
|
|||
}
|
||||
|
||||
export default function buildInfluxQLQuery(
|
||||
timeRange,
|
||||
timeRange: TimeRange,
|
||||
config: QueryConfig,
|
||||
shift: string = ''
|
||||
): string {
|
||||
|
@ -66,7 +60,7 @@ function buildSelect(
|
|||
// type arg will reason about new query types i.e. IFQL, GraphQL, or queryConfig
|
||||
export const buildQuery = (
|
||||
type: string,
|
||||
timeRange: object,
|
||||
timeRange: TimeRange,
|
||||
config: QueryConfig,
|
||||
shift: TimeShift | null = null
|
||||
): string => {
|
||||
|
@ -201,5 +195,7 @@ function buildFill(fill: string): string {
|
|||
return ` FILL(${fill})`
|
||||
}
|
||||
|
||||
export const buildRawText = (config: QueryConfig, timeRange: object): string =>
|
||||
config.rawText || buildInfluxQLQuery(timeRange, config) || ''
|
||||
export const buildRawText = (
|
||||
config: QueryConfig,
|
||||
timeRange: TimeRange
|
||||
): string => config.rawText || buildInfluxQLQuery(timeRange, config) || ''
|
||||
|
|
Loading…
Reference in New Issue