Commit 1f1d7d7f by Russ Committed by GitHub

Explore: Keep typeahead suggestions for exact label matches in Loki q… (#27201)

* Explore: Keep typeahead suggestions for exact label matches in Loki query editor

* Simplify some typing

* Explore: filter selected loki label option from suggestions

Co-authored-by: kay delaney <kay@grafana.com>
parent 1ec8eb3f
...@@ -91,7 +91,15 @@ describe('Language completion provider', () => { ...@@ -91,7 +91,15 @@ describe('Language completion provider', () => {
const input = createTypeaheadInput('{}', '', '', 1); const input = createTypeaheadInput('{}', '', '', 1);
const result = await provider.provideCompletionItems(input, { absoluteRange: rangeMock }); const result = await provider.provideCompletionItems(input, { absoluteRange: rangeMock });
expect(result.context).toBe('context-labels'); expect(result.context).toBe('context-labels');
expect(result.suggestions).toEqual([{ items: [{ label: 'label1' }, { label: 'label2' }], label: 'Labels' }]); expect(result.suggestions).toEqual([
{
items: [
{ label: 'label1', filterText: '"label1"' },
{ label: 'label2', filterText: '"label2"' },
],
label: 'Labels',
},
]);
}); });
it('returns all label suggestions on selector when starting to type', async () => { it('returns all label suggestions on selector when starting to type', async () => {
...@@ -100,7 +108,15 @@ describe('Language completion provider', () => { ...@@ -100,7 +108,15 @@ describe('Language completion provider', () => {
const input = createTypeaheadInput('{l}', '', '', 2); const input = createTypeaheadInput('{l}', '', '', 2);
const result = await provider.provideCompletionItems(input, { absoluteRange: rangeMock }); const result = await provider.provideCompletionItems(input, { absoluteRange: rangeMock });
expect(result.context).toBe('context-labels'); expect(result.context).toBe('context-labels');
expect(result.suggestions).toEqual([{ items: [{ label: 'label1' }, { label: 'label2' }], label: 'Labels' }]); expect(result.suggestions).toEqual([
{
items: [
{ label: 'label1', filterText: '"label1"' },
{ label: 'label2', filterText: '"label2"' },
],
label: 'Labels',
},
]);
}); });
}); });
...@@ -140,7 +156,13 @@ describe('Language completion provider', () => { ...@@ -140,7 +156,13 @@ describe('Language completion provider', () => {
result = await provider.provideCompletionItems(input, { absoluteRange: rangeMock }); result = await provider.provideCompletionItems(input, { absoluteRange: rangeMock });
expect(result.context).toBe('context-label-values'); expect(result.context).toBe('context-label-values');
expect(result.suggestions).toEqual([ expect(result.suggestions).toEqual([
{ items: [{ label: 'label1_val1' }, { label: 'label1_val2' }], label: 'Label values for "label1"' }, {
items: [
{ label: 'label1_val1', filterText: '"label1_val1"' },
{ label: 'label1_val2', filterText: '"label1_val2"' },
],
label: 'Label values for "label1"',
},
]); ]);
}); });
}); });
......
...@@ -28,7 +28,8 @@ const HISTORY_COUNT_CUTOFF = 1000 * 60 * 60 * 24; // 24h ...@@ -28,7 +28,8 @@ const HISTORY_COUNT_CUTOFF = 1000 * 60 * 60 * 24; // 24h
const NS_IN_MS = 1000000; const NS_IN_MS = 1000000;
export const LABEL_REFRESH_INTERVAL = 1000 * 30; // 30sec export const LABEL_REFRESH_INTERVAL = 1000 * 30; // 30sec
const wrapLabel = (label: string) => ({ label }); const wrapLabel = (label: string) => ({ label, filterText: `\"${label}\"` });
export const rangeToParams = (range: AbsoluteTimeRange) => ({ start: range.from * NS_IN_MS, end: range.to * NS_IN_MS }); export const rangeToParams = (range: AbsoluteTimeRange) => ({ start: range.from * NS_IN_MS, end: range.to * NS_IN_MS });
export type LokiHistoryItem = HistoryItem<LokiQuery>; export type LokiHistoryItem = HistoryItem<LokiQuery>;
...@@ -188,14 +189,14 @@ export default class LokiLanguageProvider extends LanguageProvider { ...@@ -188,14 +189,14 @@ export default class LokiLanguageProvider extends LanguageProvider {
const history = context?.history; const history = context?.history;
const suggestions = []; const suggestions = [];
if (history && history.length) { if (history?.length) {
const historyItems = _.chain(history) const historyItems = _.chain(history)
.map(h => h.query.expr) .map(h => h.query.expr)
.filter() .filter()
.uniq() .uniq()
.take(HISTORY_ITEM_COUNT) .take(HISTORY_ITEM_COUNT)
.map(wrapLabel) .map(wrapLabel)
.map((item: CompletionItem) => addHistoryMetadata(item, history)) .map(item => addHistoryMetadata(item, history))
.value(); .value();
suggestions.push({ suggestions.push({
...@@ -287,13 +288,13 @@ export default class LokiLanguageProvider extends LanguageProvider { ...@@ -287,13 +288,13 @@ export default class LokiLanguageProvider extends LanguageProvider {
context = 'context-label-values'; context = 'context-label-values';
suggestions.push({ suggestions.push({
label: `Label values for "${labelKey}"`, label: `Label values for "${labelKey}"`,
items: labelValues[labelKey].map(wrapLabel), // Filter to prevent previously selected values from being repeatedly suggested
items: labelValues[labelKey].map(wrapLabel).filter(({ filterText }) => filterText !== text),
}); });
} }
} else { } else {
// Label keys // Label keys
const labelKeys = labelValues ? Object.keys(labelValues) : DEFAULT_KEYS; const labelKeys = labelValues ? Object.keys(labelValues) : DEFAULT_KEYS;
if (labelKeys) { if (labelKeys) {
const possibleKeys = _.difference(labelKeys, existingKeys); const possibleKeys = _.difference(labelKeys, existingKeys);
if (possibleKeys.length) { if (possibleKeys.length) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment