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
1d60c45a
Unverified
Commit
1d60c45a
authored
Oct 17, 2018
by
David
Committed by
GitHub
Oct 17, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #13663 from miqh/fix/label-value-suggestions
Fix typeahead behaviour for QueryField
parents
da89c27c
22e0ff8b
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
47 additions
and
14 deletions
+47
-14
public/app/features/explore/PromQueryField.test.tsx
+33
-3
public/app/features/explore/PromQueryField.tsx
+2
-2
public/app/features/explore/QueryField.tsx
+7
-1
public/app/features/explore/utils/prometheus.ts
+5
-8
No files found.
public/app/features/explore/PromQueryField.test.tsx
View file @
1d60c45a
...
@@ -96,11 +96,14 @@ describe('PromQueryField typeahead handling', () => {
...
@@ -96,11 +96,14 @@ describe('PromQueryField typeahead handling', () => {
it
(
'returns label suggestions on label context but leaves out labels that already exist'
,
()
=>
{
it
(
'returns label suggestions on label context but leaves out labels that already exist'
,
()
=>
{
const
instance
=
shallow
(
const
instance
=
shallow
(
<
PromQueryField
{
...
defaultProps
}
labelKeys=
{
{
'{job="foo"}'
:
[
'bar'
,
'job'
]
}
}
/>
<
PromQueryField
{
...
defaultProps
}
labelKeys=
{
{
'{job1="foo",job2!="foo",job3=~"foo"}'
:
[
'bar'
,
'job1'
,
'job2'
,
'job3'
]
}
}
/>
).
instance
()
as
PromQueryField
;
).
instance
()
as
PromQueryField
;
const
value
=
Plain
.
deserialize
(
'{job
=
"foo",}'
);
const
value
=
Plain
.
deserialize
(
'{job
1="foo",job2!="foo",job3=~
"foo",}'
);
const
range
=
value
.
selection
.
merge
({
const
range
=
value
.
selection
.
merge
({
anchorOffset
:
11
,
anchorOffset
:
36
,
});
});
const
valueWithSelection
=
value
.
change
().
select
(
range
).
value
;
const
valueWithSelection
=
value
.
change
().
select
(
range
).
value
;
const
result
=
instance
.
getTypeahead
({
const
result
=
instance
.
getTypeahead
({
...
@@ -113,6 +116,33 @@ describe('PromQueryField typeahead handling', () => {
...
@@ -113,6 +116,33 @@ describe('PromQueryField typeahead handling', () => {
expect
(
result
.
suggestions
).
toEqual
([{
items
:
[{
label
:
'bar'
}],
label
:
'Labels'
}]);
expect
(
result
.
suggestions
).
toEqual
([{
items
:
[{
label
:
'bar'
}],
label
:
'Labels'
}]);
});
});
it
(
'returns label value suggestions inside a label value context after a negated matching operator'
,
()
=>
{
const
instance
=
shallow
(
<
PromQueryField
{
...
defaultProps
}
labelKeys=
{
{
'{}'
:
[
'label'
]
}
}
labelValues=
{
{
'{}'
:
{
label
:
[
'a'
,
'b'
,
'c'
]
}
}
}
/>
).
instance
()
as
PromQueryField
;
const
value
=
Plain
.
deserialize
(
'{label!=}'
);
const
range
=
value
.
selection
.
merge
({
anchorOffset
:
8
});
const
valueWithSelection
=
value
.
change
().
select
(
range
).
value
;
const
result
=
instance
.
getTypeahead
({
text
:
'!='
,
prefix
:
''
,
wrapperClasses
:
[
'context-labels'
],
labelKey
:
'label'
,
value
:
valueWithSelection
,
});
expect
(
result
.
context
).
toBe
(
'context-label-values'
);
expect
(
result
.
suggestions
).
toEqual
([
{
items
:
[{
label
:
'a'
},
{
label
:
'b'
},
{
label
:
'c'
}],
label
:
'Label values for "label"'
,
},
]);
});
it
(
'returns a refresher on label context and unavailable metric'
,
()
=>
{
it
(
'returns a refresher on label context and unavailable metric'
,
()
=>
{
const
instance
=
shallow
(
const
instance
=
shallow
(
<
PromQueryField
{
...
defaultProps
}
labelKeys=
{
{
'{__name__="foo"}'
:
[
'bar'
]
}
}
/>
<
PromQueryField
{
...
defaultProps
}
labelKeys=
{
{
'{__name__="foo"}'
:
[
'bar'
]
}
}
/>
...
...
public/app/features/explore/PromQueryField.tsx
View file @
1d60c45a
...
@@ -111,7 +111,7 @@ export function willApplySuggestion(
...
@@ -111,7 +111,7 @@ export function willApplySuggestion(
case
'context-label-values'
:
{
case
'context-label-values'
:
{
// Always add quotes and remove existing ones instead
// Always add quotes and remove existing ones instead
if
(
!
(
typeaheadText
.
startsWith
(
'="'
)
||
typeaheadText
.
startsWith
(
'"'
)
))
{
if
(
!
typeaheadText
.
match
(
/^
(
!
?
=~
?
"|"
)
/
))
{
suggestion
=
`"
${
suggestion
}
`
;
suggestion
=
`"
${
suggestion
}
`
;
}
}
if
(
getNextCharacter
()
!==
'"'
)
{
if
(
getNextCharacter
()
!==
'"'
)
{
...
@@ -421,7 +421,7 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
...
@@ -421,7 +421,7 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
const
containsMetric
=
selector
.
indexOf
(
'__name__='
)
>
-
1
;
const
containsMetric
=
selector
.
indexOf
(
'__name__='
)
>
-
1
;
const
existingKeys
=
parsedSelector
?
parsedSelector
.
labelKeys
:
[];
const
existingKeys
=
parsedSelector
?
parsedSelector
.
labelKeys
:
[];
if
((
text
&&
text
.
startsWith
(
'='
))
||
_
.
includes
(
wrapperClasses
,
'attr-value'
))
{
if
((
text
&&
text
.
match
(
/^!
?
=~
?
/
))
||
_
.
includes
(
wrapperClasses
,
'attr-value'
))
{
// Label values
// Label values
if
(
labelKey
&&
this
.
state
.
labelValues
[
selector
]
&&
this
.
state
.
labelValues
[
selector
][
labelKey
])
{
if
(
labelKey
&&
this
.
state
.
labelValues
[
selector
]
&&
this
.
state
.
labelValues
[
selector
][
labelKey
])
{
const
labelValues
=
this
.
state
.
labelValues
[
selector
][
labelKey
];
const
labelValues
=
this
.
state
.
labelValues
[
selector
][
labelKey
];
...
...
public/app/features/explore/QueryField.tsx
View file @
1d60c45a
...
@@ -228,7 +228,13 @@ class QueryField extends React.PureComponent<TypeaheadFieldProps, TypeaheadField
...
@@ -228,7 +228,13 @@ class QueryField extends React.PureComponent<TypeaheadFieldProps, TypeaheadField
const
offset
=
range
.
startOffset
;
const
offset
=
range
.
startOffset
;
const
text
=
selection
.
anchorNode
.
textContent
;
const
text
=
selection
.
anchorNode
.
textContent
;
let
prefix
=
text
.
substr
(
0
,
offset
);
let
prefix
=
text
.
substr
(
0
,
offset
);
if
(
cleanText
)
{
// Label values could have valid characters erased if `cleanText()` is
// blindly applied, which would undesirably interfere with suggestions
const
labelValueMatch
=
prefix
.
match
(
/
(?:
!
?
=~
?
"
?
|"
)(
.*
)
/
);
if
(
labelValueMatch
)
{
prefix
=
labelValueMatch
[
1
];
}
else
if
(
cleanText
)
{
prefix
=
cleanText
(
prefix
);
prefix
=
cleanText
(
prefix
);
}
}
...
...
public/app/features/explore/utils/prometheus.ts
View file @
1d60c45a
...
@@ -28,7 +28,7 @@ export const cleanText = s => s.replace(/[{}[\]="(),!~+\-*/^%]/g, '').trim();
...
@@ -28,7 +28,7 @@ export const cleanText = s => s.replace(/[{}[\]="(),!~+\-*/^%]/g, '').trim();
// const cleanSelectorRegexp = /\{(\w+="[^"\n]*?")(,\w+="[^"\n]*?")*\}/;
// const cleanSelectorRegexp = /\{(\w+="[^"\n]*?")(,\w+="[^"\n]*?")*\}/;
const
selectorRegexp
=
/
\{[^
}
]
*
?\}
/
;
const
selectorRegexp
=
/
\{[^
}
]
*
?\}
/
;
const
labelRegexp
=
/
\b
\w
+="
[^
"
\n]
*
?
"
/g
;
const
labelRegexp
=
/
\b
(\w
+
)(
!
?
=~
?)(
"
[^
"
\n]
*
?
"
)
/g
;
export
function
parseSelector
(
query
:
string
,
cursorOffset
=
1
):
{
labelKeys
:
any
[];
selector
:
string
}
{
export
function
parseSelector
(
query
:
string
,
cursorOffset
=
1
):
{
labelKeys
:
any
[];
selector
:
string
}
{
if
(
!
query
.
match
(
selectorRegexp
))
{
if
(
!
query
.
match
(
selectorRegexp
))
{
// Special matcher for metrics
// Special matcher for metrics
...
@@ -66,11 +66,8 @@ export function parseSelector(query: string, cursorOffset = 1): { labelKeys: any
...
@@ -66,11 +66,8 @@ export function parseSelector(query: string, cursorOffset = 1): { labelKeys: any
// Extract clean labels to form clean selector, incomplete labels are dropped
// Extract clean labels to form clean selector, incomplete labels are dropped
const
selector
=
query
.
slice
(
prefixOpen
,
suffixClose
);
const
selector
=
query
.
slice
(
prefixOpen
,
suffixClose
);
const
labels
=
{};
const
labels
=
{};
selector
.
replace
(
labelRegexp
,
match
=>
{
selector
.
replace
(
labelRegexp
,
(
_
,
key
,
operator
,
value
)
=>
{
const
delimiterIndex
=
match
.
indexOf
(
'='
);
labels
[
key
]
=
{
value
,
operator
};
const
key
=
match
.
slice
(
0
,
delimiterIndex
);
const
value
=
match
.
slice
(
delimiterIndex
+
1
,
match
.
length
);
labels
[
key
]
=
value
;
return
''
;
return
''
;
});
});
...
@@ -78,12 +75,12 @@ export function parseSelector(query: string, cursorOffset = 1): { labelKeys: any
...
@@ -78,12 +75,12 @@ export function parseSelector(query: string, cursorOffset = 1): { labelKeys: any
const
metricPrefix
=
query
.
slice
(
0
,
prefixOpen
);
const
metricPrefix
=
query
.
slice
(
0
,
prefixOpen
);
const
metricMatch
=
metricPrefix
.
match
(
/
[
A-Za-z:
][\w
:
]
*$/
);
const
metricMatch
=
metricPrefix
.
match
(
/
[
A-Za-z:
][\w
:
]
*$/
);
if
(
metricMatch
)
{
if
(
metricMatch
)
{
labels
[
'__name__'
]
=
`"
${
metricMatch
[
0
]}
"`
;
labels
[
'__name__'
]
=
{
value
:
`"
${
metricMatch
[
0
]}
"`
,
operator
:
'='
}
;
}
}
// Build sorted selector
// Build sorted selector
const
labelKeys
=
Object
.
keys
(
labels
).
sort
();
const
labelKeys
=
Object
.
keys
(
labels
).
sort
();
const
cleanSelector
=
labelKeys
.
map
(
key
=>
`
${
key
}
=
${
labels
[
key
]
}
`
).
join
(
','
);
const
cleanSelector
=
labelKeys
.
map
(
key
=>
`
${
key
}
${
labels
[
key
].
operator
}${
labels
[
key
].
value
}
`
).
join
(
','
);
const
selectorString
=
[
'{'
,
cleanSelector
,
'}'
].
join
(
''
);
const
selectorString
=
[
'{'
,
cleanSelector
,
'}'
].
join
(
''
);
...
...
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