mirror of
https://github.com/grafana/grafana.git
synced 2024-11-30 12:44:10 -06:00
Fix typeahead behaviour for QueryField
These changes were originally intended to address a bug whereby a suggestion for an already selected label value continues to appear. However, they also appear to fix several other problems in the area: - Wrong suggestions when using negated label matching operators - Misaligned label value suggestion replacements Related: #13484
This commit is contained in:
parent
b7599212e0
commit
a8c5ab76b3
@ -111,7 +111,7 @@ export function willApplySuggestion(
|
||||
|
||||
case 'context-label-values': {
|
||||
// Always add quotes and remove existing ones instead
|
||||
if (!(typeaheadText.startsWith('="') || typeaheadText.startsWith('"'))) {
|
||||
if (!typeaheadText.match(/^(!?=~?"|")/)) {
|
||||
suggestion = `"${suggestion}`;
|
||||
}
|
||||
if (getNextCharacter() !== '"') {
|
||||
@ -421,7 +421,7 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
|
||||
const containsMetric = selector.indexOf('__name__=') > -1;
|
||||
const existingKeys = parsedSelector ? parsedSelector.labelKeys : [];
|
||||
|
||||
if ((text && text.startsWith('=')) || _.includes(wrapperClasses, 'attr-value')) {
|
||||
if ((text && text.match(/^!?=~?/)) || _.includes(wrapperClasses, 'attr-value')) {
|
||||
// Label values
|
||||
if (labelKey && this.state.labelValues[selector] && this.state.labelValues[selector][labelKey]) {
|
||||
const labelValues = this.state.labelValues[selector][labelKey];
|
||||
@ -571,10 +571,10 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
|
||||
<button className="btn navbar-button navbar-button--tight">Log labels</button>
|
||||
</Cascader>
|
||||
) : (
|
||||
<Cascader options={metricsOptions} onChange={this.onChangeMetrics}>
|
||||
<button className="btn navbar-button navbar-button--tight">Metrics</button>
|
||||
</Cascader>
|
||||
)}
|
||||
<Cascader options={metricsOptions} onChange={this.onChangeMetrics}>
|
||||
<button className="btn navbar-button navbar-button--tight">Metrics</button>
|
||||
</Cascader>
|
||||
)}
|
||||
</div>
|
||||
<div className="prom-query-field-wrapper">
|
||||
<div className="slate-query-field-wrapper">
|
||||
|
@ -228,7 +228,13 @@ class QueryField extends React.PureComponent<TypeaheadFieldProps, TypeaheadField
|
||||
const offset = range.startOffset;
|
||||
const text = selection.anchorNode.textContent;
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ export const cleanText = s => s.replace(/[{}[\]="(),!~+\-*/^%]/g, '').trim();
|
||||
|
||||
// const cleanSelectorRegexp = /\{(\w+="[^"\n]*?")(,\w+="[^"\n]*?")*\}/;
|
||||
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 } {
|
||||
if (!query.match(selectorRegexp)) {
|
||||
// Special matcher for metrics
|
||||
@ -66,11 +66,8 @@ export function parseSelector(query: string, cursorOffset = 1): { labelKeys: any
|
||||
// Extract clean labels to form clean selector, incomplete labels are dropped
|
||||
const selector = query.slice(prefixOpen, suffixClose);
|
||||
const labels = {};
|
||||
selector.replace(labelRegexp, match => {
|
||||
const delimiterIndex = match.indexOf('=');
|
||||
const key = match.slice(0, delimiterIndex);
|
||||
const value = match.slice(delimiterIndex + 1, match.length);
|
||||
labels[key] = value;
|
||||
selector.replace(labelRegexp, (_, key, operator, value) => {
|
||||
labels[key] = { value, operator };
|
||||
return '';
|
||||
});
|
||||
|
||||
@ -78,12 +75,12 @@ export function parseSelector(query: string, cursorOffset = 1): { labelKeys: any
|
||||
const metricPrefix = query.slice(0, prefixOpen);
|
||||
const metricMatch = metricPrefix.match(/[A-Za-z:][\w:]*$/);
|
||||
if (metricMatch) {
|
||||
labels['__name__'] = `"${metricMatch[0]}"`;
|
||||
labels['__name__'] = { value: `"${metricMatch[0]}"`, operator: '=' };
|
||||
}
|
||||
|
||||
// Build sorted selector
|
||||
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('');
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user