From dc718a7d9dc581b595c93040a895096ff925e443 Mon Sep 17 00:00:00 2001 From: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com> Date: Tue, 20 Feb 2024 10:07:42 +0100 Subject: [PATCH] Loki: Pass time range variable in variable editor (#82900) * Loki: Pass time range variable in variable editor * Remove not needed type * Update * Add tests, not re-run if type does not change * Add range as dependency --- .betterer.results.json | 6 - .../components/VariableQueryEditor.test.tsx | 129 ++++++++++++++++++ .../loki/components/VariableQueryEditor.tsx | 11 +- 3 files changed, 136 insertions(+), 10 deletions(-) diff --git a/.betterer.results.json b/.betterer.results.json index 4dd7405a36d..abeb9276cfb 100644 --- a/.betterer.results.json +++ b/.betterer.results.json @@ -1028,12 +1028,6 @@ "count": 5 } ], - "/packages/grafana-ui/src/components/Splitter/Splitter.tsx": [ - { - "message": "Do not use any type assertions.", - "count": 1 - } - ], "/packages/grafana-ui/src/components/StatsPicker/StatsPicker.story.tsx": [ { "message": "Unexpected any. Specify a different type.", diff --git a/public/app/plugins/datasource/loki/components/VariableQueryEditor.test.tsx b/public/app/plugins/datasource/loki/components/VariableQueryEditor.test.tsx index 48613c882e1..758dfc7055c 100644 --- a/public/app/plugins/datasource/loki/components/VariableQueryEditor.test.tsx +++ b/public/app/plugins/datasource/loki/components/VariableQueryEditor.test.tsx @@ -3,6 +3,7 @@ import userEvent from '@testing-library/user-event'; import React from 'react'; import { select } from 'react-select-event'; +import { TimeRange, dateTime } from '@grafana/data'; import { TemplateSrv } from '@grafana/runtime'; import { createLokiDatasource } from '../__mocks__/datasource'; @@ -133,4 +134,132 @@ describe('LokiVariableQueryEditor', () => { await select(screen.getByLabelText('Label'), 'luna', { container: document.body }); await screen.findByText('luna'); }); + + test('Calls language provider fetchLabels with the time range received in props', async () => { + const now = dateTime('2023-09-16T21:26:00Z'); + const range: TimeRange = { + from: dateTime(now).subtract(2, 'days'), + to: now, + raw: { + from: 'now-2d', + to: 'now', + }, + }; + props.range = range; + props.query = { + refId: 'test', + type: LokiVariableQueryType.LabelValues, + label: 'luna', + }; + + render(); + await waitFor(() => + expect(props.datasource.languageProvider.fetchLabels).toHaveBeenCalledWith({ timeRange: range }) + ); + }); + + test('does not re-run fetch labels when type does not change', async () => { + const now = dateTime('2023-09-16T21:26:00Z'); + const range: TimeRange = { + from: dateTime(now).subtract(2, 'days'), + to: now, + raw: { + from: 'now-2d', + to: 'now', + }, + }; + props.range = range; + props.query = { + refId: 'test', + type: LokiVariableQueryType.LabelValues, + }; + + props.datasource.languageProvider.fetchLabels = jest.fn().mockResolvedValue([]); + const { rerender } = render(); + rerender( + + ); + + await waitFor(() => { + expect(props.datasource.languageProvider.fetchLabels).toHaveBeenCalledTimes(1); + }); + }); + + test('runs fetch labels when type changes to from LabelNames to LabelValues', async () => { + const now = dateTime('2023-09-16T21:26:00Z'); + const range: TimeRange = { + from: dateTime(now).subtract(2, 'days'), + to: now, + raw: { + from: 'now-2d', + to: 'now', + }, + }; + props.range = range; + props.query = { + refId: 'test', + type: LokiVariableQueryType.LabelNames, + }; + + props.datasource.languageProvider.fetchLabels = jest.fn().mockResolvedValue([]); + const { rerender } = render(); + rerender( + + ); + + await waitFor(() => { + expect(props.datasource.languageProvider.fetchLabels).toHaveBeenCalledTimes(1); + }); + }); + + test('runs fetch labels when type changes to LabelValues', async () => { + const now = dateTime('2023-09-16T21:26:00Z'); + const range: TimeRange = { + from: dateTime(now).subtract(2, 'days'), + to: now, + raw: { + from: 'now-2d', + to: 'now', + }, + }; + props.range = range; + props.query = { + refId: 'test', + type: LokiVariableQueryType.LabelNames, + }; + + props.datasource.languageProvider.fetchLabels = jest.fn().mockResolvedValue([]); + // Starting with LabelNames + const { rerender } = render(); + + // Changing to LabelValues, should run fetchLabels + rerender( + + ); + await waitFor(() => { + expect(props.datasource.languageProvider.fetchLabels).toHaveBeenCalledTimes(1); + }); + + // Keeping the type of LabelValues, should not run additional fetchLabels + rerender( + + ); + await waitFor(() => { + expect(props.datasource.languageProvider.fetchLabels).toHaveBeenCalledTimes(1); + }); + + // Changing to LabelNames, should not run additional fetchLabels + rerender(); + await waitFor(() => { + expect(props.datasource.languageProvider.fetchLabels).toHaveBeenCalledTimes(1); + }); + + // Changing to LabelValues, should run additional fetchLabels + rerender( + + ); + await waitFor(() => { + expect(props.datasource.languageProvider.fetchLabels).toHaveBeenCalledTimes(2); + }); + }); }); diff --git a/public/app/plugins/datasource/loki/components/VariableQueryEditor.tsx b/public/app/plugins/datasource/loki/components/VariableQueryEditor.tsx index 749b564b80a..63246b73657 100644 --- a/public/app/plugins/datasource/loki/components/VariableQueryEditor.tsx +++ b/public/app/plugins/datasource/loki/components/VariableQueryEditor.tsx @@ -1,4 +1,5 @@ import React, { FormEvent, useState, useEffect } from 'react'; +import { usePrevious } from 'react-use'; import { QueryEditorProps, SelectableValue } from '@grafana/data'; import { InlineField, InlineFieldRow, Input, Select } from '@grafana/ui'; @@ -16,11 +17,12 @@ export type Props = QueryEditorProps { +export const LokiVariableQueryEditor = ({ onChange, query, datasource, range }: Props) => { const [type, setType] = useState(undefined); const [label, setLabel] = useState(''); const [labelOptions, setLabelOptions] = useState>>([]); const [stream, setStream] = useState(''); + const previousType = usePrevious(type); useEffect(() => { if (!query) { @@ -34,14 +36,15 @@ export const LokiVariableQueryEditor = ({ onChange, query, datasource }: Props) }, [query]); useEffect(() => { - if (type !== QueryType.LabelValues) { + // Fetch label names when the query type is LabelValues, and the previous type was not the same + if (type !== QueryType.LabelValues || previousType === type) { return; } - datasource.languageProvider.fetchLabels().then((labelNames: string[]) => { + datasource.languageProvider.fetchLabels({ timeRange: range }).then((labelNames) => { setLabelOptions(labelNames.map((labelName) => ({ label: labelName, value: labelName }))); }); - }, [datasource, type]); + }, [datasource, type, range, previousType]); const onQueryTypeChange = (newType: SelectableValue) => { setType(newType.value);