diff --git a/web/ui/react-app/src/pages/graph/Panel.test.tsx b/web/ui/react-app/src/pages/graph/Panel.test.tsx index e3d2bfb115..2d702b6fbf 100644 --- a/web/ui/react-app/src/pages/graph/Panel.test.tsx +++ b/web/ui/react-app/src/pages/graph/Panel.test.tsx @@ -151,9 +151,10 @@ describe('Panel', () => { //change query without executing panel.setProps({ options: { ...defaultProps.options, expr: newExpr } }); expect(executeQuerySpy).toHaveBeenCalledTimes(0); + const debounceExecuteQuerySpy = jest.spyOn(instance, 'debounceExecuteQuery'); //execute query implicitly with time change panel.setProps({ options: { ...defaultProps.options, expr: newExpr, endTime: 1575744840 } }); - expect(executeQuerySpy).toHaveBeenCalledTimes(1); + expect(debounceExecuteQuerySpy).toHaveBeenCalledTimes(1); }); }); }); diff --git a/web/ui/react-app/src/pages/graph/Panel.tsx b/web/ui/react-app/src/pages/graph/Panel.tsx index a7de9f3421..1dca06ad04 100644 --- a/web/ui/react-app/src/pages/graph/Panel.tsx +++ b/web/ui/react-app/src/pages/graph/Panel.tsx @@ -13,6 +13,7 @@ import TimeInput from './TimeInput'; import QueryStatsView, { QueryStats } from './QueryStatsView'; import { QueryParams, ExemplarData } from '../../types/types'; import { API_PATH } from '../../constants/constants'; +import { debounce } from '../../utils'; interface PanelProps { options: PanelOptions; @@ -69,6 +70,7 @@ export const PanelDefaultOptions: PanelOptions = { class Panel extends Component { private abortInFlightFetch: (() => void) | null = null; + private debounceExecuteQuery: () => void; constructor(props: PanelProps) { super(props); @@ -83,17 +85,19 @@ class Panel extends Component { stats: null, exprInputValue: props.options.expr, }; + + this.debounceExecuteQuery = debounce(this.executeQuery.bind(this), 250); } componentDidUpdate({ options: prevOpts }: PanelProps): void { const { endTime, range, resolution, showExemplars, type } = this.props.options; - if ( - prevOpts.endTime !== endTime || - prevOpts.range !== range || - prevOpts.resolution !== resolution || - prevOpts.type !== type || - showExemplars !== prevOpts.showExemplars - ) { + + if (prevOpts.endTime !== endTime || prevOpts.range !== range) { + this.debounceExecuteQuery(); + return; + } + + if (prevOpts.resolution !== resolution || prevOpts.type !== type || showExemplars !== prevOpts.showExemplars) { this.executeQuery(); } } diff --git a/web/ui/react-app/src/utils/index.ts b/web/ui/react-app/src/utils/index.ts index b01ce840ec..ca714970f5 100644 --- a/web/ui/react-app/src/utils/index.ts +++ b/web/ui/react-app/src/utils/index.ts @@ -269,3 +269,16 @@ export const parsePrometheusFloat = (value: string): string | number => { return Number(value); } }; + +export function debounce( + func: (...args: Params) => unknown, + timeout: number +): (...args: Params) => void { + let timer: NodeJS.Timeout; + return (...args: Params) => { + clearTimeout(timer); + timer = setTimeout(() => { + func(...args); + }, timeout); + }; +}