From ff39df74d3e63a17da5188a9763791b5a7da79a0 Mon Sep 17 00:00:00 2001 From: Yury Molodov Date: Fri, 12 May 2023 13:55:47 +0200 Subject: [PATCH] vmui: add notification for non-matching queries (#4301) vmui: add notification for non-matching queries (#4211) https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4211 --- app/vmui/packages/vmui/src/api/types.ts | 5 ++++ .../Configurators/QueryEditor/QueryEditor.tsx | 23 +++++++++++++++++++ .../Configurators/QueryEditor/style.scss | 18 +++++++++++++++ .../packages/vmui/src/hooks/useFetchQuery.ts | 14 ++++++++--- .../QueryConfigurator/QueryConfigurator.tsx | 4 ++++ .../vmui/src/pages/CustomPanel/index.tsx | 2 ++ docs/CHANGELOG.md | 1 + 7 files changed, 64 insertions(+), 3 deletions(-) diff --git a/app/vmui/packages/vmui/src/api/types.ts b/app/vmui/packages/vmui/src/api/types.ts index 17d1c84a9..204dc2f7d 100644 --- a/app/vmui/packages/vmui/src/api/types.ts +++ b/app/vmui/packages/vmui/src/api/types.ts @@ -20,3 +20,8 @@ export interface TracingData { duration_msec: number; children: TracingData[]; } + +export interface QueryStats { + seriesFetched?: string; + resultLength?: number; +} diff --git a/app/vmui/packages/vmui/src/components/Configurators/QueryEditor/QueryEditor.tsx b/app/vmui/packages/vmui/src/components/Configurators/QueryEditor/QueryEditor.tsx index ed6c36fe7..cd77cc059 100644 --- a/app/vmui/packages/vmui/src/components/Configurators/QueryEditor/QueryEditor.tsx +++ b/app/vmui/packages/vmui/src/components/Configurators/QueryEditor/QueryEditor.tsx @@ -4,6 +4,9 @@ import { ErrorTypes } from "../../../types"; import TextField from "../../Main/TextField/TextField"; import Autocomplete from "../../Main/Autocomplete/Autocomplete"; import "./style.scss"; +import { QueryStats } from "../../../api/types"; +import Tooltip from "../../Main/Tooltip/Tooltip"; +import { WarningIcon } from "../../Main/Icons"; export interface QueryEditorProps { onChange: (query: string) => void; @@ -14,6 +17,7 @@ export interface QueryEditorProps { oneLiner?: boolean; autocomplete: boolean; error?: ErrorTypes | string; + stats?: QueryStats; options: string[]; label: string; disabled?: boolean @@ -27,6 +31,7 @@ const QueryEditor: FC = ({ onArrowDown, autocomplete, error, + stats, options, label, disabled = false @@ -34,6 +39,7 @@ const QueryEditor: FC = ({ const [openAutocomplete, setOpenAutocomplete] = useState(false); const autocompleteAnchorEl = useRef(null); + const showSeriesFetchedWarning = stats?.seriesFetched === "0" && !stats.resultLength; const handleSelect = (val: string) => { onChange(val); @@ -90,6 +96,23 @@ const QueryEditor: FC = ({ onOpenAutocomplete={setOpenAutocomplete} /> )} + {showSeriesFetchedWarning && ( +
+ + {`No match! + This query hasn't selected any time series from database. + Either the requested metrics are missing in the database, + or there is a typo in series selector.`} + + )} + > + + +
+ )} ; }; diff --git a/app/vmui/packages/vmui/src/components/Configurators/QueryEditor/style.scss b/app/vmui/packages/vmui/src/components/Configurators/QueryEditor/style.scss index 24f57d152..3381222c1 100644 --- a/app/vmui/packages/vmui/src/components/Configurators/QueryEditor/style.scss +++ b/app/vmui/packages/vmui/src/components/Configurators/QueryEditor/style.scss @@ -1,9 +1,27 @@ @use "src/styles/variables" as *; .vm-query-editor { + position: relative; &-autocomplete { max-height: 300px; overflow: auto; } + + &-warning { + position: absolute; + top: 50%; + right: $padding-global; + transform: translateY(-50%); + display: grid; + align-items: center; + justify-content: center; + width: 18px; + height: 18px; + color: $color-warning; + + &__tooltip { + white-space: pre-line; + } + } } diff --git a/app/vmui/packages/vmui/src/hooks/useFetchQuery.ts b/app/vmui/packages/vmui/src/hooks/useFetchQuery.ts index 5a1981fb3..53a333f5a 100644 --- a/app/vmui/packages/vmui/src/hooks/useFetchQuery.ts +++ b/app/vmui/packages/vmui/src/hooks/useFetchQuery.ts @@ -1,7 +1,7 @@ import { useCallback, useEffect, useMemo, useState } from "preact/compat"; import { getQueryRangeUrl, getQueryUrl } from "../api/query-range"; import { useAppState } from "../state/common/StateContext"; -import { InstantMetricResult, MetricBase, MetricResult } from "../api/types"; +import { InstantMetricResult, MetricBase, MetricResult, QueryStats } from "../api/types"; import { isValidHttpUrl } from "../utils/url"; import { ErrorTypes, SeriesLimits } from "../types"; import debounce from "lodash.debounce"; @@ -28,9 +28,10 @@ interface FetchQueryReturn { liveData?: InstantMetricResult[], error?: ErrorTypes | string, queryErrors: (ErrorTypes | string)[], + queryStats: QueryStats[], warning?: string, traces?: Trace[], - isHistogram: boolean, + isHistogram: boolean } interface FetchDataParams { @@ -62,6 +63,7 @@ export const useFetchQuery = ({ const [traces, setTraces] = useState(); const [error, setError] = useState(); const [queryErrors, setQueryErrors] = useState<(ErrorTypes | string)[]>([]); + const [queryStats, setQueryStats] = useState([]); const [warning, setWarning] = useState(); const [fetchQueue, setFetchQueue] = useState([]); const [isHistogram, setIsHistogram] = useState(false); @@ -90,6 +92,7 @@ export const useFetchQuery = ({ const isHideQuery = hideQuery?.includes(counter - 1); if (isHideQuery) { setQueryErrors(prev => [...prev, ""]); + setQueryStats(prev => [...prev, {}]); counter++; continue; } @@ -98,6 +101,10 @@ export const useFetchQuery = ({ const resp = await response.json(); if (response.ok) { + setQueryStats(prev => [...prev, { + ...resp?.stats, + resultLength: resp.data.result.length, + }]); setQueryErrors(prev => [...prev, ""]); if (resp.trace) { @@ -139,6 +146,7 @@ export const useFetchQuery = ({ const fetchUrl = useMemo(() => { setError(""); setQueryErrors([]); + setQueryStats([]); const expr = predefinedQuery ?? query; const displayChart = (display || displayType) === "chart"; if (!period) return; @@ -184,5 +192,5 @@ export const useFetchQuery = ({ setFetchQueue(fetchQueue.filter(f => !f.signal.aborted)); }, [fetchQueue]); - return { fetchUrl, isLoading, graphData, liveData, error, queryErrors, warning, traces, isHistogram }; + return { fetchUrl, isLoading, graphData, liveData, error, queryErrors, queryStats, warning, traces, isHistogram }; }; diff --git a/app/vmui/packages/vmui/src/pages/CustomPanel/QueryConfigurator/QueryConfigurator.tsx b/app/vmui/packages/vmui/src/pages/CustomPanel/QueryConfigurator/QueryConfigurator.tsx index 57f16cd63..23e581a22 100644 --- a/app/vmui/packages/vmui/src/pages/CustomPanel/QueryConfigurator/QueryConfigurator.tsx +++ b/app/vmui/packages/vmui/src/pages/CustomPanel/QueryConfigurator/QueryConfigurator.tsx @@ -14,9 +14,11 @@ import classNames from "classnames"; import { MouseEvent as ReactMouseEvent } from "react"; import { arrayEquals } from "../../../utils/array"; import useDeviceDetect from "../../../hooks/useDeviceDetect"; +import { QueryStats } from "../../../api/types"; export interface QueryConfiguratorProps { errors: (ErrorTypes | string)[]; + stats: QueryStats[]; queryOptions: string[] onHideQuery: (queries: number[]) => void onRunQuery: () => void @@ -24,6 +26,7 @@ export interface QueryConfiguratorProps { const QueryConfigurator: FC = ({ errors, + stats, queryOptions, onHideQuery, onRunQuery @@ -142,6 +145,7 @@ const QueryConfigurator: FC = ({ autocomplete={autocomplete} options={queryOptions} error={errors[i]} + stats={stats[i]} onArrowUp={createHandlerArrow(-1, i)} onArrowDown={createHandlerArrow(1, i)} onEnter={handleRunQuery} diff --git a/app/vmui/packages/vmui/src/pages/CustomPanel/index.tsx b/app/vmui/packages/vmui/src/pages/CustomPanel/index.tsx index 2194056d2..dcca30263 100644 --- a/app/vmui/packages/vmui/src/pages/CustomPanel/index.tsx +++ b/app/vmui/packages/vmui/src/pages/CustomPanel/index.tsx @@ -49,6 +49,7 @@ const CustomPanel: FC = () => { graphData, error, queryErrors, + queryStats, warning, traces, isHistogram @@ -115,6 +116,7 @@ const CustomPanel: FC = () => { >