diff --git a/public/app/plugins/datasource/loki/components/LokiQueryEditor.test.tsx b/public/app/plugins/datasource/loki/components/LokiQueryEditor.test.tsx new file mode 100644 index 00000000000..f117ec6f505 --- /dev/null +++ b/public/app/plugins/datasource/loki/components/LokiQueryEditor.test.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import { toUtc } from '@grafana/data'; + +import { LokiQueryEditor } from './LokiQueryEditor'; +import { LokiDatasource } from '../datasource'; +import { LokiQuery } from '../types'; + +const createMockRequestRange = (from: string, to: string) => { + return { + request: { + range: { + from: toUtc(from, 'YYYY-MM-DD'), + to: toUtc(to, 'YYYY-MM-DD'), + }, + }, + }; +}; + +const setup = (propOverrides?: object) => { + const datasourceMock: unknown = {}; + const datasource: LokiDatasource = datasourceMock as LokiDatasource; + const onRunQuery = jest.fn(); + const onChange = jest.fn(); + + const query: LokiQuery = { + expr: '', + refId: 'A', + legendFormat: 'My Legend', + }; + + const data = createMockRequestRange('2020-01-01', '2020-01-02'); + + const props: any = { + datasource, + onChange, + onRunQuery, + query, + data, + }; + + Object.assign(props, propOverrides); + + const wrapper = shallow(); + const instance = wrapper.instance() as LokiQueryEditor; + + return { + instance, + wrapper, + }; +}; + +describe('Render LokiQueryEditor with legend', () => { + it('should render', () => { + const { wrapper } = setup(); + expect(wrapper).toMatchSnapshot(); + }); + + it('should update absolute timerange', () => { + const { wrapper } = setup(); + wrapper.setProps({ + data: createMockRequestRange('2019-01-01', '2020-01-02'), + }); + expect(wrapper).toMatchSnapshot(); + }); +}); diff --git a/public/app/plugins/datasource/loki/components/LokiQueryEditor.tsx b/public/app/plugins/datasource/loki/components/LokiQueryEditor.tsx index b8d47578850..7782269f853 100644 --- a/public/app/plugins/datasource/loki/components/LokiQueryEditor.tsx +++ b/public/app/plugins/datasource/loki/components/LokiQueryEditor.tsx @@ -1,45 +1,105 @@ // Libraries -import React, { memo } from 'react'; +import React, { PureComponent } from 'react'; // Types -import { AbsoluteTimeRange, QueryEditorProps } from '@grafana/data'; +import { AbsoluteTimeRange, QueryEditorProps, PanelData } from '@grafana/data'; +import { InlineFormLabel } from '@grafana/ui'; import { LokiDatasource } from '../datasource'; import { LokiQuery } from '../types'; import { LokiQueryField } from './LokiQueryField'; type Props = QueryEditorProps; -export const LokiQueryEditor = memo(function LokiQueryEditor(props: Props) { - const { query, data, datasource, onChange, onRunQuery } = props; +interface State { + legendFormat: string; +} - let absolute: AbsoluteTimeRange; +export class LokiQueryEditor extends PureComponent { + // Query target to be modified and used for queries + query: LokiQuery; - if (data && data.request) { - const { range } = data.request; - absolute = { - from: range.from.valueOf(), - to: range.to.valueOf(), - }; - } else { - absolute = { - from: Date.now() - 10000, - to: Date.now(), + constructor(props: Props) { + super(props); + // Use default query to prevent undefined input values + const defaultQuery: Partial = { expr: '', legendFormat: '' }; + const query = Object.assign({}, defaultQuery, props.query); + this.query = query; + // Query target properties that are fully controlled inputs + this.state = { + // Fully controlled text inputs + legendFormat: query.legendFormat, }; } - return ( -
- -
- ); -}); + calcAbsoluteRange = (data: PanelData): AbsoluteTimeRange => { + if (data && data.request) { + const { range } = data.request; + return { + from: range.from.valueOf(), + to: range.to.valueOf(), + }; + } + + return { + from: Date.now() - 10000, + to: Date.now(), + }; + }; + + onFieldChange = (query: LokiQuery, override?: any) => { + this.query.expr = query.expr; + }; + + onLegendChange = (e: React.SyntheticEvent) => { + const legendFormat = e.currentTarget.value; + this.query.legendFormat = legendFormat; + this.setState({ legendFormat }); + }; + + onRunQuery = () => { + const { query } = this; + this.props.onChange(query); + this.props.onRunQuery(); + }; + + render() { + const { datasource, query, data } = this.props; + const { legendFormat } = this.state; + + return ( +
+ + +
+
+ + Legend + + +
+
+
+ ); + } +} export default LokiQueryEditor; diff --git a/public/app/plugins/datasource/loki/components/__snapshots__/LokiQueryEditor.test.tsx.snap b/public/app/plugins/datasource/loki/components/__snapshots__/LokiQueryEditor.test.tsx.snap new file mode 100644 index 00000000000..d7d39fcb240 --- /dev/null +++ b/public/app/plugins/datasource/loki/components/__snapshots__/LokiQueryEditor.test.tsx.snap @@ -0,0 +1,115 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Render LokiQueryEditor with legend should render 1`] = ` +
+ +
+
+ + Legend + + +
+
+
+`; + +exports[`Render LokiQueryEditor with legend should update absolute timerange 1`] = ` +
+ +
+
+ + Legend + + +
+
+
+`; diff --git a/public/app/plugins/datasource/loki/result_transformer.ts b/public/app/plugins/datasource/loki/result_transformer.ts index 4ae03bd1d64..8c2ba7409da 100644 --- a/public/app/plugins/datasource/loki/result_transformer.ts +++ b/public/app/plugins/datasource/loki/result_transformer.ts @@ -143,8 +143,10 @@ function createUid(ts: string, labelsString: string, line: string): string { } function lokiMatrixToTimeSeries(matrixResult: LokiMatrixResult, options: TransformerOptions): TimeSeries { + const name = createMetricLabel(matrixResult.metric, options); return { - target: createMetricLabel(matrixResult.metric, options), + target: name, + title: name, datapoints: lokiPointsToTimeseriesPoints(matrixResult.values, options), tags: matrixResult.metric, meta: options.meta,