mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2025-02-09 15:27:11 +00:00
Co-authored-by: Aliaksandr Valialkin <valyala@victoriametrics.com>
This commit is contained in:
parent
5f2905d120
commit
b08a23c4a5
7 changed files with 45 additions and 39 deletions
|
@ -4,9 +4,8 @@ import { useFetchQueryOptions } from "../../../hooks/useFetchQueryOptions";
|
|||
import { getTextWidth } from "../../../utils/uplot";
|
||||
import { escapeRegexp } from "../../../utils/regexp";
|
||||
import useGetMetricsQL from "../../../hooks/useGetMetricsQL";
|
||||
import { RefreshIcon } from "../../Main/Icons";
|
||||
import { QueryContextType } from "../../../types";
|
||||
import { AUTOCOMPLETE_LIMITS, AUTOCOMPLETE_MIN_SYMBOLS } from "../../../constants/queryAutocomplete";
|
||||
import { AUTOCOMPLETE_LIMITS } from "../../../constants/queryAutocomplete";
|
||||
|
||||
interface QueryEditorAutocompleteProps {
|
||||
value: string;
|
||||
|
@ -26,22 +25,27 @@ const QueryEditorAutocomplete: FC<QueryEditorAutocompleteProps> = ({
|
|||
const [leftOffset, setLeftOffset] = useState(0);
|
||||
const metricsqlFunctions = useGetMetricsQL();
|
||||
|
||||
const exprLastPart = useMemo(() => {
|
||||
const parts = value.split("}");
|
||||
return parts[parts.length - 1];
|
||||
}, [value]);
|
||||
|
||||
const metric = useMemo(() => {
|
||||
const regexp = /\b[^{}(),\s]+(?={|$)/g;
|
||||
const match = value.match(regexp);
|
||||
const match = exprLastPart.match(regexp);
|
||||
return match ? match[0] : "";
|
||||
}, [value]);
|
||||
}, [exprLastPart]);
|
||||
|
||||
const label = useMemo(() => {
|
||||
const regexp = /[a-z_:-][\w\-.:/]*\b(?=\s*(=|!=|=~|!~))/g;
|
||||
const match = value.match(regexp);
|
||||
const match = exprLastPart.match(regexp);
|
||||
return match ? match[match.length - 1] : "";
|
||||
}, [value]);
|
||||
}, [exprLastPart]);
|
||||
|
||||
const context = useMemo(() => {
|
||||
if (!value) return QueryContextType.empty;
|
||||
if (!value || value.endsWith("}")) return QueryContextType.empty;
|
||||
|
||||
const labelRegexp = /\{[^}]*?(\w+)$/gm;
|
||||
const labelRegexp = /\{[^}]*?(\w+)*$/gm;
|
||||
const labelValueRegexp = new RegExp(`(${escapeRegexp(metric)})?{?.+${escapeRegexp(label)}(=|!=|=~|!~)"?([^"]*)$`, "g");
|
||||
|
||||
switch (true) {
|
||||
|
@ -88,6 +92,13 @@ const QueryEditorAutocomplete: FC<QueryEditorAutocompleteProps> = ({
|
|||
const beforeValueByContext = value.substring(0, startIndexOfValueByContext);
|
||||
const afterValueByContext = value.substring(endIndexOfValueByContext);
|
||||
|
||||
// Add quotes around the value if the context is labelValue
|
||||
if (context === QueryContextType.labelValue) {
|
||||
const quote = "\"";
|
||||
const needsQuote = /(?:=|!=|=~|!~)$/.test(beforeValueByContext);
|
||||
insert = `${needsQuote ? quote : ""}${insert}`;
|
||||
}
|
||||
|
||||
// Assemble the new value with the inserted text
|
||||
const newVal = `${beforeValueByContext}${insert}${afterValueByContext}`;
|
||||
onSelect(newVal);
|
||||
|
@ -109,11 +120,12 @@ const QueryEditorAutocomplete: FC<QueryEditorAutocompleteProps> = ({
|
|||
return (
|
||||
<>
|
||||
<Autocomplete
|
||||
loading={loading}
|
||||
disabledFullScreen
|
||||
value={valueByContext}
|
||||
options={options?.length < AUTOCOMPLETE_LIMITS.queryLimit ? options : []}
|
||||
options={options}
|
||||
anchor={anchorEl}
|
||||
minLength={AUTOCOMPLETE_MIN_SYMBOLS[context]}
|
||||
minLength={0}
|
||||
offset={{ top: 0, left: leftOffset }}
|
||||
onSelect={handleSelect}
|
||||
onFoundOptions={onFoundOptions}
|
||||
|
@ -122,7 +134,6 @@ const QueryEditorAutocomplete: FC<QueryEditorAutocompleteProps> = ({
|
|||
message: "Please, specify the query more precisely."
|
||||
}}
|
||||
/>
|
||||
{loading && <div className="vm-query-editor-autocomplete"><RefreshIcon/></div>}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -2,20 +2,4 @@
|
|||
|
||||
.vm-query-editor {
|
||||
position: relative;
|
||||
|
||||
&-autocomplete {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-items: center;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: $padding-global;
|
||||
width: 12px;
|
||||
height: 100%;
|
||||
color: $color-text-secondary;
|
||||
z-index: 2;
|
||||
animation: half-circle-spinner-animation 1s infinite linear, vm-fade 0.5s ease-in;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import React, { FC, Ref, useCallback, useEffect, useMemo, useRef, useState, JSX
|
|||
import classNames from "classnames";
|
||||
import Popper from "../Popper/Popper";
|
||||
import "./style.scss";
|
||||
import { DoneIcon } from "../Icons";
|
||||
import { DoneIcon, RefreshIcon } from "../Icons";
|
||||
import useDeviceDetect from "../../../hooks/useDeviceDetect";
|
||||
import useBoolean from "../../../hooks/useBoolean";
|
||||
import useEventListener from "../../../hooks/useEventListener";
|
||||
|
@ -27,6 +27,7 @@ interface AutocompleteProps {
|
|||
disabledFullScreen?: boolean
|
||||
offset?: {top: number, left: number}
|
||||
maxDisplayResults?: {limit: number, message?: string}
|
||||
loading?: boolean;
|
||||
onSelect: (val: string) => void
|
||||
onOpenAutocomplete?: (val: boolean) => void
|
||||
onFoundOptions?: (val: AutocompleteOptions[]) => void
|
||||
|
@ -51,6 +52,7 @@ const Autocomplete: FC<AutocompleteProps> = ({
|
|||
disabledFullScreen,
|
||||
offset,
|
||||
maxDisplayResults,
|
||||
loading,
|
||||
onSelect,
|
||||
onOpenAutocomplete,
|
||||
onFoundOptions,
|
||||
|
@ -190,6 +192,7 @@ const Autocomplete: FC<AutocompleteProps> = ({
|
|||
})}
|
||||
ref={wrapperEl}
|
||||
>
|
||||
{loading && <div className="vm-autocomplete__loader"><RefreshIcon/><span>Loading...</span></div>}
|
||||
{displayNoOptionsText && <div className="vm-autocomplete__no-options">{noOptionsText}</div>}
|
||||
{!hideFoundedOptions && foundOptions.map((option, i) =>
|
||||
<div
|
||||
|
|
|
@ -16,6 +16,22 @@
|
|||
color: $color-text-disabled;
|
||||
}
|
||||
|
||||
&__loader {
|
||||
display: grid;
|
||||
grid-template-columns: 14px auto;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: $padding-small;
|
||||
padding: $padding-global;
|
||||
color: $color-text-secondary;
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
|
||||
svg {
|
||||
animation: half-circle-spinner-animation 1s infinite linear, vm-fade 0.5s ease-in;
|
||||
}
|
||||
}
|
||||
|
||||
&-info,
|
||||
&-message {
|
||||
padding: $padding-global;
|
||||
|
|
|
@ -1,14 +1,5 @@
|
|||
import { QueryContextType } from "../types";
|
||||
|
||||
export const AUTOCOMPLETE_LIMITS = {
|
||||
displayResults: 50,
|
||||
queryLimit: 1000,
|
||||
cacheLimit: 1000,
|
||||
};
|
||||
|
||||
export const AUTOCOMPLETE_MIN_SYMBOLS = {
|
||||
[QueryContextType.metricsql]: 2,
|
||||
[QueryContextType.empty]: 2,
|
||||
[QueryContextType.label]: 0,
|
||||
[QueryContextType.labelValue]: 0,
|
||||
};
|
||||
|
|
|
@ -47,7 +47,7 @@ export const useFetchQueryOptions = ({ valueByContext, metric, label, context }:
|
|||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [value, setValue] = useState(valueByContext);
|
||||
const debouncedSetValue = debounce(setValue, 800);
|
||||
const debouncedSetValue = debounce(setValue, 500);
|
||||
useEffect(() => {
|
||||
debouncedSetValue(valueByContext);
|
||||
return debouncedSetValue.cancel;
|
||||
|
@ -80,7 +80,7 @@ export const useFetchQueryOptions = ({ valueByContext, metric, label, context }:
|
|||
};
|
||||
|
||||
const fetchData = async ({ value, urlSuffix, setter, type, params }: FetchDataArgs) => {
|
||||
if (!value) return;
|
||||
if (!value && type === TypeData.metric) return;
|
||||
abortControllerRef.current.abort();
|
||||
abortControllerRef.current = new AbortController();
|
||||
const { signal } = abortControllerRef.current;
|
||||
|
|
|
@ -58,6 +58,7 @@ The sandbox cluster installation is running under the constant load generated by
|
|||
* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): fix handling invalid timezone. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5732).
|
||||
* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): fix the bug where the select does not open. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5728).
|
||||
* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): clear entered text in select after selecting a value. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5727).
|
||||
* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): improve the operation of the context for autocomplete. See [this](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5736), [this](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5737) and [this](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5739) issues.
|
||||
* BUGFIX: [dashboards](https://grafana.com/orgs/victoriametrics): update `Storage full ETA` panels for Single-node and Cluster dashboards to prevent them from showing negative or blank results caused by increase of deduplicated samples. Deduplicated samples were part of the expression to provide a better estimate for disk usage, but due to sporadic nature of [deduplication](https://docs.victoriametrics.com/#deduplication) in VictoriaMetrics it rather produced skewed results. See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/5747).
|
||||
|
||||
## [v1.97.1](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.97.1)
|
||||
|
|
Loading…
Reference in a new issue