From bb8a70342850bc86cd5e9633fa9f4164157f38da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Bedi?= Date: Tue, 16 Mar 2021 13:58:51 +0100 Subject: [PATCH] Exemplars: always query exemplars (#31673) * Exemplars: always query exemplars * Update exemplar button to be an eye * Add tooltip to eye button --- .../components/PromExemplarField.tsx | 67 ++++++++++++++++--- .../components/PromExploreExtraField.test.tsx | 3 + .../components/PromExploreExtraField.tsx | 6 +- .../components/PromExploreQueryEditor.tsx | 9 ++- .../prometheus/components/PromQueryEditor.tsx | 4 +- .../PromExploreQueryEditor.test.tsx.snap | 7 ++ .../PromQueryEditor.test.tsx.snap | 10 +++ .../datasource/prometheus/datasource.ts | 25 ++++++- 8 files changed, 113 insertions(+), 18 deletions(-) diff --git a/public/app/plugins/datasource/prometheus/components/PromExemplarField.tsx b/public/app/plugins/datasource/prometheus/components/PromExemplarField.tsx index 0b21afcbd50..0b3e5a34a73 100644 --- a/public/app/plugins/datasource/prometheus/components/PromExemplarField.tsx +++ b/public/app/plugins/datasource/prometheus/components/PromExemplarField.tsx @@ -1,21 +1,68 @@ -import { InlineField, InlineSwitch } from '@grafana/ui'; -import React from 'react'; +import { GrafanaTheme } from '@grafana/data'; +import { FetchError } from '@grafana/runtime'; +import { IconButton, InlineLabel, Tooltip, useStyles } from '@grafana/ui'; +import { css, cx } from 'emotion'; +import React, { useEffect, useState } from 'react'; +import { PrometheusDatasource } from '../datasource'; import { PromQuery } from '../types'; interface Props { query: PromQuery; onChange: (value: PromQuery) => void; + datasource: PrometheusDatasource; } -const onExemplarsChange = ({ query, onChange }: Props) => (e: React.ChangeEvent) => { - const exemplar = e.target.checked; - onChange({ ...query, exemplar }); -}; - export function PromExemplarField(props: Props) { + const [error, setError] = useState(); + const styles = useStyles(getStyles); + + useEffect(() => { + const subscription = props.datasource.exemplarErrors.subscribe((err) => { + setError(err); + }); + return () => { + subscription.unsubscribe(); + }; + }, [props]); + + const iconButtonStyles = cx( + { + [styles.activeIcon]: !!props.query.exemplar, + }, + styles.eyeIcon + ); + return ( - - - + + +
+ Exemplars + { + props.onChange({ ...props.query, exemplar: !props.query.exemplar }); + }} + /> +
+
+
); } + +function getStyles(theme: GrafanaTheme) { + return { + eyeIcon: css` + margin-left: ${theme.spacing.md}; + `, + activeIcon: css` + color: ${theme.palette.blue95}; + `, + iconWrapper: css` + display: flex; + align-items: center; + `, + }; +} diff --git a/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.test.tsx b/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.test.tsx index e00df58884a..992b7090b1f 100644 --- a/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.test.tsx +++ b/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.test.tsx @@ -1,11 +1,13 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import { PromExploreExtraFieldProps, PromExploreExtraField } from './PromExploreExtraField'; +import { Observable } from 'rxjs'; const setup = (propOverrides?: PromExploreExtraFieldProps) => { const queryType = 'range'; const stepValue = '1'; const query = { exemplar: false }; + const datasource = { exemplarErrors: new Observable() }; const onStepChange = jest.fn(); const onQueryTypeChange = jest.fn(); const onKeyDownFunc = jest.fn(); @@ -17,6 +19,7 @@ const setup = (propOverrides?: PromExploreExtraFieldProps) => { onStepChange, onQueryTypeChange, onKeyDownFunc, + datasource, }; Object.assign(props, propOverrides); diff --git a/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.tsx b/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.tsx index 71f623c4fbb..e63a072c9b9 100644 --- a/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.tsx +++ b/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.tsx @@ -6,6 +6,7 @@ import { css, cx } from 'emotion'; import { InlineFormLabel, RadioButtonGroup } from '@grafana/ui'; import { PromQuery } from '../types'; import { PromExemplarField } from './PromExemplarField'; +import { PrometheusDatasource } from '../datasource'; export interface PromExploreExtraFieldProps { queryType: string; @@ -15,10 +16,11 @@ export interface PromExploreExtraFieldProps { onKeyDownFunc: (e: React.KeyboardEvent) => void; onQueryTypeChange: (value: string) => void; onChange: (value: PromQuery) => void; + datasource: PrometheusDatasource; } export const PromExploreExtraField: React.FC = memo( - ({ queryType, stepValue, query, onChange, onStepChange, onQueryTypeChange, onKeyDownFunc }) => { + ({ queryType, stepValue, query, onChange, onStepChange, onQueryTypeChange, onKeyDownFunc, datasource }) => { const rangeOptions = [ { value: 'range', label: 'Range', description: 'Run query over a range of time.' }, { @@ -75,7 +77,7 @@ export const PromExploreExtraField: React.FC = memo( /> - + ); } diff --git a/public/app/plugins/datasource/prometheus/components/PromExploreQueryEditor.tsx b/public/app/plugins/datasource/prometheus/components/PromExploreQueryEditor.tsx index 49de300022c..d3aa7e0005b 100644 --- a/public/app/plugins/datasource/prometheus/components/PromExploreQueryEditor.tsx +++ b/public/app/plugins/datasource/prometheus/components/PromExploreQueryEditor.tsx @@ -1,4 +1,4 @@ -import React, { memo, FC } from 'react'; +import React, { memo, FC, useEffect } from 'react'; // Types import { ExploreQueryFieldProps } from '@grafana/data'; @@ -14,6 +14,12 @@ export type Props = ExploreQueryFieldProps = (props: Props) => { const { range, query, data, datasource, history, onChange, onRunQuery } = props; + useEffect(() => { + if (query.exemplar === undefined) { + onChange({ ...query, exemplar: true }); + } + }, [query]); + function onChangeQueryStep(value: string) { const { query, onChange } = props; const nextQuery = { ...query, interval: value }; @@ -65,6 +71,7 @@ export const PromExploreQueryEditor: FC = (props: Props) => { onKeyDownFunc={onReturnKeyDown} query={query} onChange={onChange} + datasource={datasource} /> } /> diff --git a/public/app/plugins/datasource/prometheus/components/PromQueryEditor.tsx b/public/app/plugins/datasource/prometheus/components/PromQueryEditor.tsx index 3876687ac74..6bfb30523de 100644 --- a/public/app/plugins/datasource/prometheus/components/PromQueryEditor.tsx +++ b/public/app/plugins/datasource/prometheus/components/PromQueryEditor.tsx @@ -41,7 +41,7 @@ export class PromQueryEditor extends PureComponent { constructor(props: Props) { super(props); // Use default query to prevent undefined input values - const defaultQuery: Partial = { expr: '', legendFormat: '', interval: '' }; + const defaultQuery: Partial = { expr: '', legendFormat: '', interval: '', exemplar: true }; const query = Object.assign({}, defaultQuery, props.query); this.query = query; // Query target properties that are fully controlled inputs @@ -186,7 +186,7 @@ export class PromQueryEditor extends PureComponent { - + ); diff --git a/public/app/plugins/datasource/prometheus/components/__snapshots__/PromExploreQueryEditor.test.tsx.snap b/public/app/plugins/datasource/prometheus/components/__snapshots__/PromExploreQueryEditor.test.tsx.snap index 7baccbbc1a7..24118aab039 100644 --- a/public/app/plugins/datasource/prometheus/components/__snapshots__/PromExploreQueryEditor.test.tsx.snap +++ b/public/app/plugins/datasource/prometheus/components/__snapshots__/PromExploreQueryEditor.test.tsx.snap @@ -4,6 +4,13 @@ exports[`PromExploreQueryEditor should render component 1`] = ` exemplarTraceIdDestinations: ExemplarTraceIdDestination[] | undefined; lookupsDisabled: boolean; customQueryParameters: any; + exemplarErrors: Subject = new Subject(); constructor( instanceSettings: DataSourceInstanceSettings, @@ -308,7 +309,16 @@ export class PrometheusDatasource extends DataSourceApi } if (query.exemplar) { - return this.getExemplars(query).pipe(filterAndMapResponse); + return this.getExemplars(query).pipe( + catchError((err: FetchError) => { + this.exemplarErrors.next(err); + return of({ + data: [], + state: LoadingState.Done, + }); + }), + filterAndMapResponse + ); } return this.performTimeSeriesQuery(query, query.start, query.end).pipe(filterAndMapResponse); @@ -346,7 +356,16 @@ export class PrometheusDatasource extends DataSourceApi } if (query.exemplar) { - return this.getExemplars(query).pipe(filterAndMapResponse); + return this.getExemplars(query).pipe( + catchError((err: FetchError) => { + this.exemplarErrors.next(err); + return of({ + data: [], + state: LoadingState.Done, + }); + }), + filterAndMapResponse + ); } return this.performTimeSeriesQuery(query, query.start, query.end).pipe(filterAndMapResponse);