Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
nexpie-grafana-theme
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kornkitt Poolsup
nexpie-grafana-theme
Commits
7863d2d8
Commit
7863d2d8
authored
Oct 28, 2018
by
Torkel Ödegaard
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of github.com:grafana/grafana
parents
52669032
9f35b8a6
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
377 additions
and
31 deletions
+377
-31
docs/sources/auth/gitlab.md
+2
-2
public/app/features/explore/Explore.tsx
+24
-12
public/app/features/explore/PlaceholdersBuffer.test.ts
+72
-0
public/app/features/explore/PlaceholdersBuffer.ts
+112
-0
public/app/features/explore/QueryField.tsx
+26
-8
public/app/plugins/datasource/prometheus/datasource.ts
+3
-0
public/app/plugins/datasource/prometheus/language_provider.ts
+20
-7
public/app/plugins/datasource/prometheus/query_hints.ts
+24
-0
public/app/plugins/datasource/prometheus/specs/language_provider.test.ts
+71
-0
public/app/plugins/datasource/prometheus/specs/query_hints.test.ts
+22
-1
public/app/plugins/datasource/stackdriver/datasource.ts
+0
-1
public/app/types/explore.ts
+1
-0
No files found.
docs/sources/auth/gitlab.md
View file @
7863d2d8
...
...
@@ -100,12 +100,12 @@ display name, especially if the display name contains spaces or special
characters. Make sure you always use the group or subgroup name as it appears
in the URL of the group or subgroup.
Here's a complete example with
`allo
ed
_sign_up`
enabled, and access limited to
Here's a complete example with
`allo
w
_sign_up`
enabled, and access limited to
the
`example`
and
`foo/bar`
groups:
```
ini
[auth.gitlab]
enabled
=
fals
e
enabled
=
tru
e
allow_sign_up
=
true
client_id
=
GITLAB_APPLICATION_ID
client_secret
=
GITLAB_SECRET
...
...
public/app/features/explore/Explore.tsx
View file @
7863d2d8
...
...
@@ -373,9 +373,10 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
this
.
onModifyQueries
({
type
:
'ADD_FILTER'
,
key
:
columnKey
,
value
:
rowValue
});
};
onModifyQueries
=
(
action
:
object
,
index
?:
number
)
=>
{
onModifyQueries
=
(
action
,
index
?:
number
)
=>
{
const
{
datasource
}
=
this
.
state
;
if
(
datasource
&&
datasource
.
modifyQuery
)
{
const
preventSubmit
=
action
.
preventSubmit
;
this
.
setState
(
state
=>
{
const
{
queries
,
queryTransactions
}
=
state
;
...
...
@@ -391,16 +392,26 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
nextQueryTransactions
=
[];
}
else
{
// Modify query only at index
nextQueries
=
[
...
queries
.
slice
(
0
,
index
),
{
key
:
generateQueryKey
(
index
),
query
:
datasource
.
modifyQuery
(
this
.
queryExpressions
[
index
],
action
),
},
...
queries
.
slice
(
index
+
1
),
];
// Discard transactions related to row query
nextQueryTransactions
=
queryTransactions
.
filter
(
qt
=>
qt
.
rowIndex
!==
index
);
nextQueries
=
queries
.
map
((
q
,
i
)
=>
{
// Synchronise all queries with local query cache to ensure consistency
q
.
query
=
this
.
queryExpressions
[
i
];
return
i
===
index
?
{
key
:
generateQueryKey
(
index
),
query
:
datasource
.
modifyQuery
(
q
.
query
,
action
),
}
:
q
;
});
nextQueryTransactions
=
queryTransactions
// Consume the hint corresponding to the action
.
map
(
qt
=>
{
if
(
qt
.
hints
!=
null
&&
qt
.
rowIndex
===
index
)
{
qt
.
hints
=
qt
.
hints
.
filter
(
hint
=>
hint
.
fix
.
action
!==
action
);
}
return
qt
;
})
// Preserve previous row query transaction to keep results visible if next query is incomplete
.
filter
(
qt
=>
preventSubmit
||
qt
.
rowIndex
!==
index
);
}
this
.
queryExpressions
=
nextQueries
.
map
(
q
=>
q
.
query
);
return
{
...
...
@@ -408,7 +419,8 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
queryTransactions
:
nextQueryTransactions
,
};
},
()
=>
this
.
onSubmit
()
// Accepting certain fixes do not result in a well-formed query which should not be submitted
!
preventSubmit
?
()
=>
this
.
onSubmit
()
:
null
);
}
};
...
...
public/app/features/explore/PlaceholdersBuffer.test.ts
0 → 100644
View file @
7863d2d8
import
PlaceholdersBuffer
from
'./PlaceholdersBuffer'
;
describe
(
'PlaceholdersBuffer'
,
()
=>
{
it
(
'does nothing if no placeholders are defined'
,
()
=>
{
const
text
=
'metric'
;
const
buffer
=
new
PlaceholdersBuffer
(
text
);
expect
(
buffer
.
hasPlaceholders
()).
toBe
(
false
);
expect
(
buffer
.
toString
()).
toBe
(
text
);
expect
(
buffer
.
getNextMoveOffset
()).
toBe
(
0
);
});
it
(
'respects the traversal order of placeholders'
,
()
=>
{
const
text
=
'sum($2 offset $1) by ($3)'
;
const
buffer
=
new
PlaceholdersBuffer
(
text
);
expect
(
buffer
.
hasPlaceholders
()).
toBe
(
true
);
expect
(
buffer
.
toString
()).
toBe
(
'sum( offset ) by ()'
);
expect
(
buffer
.
getNextMoveOffset
()).
toBe
(
12
);
buffer
.
setNextPlaceholderValue
(
'1h'
);
expect
(
buffer
.
hasPlaceholders
()).
toBe
(
true
);
expect
(
buffer
.
toString
()).
toBe
(
'sum( offset 1h) by ()'
);
expect
(
buffer
.
getNextMoveOffset
()).
toBe
(
-
10
);
buffer
.
setNextPlaceholderValue
(
'metric'
);
expect
(
buffer
.
hasPlaceholders
()).
toBe
(
true
);
expect
(
buffer
.
toString
()).
toBe
(
'sum(metric offset 1h) by ()'
);
expect
(
buffer
.
getNextMoveOffset
()).
toBe
(
16
);
buffer
.
setNextPlaceholderValue
(
'label'
);
expect
(
buffer
.
hasPlaceholders
()).
toBe
(
false
);
expect
(
buffer
.
toString
()).
toBe
(
'sum(metric offset 1h) by (label)'
);
expect
(
buffer
.
getNextMoveOffset
()).
toBe
(
0
);
});
it
(
'respects the traversal order of adjacent placeholders'
,
()
=>
{
const
text
=
'$1$3$2$4'
;
const
buffer
=
new
PlaceholdersBuffer
(
text
);
expect
(
buffer
.
hasPlaceholders
()).
toBe
(
true
);
expect
(
buffer
.
toString
()).
toBe
(
''
);
expect
(
buffer
.
getNextMoveOffset
()).
toBe
(
0
);
buffer
.
setNextPlaceholderValue
(
'1'
);
expect
(
buffer
.
hasPlaceholders
()).
toBe
(
true
);
expect
(
buffer
.
toString
()).
toBe
(
'1'
);
expect
(
buffer
.
getNextMoveOffset
()).
toBe
(
0
);
buffer
.
setNextPlaceholderValue
(
'2'
);
expect
(
buffer
.
hasPlaceholders
()).
toBe
(
true
);
expect
(
buffer
.
toString
()).
toBe
(
'12'
);
expect
(
buffer
.
getNextMoveOffset
()).
toBe
(
-
1
);
buffer
.
setNextPlaceholderValue
(
'3'
);
expect
(
buffer
.
hasPlaceholders
()).
toBe
(
true
);
expect
(
buffer
.
toString
()).
toBe
(
'132'
);
expect
(
buffer
.
getNextMoveOffset
()).
toBe
(
1
);
buffer
.
setNextPlaceholderValue
(
'4'
);
expect
(
buffer
.
hasPlaceholders
()).
toBe
(
false
);
expect
(
buffer
.
toString
()).
toBe
(
'1324'
);
expect
(
buffer
.
getNextMoveOffset
()).
toBe
(
0
);
});
});
public/app/features/explore/PlaceholdersBuffer.ts
0 → 100644
View file @
7863d2d8
/**
* Provides a stateful means of managing placeholders in text.
*
* Placeholders are numbers prefixed with the `$` character (e.g. `$1`).
* Each number value represents the order in which a placeholder should
* receive focus if multiple placeholders exist.
*
* Example scenario given `sum($3 offset $1) by($2)`:
* 1. `sum( offset |) by()`
* 2. `sum( offset 1h) by(|)`
* 3. `sum(| offset 1h) by (label)`
*/
export
default
class
PlaceholdersBuffer
{
private
nextMoveOffset
:
number
;
private
orders
:
number
[];
private
parts
:
string
[];
constructor
(
text
:
string
)
{
const
result
=
this
.
parse
(
text
);
const
nextPlaceholderIndex
=
result
.
orders
.
length
?
result
.
orders
[
0
]
:
0
;
this
.
nextMoveOffset
=
this
.
getOffsetBetween
(
result
.
parts
,
0
,
nextPlaceholderIndex
);
this
.
orders
=
result
.
orders
;
this
.
parts
=
result
.
parts
;
}
clearPlaceholders
()
{
this
.
nextMoveOffset
=
0
;
this
.
orders
=
[];
}
getNextMoveOffset
():
number
{
return
this
.
nextMoveOffset
;
}
hasPlaceholders
():
boolean
{
return
this
.
orders
.
length
>
0
;
}
setNextPlaceholderValue
(
value
:
string
)
{
if
(
this
.
orders
.
length
===
0
)
{
return
;
}
const
currentPlaceholderIndex
=
this
.
orders
[
0
];
this
.
parts
[
currentPlaceholderIndex
]
=
value
;
this
.
orders
=
this
.
orders
.
slice
(
1
);
if
(
this
.
orders
.
length
===
0
)
{
this
.
nextMoveOffset
=
0
;
return
;
}
const
nextPlaceholderIndex
=
this
.
orders
[
0
];
// Case should never happen but handle it gracefully in case
if
(
currentPlaceholderIndex
===
nextPlaceholderIndex
)
{
this
.
nextMoveOffset
=
0
;
return
;
}
const
backwardMove
=
currentPlaceholderIndex
>
nextPlaceholderIndex
;
const
indices
=
backwardMove
?
{
start
:
nextPlaceholderIndex
+
1
,
end
:
currentPlaceholderIndex
+
1
}
:
{
start
:
currentPlaceholderIndex
+
1
,
end
:
nextPlaceholderIndex
};
this
.
nextMoveOffset
=
(
backwardMove
?
-
1
:
1
)
*
this
.
getOffsetBetween
(
this
.
parts
,
indices
.
start
,
indices
.
end
);
}
toString
():
string
{
return
this
.
parts
.
join
(
''
);
}
private
getOffsetBetween
(
parts
:
string
[],
startIndex
:
number
,
endIndex
:
number
)
{
return
parts
.
slice
(
startIndex
,
endIndex
).
reduce
((
offset
,
part
)
=>
offset
+
part
.
length
,
0
);
}
private
parse
(
text
:
string
):
ParseResult
{
const
placeholderRegExp
=
/
\$(\d
+
)
/g
;
const
parts
=
[];
const
orders
=
[];
let
textOffset
=
0
;
while
(
true
)
{
const
match
=
placeholderRegExp
.
exec
(
text
);
if
(
!
match
)
{
break
;
}
const
part
=
text
.
slice
(
textOffset
,
match
.
index
);
parts
.
push
(
part
);
// Accounts for placeholders at text boundaries
if
(
part
!==
''
)
{
parts
.
push
(
''
);
}
const
order
=
parseInt
(
match
[
1
],
10
);
orders
.
push
({
index
:
parts
.
length
-
1
,
order
});
textOffset
+=
part
.
length
+
match
.
length
;
}
// Ensures string serialisation still works if no placeholders were parsed
// and also accounts for the remainder of text with placeholders
parts
.
push
(
text
.
slice
(
textOffset
));
return
{
// Placeholder values do not necessarily appear sequentially so sort the
// indices to traverse in priority order
orders
:
orders
.
sort
((
o1
,
o2
)
=>
o1
.
order
-
o2
.
order
).
map
(
o
=>
o
.
index
),
parts
,
};
}
}
type
ParseResult
=
{
/**
* Indices to placeholder items in `parts` in traversal order.
*/
orders
:
number
[];
/**
* Parts comprising the original text with placeholders occupying distinct items.
*/
parts
:
string
[];
};
public/app/features/explore/QueryField.tsx
View file @
7863d2d8
...
...
@@ -12,6 +12,7 @@ import NewlinePlugin from './slate-plugins/newline';
import
Typeahead
from
'./Typeahead'
;
import
{
makeFragment
,
makeValue
}
from
'./Value'
;
import
PlaceholdersBuffer
from
'./PlaceholdersBuffer'
;
export
const
TYPEAHEAD_DEBOUNCE
=
100
;
...
...
@@ -61,12 +62,15 @@ export interface TypeaheadInput {
class
QueryField
extends
React
.
PureComponent
<
TypeaheadFieldProps
,
TypeaheadFieldState
>
{
menuEl
:
HTMLElement
|
null
;
placeholdersBuffer
:
PlaceholdersBuffer
;
plugins
:
any
[];
resetTimer
:
any
;
constructor
(
props
,
context
)
{
super
(
props
,
context
);
this
.
placeholdersBuffer
=
new
PlaceholdersBuffer
(
props
.
initialValue
||
''
);
// Base plugins
this
.
plugins
=
[
ClearPlugin
(),
NewlinePlugin
(),
...
props
.
additionalPlugins
];
...
...
@@ -76,7 +80,7 @@ class QueryField extends React.PureComponent<TypeaheadFieldProps, TypeaheadField
typeaheadIndex
:
0
,
typeaheadPrefix
:
''
,
typeaheadText
:
''
,
value
:
makeValue
(
props
.
initialValue
||
''
,
props
.
syntax
),
value
:
makeValue
(
this
.
placeholdersBuffer
.
toString
()
,
props
.
syntax
),
};
}
...
...
@@ -101,12 +105,14 @@ class QueryField extends React.PureComponent<TypeaheadFieldProps, TypeaheadField
componentWillReceiveProps
(
nextProps
:
TypeaheadFieldProps
)
{
if
(
nextProps
.
syntaxLoaded
&&
!
this
.
props
.
syntaxLoaded
)
{
// Need a bogus edit to re-render the editor after syntax has fully loaded
this
.
onChange
(
this
.
state
.
value
.
change
()
.
insertText
(
' '
)
.
deleteBackward
()
);
const
change
=
this
.
state
.
value
.
change
()
.
insertText
(
' '
)
.
deleteBackward
();
if
(
this
.
placeholdersBuffer
.
hasPlaceholders
())
{
change
.
move
(
this
.
placeholdersBuffer
.
getNextMoveOffset
()).
focus
();
}
this
.
onChange
(
change
);
}
}
...
...
@@ -289,7 +295,17 @@ class QueryField extends React.PureComponent<TypeaheadFieldProps, TypeaheadField
}
const
suggestion
=
getSuggestionByIndex
(
suggestions
,
typeaheadIndex
);
this
.
applyTypeahead
(
change
,
suggestion
);
const
nextChange
=
this
.
applyTypeahead
(
change
,
suggestion
);
const
insertTextOperation
=
nextChange
.
operations
.
find
(
operation
=>
operation
.
type
===
'insert_text'
);
if
(
insertTextOperation
)
{
const
suggestionText
=
insertTextOperation
.
text
;
this
.
placeholdersBuffer
.
setNextPlaceholderValue
(
suggestionText
);
if
(
this
.
placeholdersBuffer
.
hasPlaceholders
())
{
nextChange
.
move
(
this
.
placeholdersBuffer
.
getNextMoveOffset
()).
focus
();
}
}
return
true
;
}
break
;
...
...
@@ -336,6 +352,8 @@ class QueryField extends React.PureComponent<TypeaheadFieldProps, TypeaheadField
// If we dont wait here, menu clicks wont work because the menu
// will be gone.
this
.
resetTimer
=
setTimeout
(
this
.
resetTypeahead
,
100
);
// Disrupting placeholder entry wipes all remaining placeholders needing input
this
.
placeholdersBuffer
.
clearPlaceholders
();
if
(
onBlur
)
{
onBlur
();
}
...
...
public/app/plugins/datasource/prometheus/datasource.ts
View file @
7863d2d8
...
...
@@ -464,6 +464,9 @@ export class PrometheusDatasource {
case '
ADD_RATE
': {
return `rate(${query}[5m])`;
}
case '
ADD_SUM
': {
return `sum(${query.trim()}) by ($1)`;
}
case '
EXPAND_RULES
': {
const mapping = action.mapping;
if (mapping) {
...
...
public/app/plugins/datasource/prometheus/language_provider.ts
View file @
7863d2d8
...
...
@@ -162,16 +162,29 @@ export default class PromQlLanguageProvider extends LanguageProvider {
let
refresher
:
Promise
<
any
>
=
null
;
const
suggestions
:
CompletionItemGroup
[]
=
[];
// sum(foo{bar="1"}) by (|)
const
line
=
value
.
anchorBlock
.
getText
();
const
cursorOffset
:
number
=
value
.
anchorOffset
;
// sum(foo{bar="1"}) by (
const
leftSide
=
line
.
slice
(
0
,
cursorOffset
);
// Stitch all query lines together to support multi-line queries
let
queryOffset
;
const
queryText
=
value
.
document
.
getBlocks
().
reduce
((
text
,
block
)
=>
{
const
blockText
=
block
.
getText
();
if
(
value
.
anchorBlock
.
key
===
block
.
key
)
{
// Newline characters are not accounted for but this is irrelevant
// for the purpose of extracting the selector string
queryOffset
=
value
.
anchorOffset
+
text
.
length
;
}
text
+=
blockText
;
return
text
;
},
''
);
const
leftSide
=
queryText
.
slice
(
0
,
queryOffset
);
const
openParensAggregationIndex
=
leftSide
.
lastIndexOf
(
'('
);
const
openParensSelectorIndex
=
leftSide
.
slice
(
0
,
openParensAggregationIndex
).
lastIndexOf
(
'('
);
const
closeParensSelectorIndex
=
leftSide
.
slice
(
openParensSelectorIndex
).
indexOf
(
')'
)
+
openParensSelectorIndex
;
// foo{bar="1"}
const
selectorString
=
leftSide
.
slice
(
openParensSelectorIndex
+
1
,
closeParensSelectorIndex
);
let
selectorString
=
leftSide
.
slice
(
openParensSelectorIndex
+
1
,
closeParensSelectorIndex
);
// Range vector syntax not accounted for by subsequent parse so discard it if present
selectorString
=
selectorString
.
replace
(
/
\[[^\]]
+
\]
$/
,
''
);
const
selector
=
parseSelector
(
selectorString
,
selectorString
.
length
-
2
).
selector
;
const
labelKeys
=
this
.
labelKeys
[
selector
];
...
...
public/app/plugins/datasource/prometheus/query_hints.ts
View file @
7863d2d8
...
...
@@ -2,6 +2,11 @@ import _ from 'lodash';
import
{
QueryHint
}
from
'app/types/explore'
;
/**
* Number of time series results needed before starting to suggest sum aggregation hints
*/
export
const
SUM_HINT_THRESHOLD_COUNT
=
20
;
export
function
getQueryHints
(
query
:
string
,
series
?:
any
[],
datasource
?:
any
):
QueryHint
[]
{
const
hints
=
[];
...
...
@@ -90,5 +95,24 @@ export function getQueryHints(query: string, series?: any[], datasource?: any):
});
}
}
if
(
series
.
length
>=
SUM_HINT_THRESHOLD_COUNT
)
{
const
simpleMetric
=
query
.
trim
().
match
(
/^
\w
+$/
);
if
(
simpleMetric
)
{
hints
.
push
({
type
:
'ADD_SUM'
,
label
:
'Many time series results returned.'
,
fix
:
{
label
:
'Consider aggregating with sum().'
,
action
:
{
type
:
'ADD_SUM'
,
query
:
query
,
preventSubmit
:
true
,
},
},
});
}
}
return
hints
.
length
>
0
?
hints
:
null
;
}
public/app/plugins/datasource/prometheus/specs/language_provider.test.ts
View file @
7863d2d8
...
...
@@ -198,5 +198,76 @@ describe('Language completion provider', () => {
expect
(
result
.
context
).
toBe
(
'context-aggregation'
);
expect
(
result
.
suggestions
).
toEqual
([{
items
:
[{
label
:
'bar'
}],
label
:
'Labels'
}]);
});
it
(
'returns label suggestions inside a multi-line aggregation context'
,
()
=>
{
const
instance
=
new
LanguageProvider
(
datasource
,
{
labelKeys
:
{
'{__name__="metric"}'
:
[
'label1'
,
'label2'
,
'label3'
]
},
});
const
value
=
Plain
.
deserialize
(
'sum(
\
nmetric
\
n)
\
nby ()'
);
const
aggregationTextBlock
=
value
.
document
.
getBlocksAsArray
()[
3
];
const
range
=
value
.
selection
.
moveToStartOf
(
aggregationTextBlock
).
merge
({
anchorOffset
:
4
});
const
valueWithSelection
=
value
.
change
().
select
(
range
).
value
;
const
result
=
instance
.
provideCompletionItems
({
text
:
''
,
prefix
:
''
,
wrapperClasses
:
[
'context-aggregation'
],
value
:
valueWithSelection
,
});
expect
(
result
.
context
).
toBe
(
'context-aggregation'
);
expect
(
result
.
suggestions
).
toEqual
([
{
items
:
[{
label
:
'label1'
},
{
label
:
'label2'
},
{
label
:
'label3'
}],
label
:
'Labels'
,
},
]);
});
it
(
'returns label suggestions inside an aggregation context with a range vector'
,
()
=>
{
const
instance
=
new
LanguageProvider
(
datasource
,
{
labelKeys
:
{
'{__name__="metric"}'
:
[
'label1'
,
'label2'
,
'label3'
]
},
});
const
value
=
Plain
.
deserialize
(
'sum(rate(metric[1h])) by ()'
);
const
range
=
value
.
selection
.
merge
({
anchorOffset
:
26
,
});
const
valueWithSelection
=
value
.
change
().
select
(
range
).
value
;
const
result
=
instance
.
provideCompletionItems
({
text
:
''
,
prefix
:
''
,
wrapperClasses
:
[
'context-aggregation'
],
value
:
valueWithSelection
,
});
expect
(
result
.
context
).
toBe
(
'context-aggregation'
);
expect
(
result
.
suggestions
).
toEqual
([
{
items
:
[{
label
:
'label1'
},
{
label
:
'label2'
},
{
label
:
'label3'
}],
label
:
'Labels'
,
},
]);
});
it
(
'returns label suggestions inside an aggregation context with a range vector and label'
,
()
=>
{
const
instance
=
new
LanguageProvider
(
datasource
,
{
labelKeys
:
{
'{__name__="metric",label1="value"}'
:
[
'label1'
,
'label2'
,
'label3'
]
},
});
const
value
=
Plain
.
deserialize
(
'sum(rate(metric{label1="value"}[1h])) by ()'
);
const
range
=
value
.
selection
.
merge
({
anchorOffset
:
42
,
});
const
valueWithSelection
=
value
.
change
().
select
(
range
).
value
;
const
result
=
instance
.
provideCompletionItems
({
text
:
''
,
prefix
:
''
,
wrapperClasses
:
[
'context-aggregation'
],
value
:
valueWithSelection
,
});
expect
(
result
.
context
).
toBe
(
'context-aggregation'
);
expect
(
result
.
suggestions
).
toEqual
([
{
items
:
[{
label
:
'label1'
},
{
label
:
'label2'
},
{
label
:
'label3'
}],
label
:
'Labels'
,
},
]);
});
});
});
public/app/plugins/datasource/prometheus/specs/query_hints.test.ts
View file @
7863d2d8
import
{
getQueryHints
}
from
'../query_hints'
;
import
{
getQueryHints
,
SUM_HINT_THRESHOLD_COUNT
}
from
'../query_hints'
;
describe
(
'getQueryHints()'
,
()
=>
{
it
(
'returns no hints for no series'
,
()
=>
{
...
...
@@ -79,4 +79,25 @@ describe('getQueryHints()', () => {
},
});
});
it
(
'returns a sum hint when many time series results are returned for a simple metric'
,
()
=>
{
const
seriesCount
=
SUM_HINT_THRESHOLD_COUNT
;
const
series
=
Array
.
from
({
length
:
seriesCount
},
_
=>
({
datapoints
:
[[
0
,
0
],
[
0
,
0
]],
}));
const
hints
=
getQueryHints
(
'metric'
,
series
);
expect
(
hints
.
length
).
toBe
(
1
);
expect
(
hints
[
0
]).
toMatchObject
({
type
:
'ADD_SUM'
,
label
:
'Many time series results returned.'
,
fix
:
{
label
:
'Consider aggregating with sum().'
,
action
:
{
type
:
'ADD_SUM'
,
query
:
'metric'
,
preventSubmit
:
true
,
},
},
});
});
});
public/app/plugins/datasource/stackdriver/datasource.ts
View file @
7863d2d8
...
...
@@ -114,7 +114,6 @@ export default class StackdriverDatasource {
if
(
!
queryRes
.
series
)
{
return
;
}
this
.
projectName
=
queryRes
.
meta
.
defaultProject
;
const
unit
=
this
.
resolvePanelUnitFromTargets
(
options
.
targets
);
queryRes
.
series
.
forEach
(
series
=>
{
let
timeSerie
:
any
=
{
...
...
public/app/types/explore.ts
View file @
7863d2d8
...
...
@@ -119,6 +119,7 @@ export interface QueryFix {
export
interface
QueryFixAction
{
type
:
string
;
query
?:
string
;
preventSubmit
?:
boolean
;
}
export
interface
QueryHint
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment