mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Loki: Update labels in log browser when time range changes (#37520)
* Refresh label when time range changes * Refactor solution * Add tests * Update tests comments * Update test * Update public/app/plugins/datasource/loki/components/LokiQueryField.tsx * Update public/app/plugins/datasource/loki/components/LokiQueryField.tsx
This commit is contained in:
parent
224b062cac
commit
7fd94e69c3
@ -11,7 +11,7 @@ import { LokiOptionFields } from './LokiOptionFields';
|
||||
type Props = ExploreQueryFieldProps<LokiDatasource, LokiQuery, LokiOptions>;
|
||||
|
||||
export function LokiExploreQueryEditor(props: Props) {
|
||||
const { query, data, datasource, history, onChange, onRunQuery } = props;
|
||||
const { query, data, datasource, history, onChange, onRunQuery, range } = props;
|
||||
|
||||
return (
|
||||
<LokiQueryField
|
||||
@ -22,6 +22,7 @@ export function LokiExploreQueryEditor(props: Props) {
|
||||
onRunQuery={onRunQuery}
|
||||
history={history}
|
||||
data={data}
|
||||
range={range}
|
||||
ExtraFieldElement={
|
||||
<LokiOptionFields
|
||||
queryType={query.instant ? 'instant' : 'range'}
|
||||
|
@ -0,0 +1,79 @@
|
||||
import React, { ComponentProps } from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { LokiQueryField } from './LokiQueryField';
|
||||
import { dateTime } from '@grafana/data';
|
||||
|
||||
type Props = ComponentProps<typeof LokiQueryField>;
|
||||
|
||||
const defaultProps: Props = {
|
||||
datasource: {
|
||||
languageProvider: {
|
||||
start: () => Promise.resolve(['label1']),
|
||||
fetchLabels: Promise.resolve(['label1']),
|
||||
getSyntax: () => {},
|
||||
getLabelKeys: () => ['label1'],
|
||||
getLabelValues: () => ['value1'],
|
||||
} as any,
|
||||
getInitHints: () => [],
|
||||
} as any,
|
||||
range: {
|
||||
from: dateTime([2021, 1, 11, 12, 0, 0]),
|
||||
to: dateTime([2021, 1, 11, 18, 0, 0]),
|
||||
raw: {
|
||||
from: 'now-1h',
|
||||
to: 'now',
|
||||
},
|
||||
},
|
||||
query: { expr: '', refId: '' },
|
||||
onRunQuery: () => {},
|
||||
onChange: () => {},
|
||||
history: [],
|
||||
};
|
||||
|
||||
describe('LokiQueryField', () => {
|
||||
it('refreshes metrics when time range changes over 1 minute', async () => {
|
||||
const fetchLabelsMock = jest.fn();
|
||||
const props = defaultProps;
|
||||
props.datasource.languageProvider.fetchLabels = fetchLabelsMock;
|
||||
|
||||
const { rerender } = render(<LokiQueryField {...props} />);
|
||||
|
||||
expect(fetchLabelsMock).not.toHaveBeenCalled();
|
||||
|
||||
// 2 minutes difference over the initial time
|
||||
const newRange = {
|
||||
from: dateTime([2021, 1, 11, 12, 2, 0]),
|
||||
to: dateTime([2021, 1, 11, 18, 2, 0]),
|
||||
raw: {
|
||||
from: 'now-1h',
|
||||
to: 'now',
|
||||
},
|
||||
};
|
||||
|
||||
rerender(<LokiQueryField {...props} range={newRange} />);
|
||||
expect(fetchLabelsMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('does not refreshes metrics when time range change by less than 1 minute', async () => {
|
||||
const fetchLabelsMock = jest.fn();
|
||||
const props = defaultProps;
|
||||
props.datasource.languageProvider.fetchLabels = fetchLabelsMock;
|
||||
|
||||
const { rerender } = render(<LokiQueryField {...props} />);
|
||||
|
||||
expect(fetchLabelsMock).not.toHaveBeenCalled();
|
||||
|
||||
// 20 seconds difference over the initial time
|
||||
const newRange = {
|
||||
from: dateTime([2021, 1, 11, 12, 0, 20]),
|
||||
to: dateTime([2021, 1, 11, 18, 0, 20]),
|
||||
raw: {
|
||||
from: 'now-1h',
|
||||
to: 'now',
|
||||
},
|
||||
};
|
||||
|
||||
rerender(<LokiQueryField {...props} range={newRange} />);
|
||||
expect(fetchLabelsMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
@ -1,6 +1,4 @@
|
||||
// Libraries
|
||||
import React, { ReactNode } from 'react';
|
||||
|
||||
import {
|
||||
SlatePrism,
|
||||
TypeaheadOutput,
|
||||
@ -11,17 +9,13 @@ import {
|
||||
DOMUtil,
|
||||
Icon,
|
||||
} from '@grafana/ui';
|
||||
|
||||
// Utils & Services
|
||||
// dom also includes Element polyfills
|
||||
import { Plugin, Node } from 'slate';
|
||||
import { LokiLabelBrowser } from './LokiLabelBrowser';
|
||||
|
||||
// Types
|
||||
import { ExploreQueryFieldProps } from '@grafana/data';
|
||||
import { LokiQuery, LokiOptions } from '../types';
|
||||
import { LanguageMap, languages as prismLanguages } from 'prismjs';
|
||||
import LokiLanguageProvider, { LokiHistoryItem } from '../language_provider';
|
||||
import { shouldRefreshLabels } from '../language_utils';
|
||||
import LokiDatasource from '../datasource';
|
||||
|
||||
function getChooserText(hasSyntax: boolean, hasLogLabels: boolean) {
|
||||
@ -98,6 +92,18 @@ export class LokiQueryField extends React.PureComponent<LokiQueryFieldProps, Lok
|
||||
this.setState({ labelsLoaded: true });
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: LokiQueryFieldProps) {
|
||||
const {
|
||||
range,
|
||||
datasource: { languageProvider },
|
||||
} = this.props;
|
||||
const refreshLabels = shouldRefreshLabels(range, prevProps.range);
|
||||
// We want to refresh labels when range changes (we round up intervals to a minute)
|
||||
if (refreshLabels) {
|
||||
languageProvider.fetchLabels();
|
||||
}
|
||||
}
|
||||
|
||||
onChangeLabelBrowser = (selector: string) => {
|
||||
this.onChangeQuery(selector, true);
|
||||
this.setState({ labelBrowserVisible: false });
|
||||
|
@ -115,5 +115,15 @@ exports[`LokiExploreQueryEditor should render component 1`] = `
|
||||
"refId": "A",
|
||||
}
|
||||
}
|
||||
range={
|
||||
Object {
|
||||
"from": "2020-01-01T00:00:00.000Z",
|
||||
"raw": Object {
|
||||
"from": "2020-01-01T00:00:00.000Z",
|
||||
"to": "2020-01-02T00:00:00.000Z",
|
||||
},
|
||||
"to": "2020-01-02T00:00:00.000Z",
|
||||
}
|
||||
}
|
||||
/>
|
||||
`;
|
||||
|
19
public/app/plugins/datasource/loki/language_utils.ts
Normal file
19
public/app/plugins/datasource/loki/language_utils.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { TimeRange } from '@grafana/data';
|
||||
|
||||
function roundMsToMin(milliseconds: number): number {
|
||||
return roundSecToMin(milliseconds / 1000);
|
||||
}
|
||||
|
||||
function roundSecToMin(seconds: number): number {
|
||||
return Math.floor(seconds / 60);
|
||||
}
|
||||
|
||||
export function shouldRefreshLabels(range?: TimeRange, prevRange?: TimeRange): boolean {
|
||||
if (range && prevRange) {
|
||||
const sameMinuteFrom = roundMsToMin(range.from.valueOf()) === roundMsToMin(prevRange.from.valueOf());
|
||||
const sameMinuteTo = roundMsToMin(range.to.valueOf()) === roundMsToMin(prevRange.to.valueOf());
|
||||
// If both are same, don't need to refresh
|
||||
return !(sameMinuteFrom && sameMinuteTo);
|
||||
}
|
||||
return false;
|
||||
}
|
Loading…
Reference in New Issue
Block a user