mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2025-01-10 15:14:09 +00:00
vmui: correct url encoding (#2067)
* fix: correct encode multi-line queries * fix: change autocomplete for correct arrows work * app/vmselect/vmui: `make vmui-update` * docs/CHANGELOG.md: document the bugfix for https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2039 Co-authored-by: Aliaksandr Valialkin <valyala@victoriametrics.com>
This commit is contained in:
parent
dcadec65b6
commit
70737ea4ac
9 changed files with 78 additions and 42 deletions
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"files": {
|
||||
"main.css": "./static/css/main.79ff1ad2.css",
|
||||
"main.js": "./static/js/main.b46d35b9.js",
|
||||
"main.js": "./static/js/main.7d03dd65.js",
|
||||
"static/js/27.cc1b69f7.chunk.js": "./static/js/27.cc1b69f7.chunk.js",
|
||||
"index.html": "./index.html"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/css/main.79ff1ad2.css",
|
||||
"static/js/main.b46d35b9.js"
|
||||
"static/js/main.7d03dd65.js"
|
||||
]
|
||||
}
|
|
@ -1 +1 @@
|
|||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="VM-UI is a metric explorer for Victoria Metrics"/><link rel="apple-touch-icon" href="./apple-touch-icon.png"/><link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png"><link rel="manifest" href="./manifest.json"/><title>VM UI</title><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"/><script defer="defer" src="./static/js/main.b46d35b9.js"></script><link href="./static/css/main.79ff1ad2.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="VM-UI is a metric explorer for Victoria Metrics"/><link rel="apple-touch-icon" href="./apple-touch-icon.png"/><link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png"><link rel="manifest" href="./manifest.json"/><title>VM UI</title><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"/><script defer="defer" src="./static/js/main.7d03dd65.js"></script><link href="./static/css/main.79ff1ad2.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
2
app/vmselect/vmui/static/js/main.7d03dd65.js
Normal file
2
app/vmselect/vmui/static/js/main.7d03dd65.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,9 +1,12 @@
|
|||
import React, {FC, useEffect, useState} from "preact/compat";
|
||||
import React, {FC, useEffect, useMemo, useRef, useState} from "preact/compat";
|
||||
import {KeyboardEvent} from "react";
|
||||
import {ErrorTypes} from "../../../../types";
|
||||
import Autocomplete from "@mui/material/Autocomplete";
|
||||
import Popper from "@mui/material/Popper";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import {queryToBreakLine} from "../../../../utils/query-string";
|
||||
import Box from "@mui/material/Box";
|
||||
import Paper from "@mui/material/Paper";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import MenuList from "@mui/material/MenuList";
|
||||
|
||||
export interface QueryEditorProps {
|
||||
setHistoryIndex: (step: number, index: number) => void;
|
||||
|
@ -28,18 +31,43 @@ const QueryEditor: FC<QueryEditorProps> = ({
|
|||
queryOptions
|
||||
}) => {
|
||||
|
||||
const [value, setValue] = useState(query);
|
||||
const [downMetaKeys, setDownMetaKeys] = useState<string[]>([]);
|
||||
const [focusField, setFocusField] = useState(false);
|
||||
const [focusOption, setFocusOption] = useState(-1);
|
||||
const autocompleteAnchorEl = useRef<HTMLDivElement>(null);
|
||||
const wrapperEl = useRef<HTMLUListElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
setValue(queryToBreakLine(query));
|
||||
}, [query]);
|
||||
const openAutocomplete = useMemo(() => {
|
||||
return !(!autocomplete || downMetaKeys.length || query.length < 2 || !focusField);
|
||||
}, [query, downMetaKeys, autocomplete, focusField]);
|
||||
|
||||
const handleKeyDown = (e: KeyboardEvent<HTMLDivElement>): void => {
|
||||
if (e.ctrlKey || e.metaKey) setDownMetaKeys([...downMetaKeys, e.key]);
|
||||
const actualOptions = useMemo(() => {
|
||||
if (!openAutocomplete) return [];
|
||||
try {
|
||||
const regexp = new RegExp(String(query), "i");
|
||||
return queryOptions.filter((item) => regexp.test(item) && item !== query);
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
}, [autocomplete, query, queryOptions]);
|
||||
|
||||
const handleKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {
|
||||
const {key, ctrlKey, metaKey, shiftKey} = e;
|
||||
if (ctrlKey || metaKey) setDownMetaKeys([...downMetaKeys, e.key]);
|
||||
if (key === "ArrowUp" && openAutocomplete && actualOptions.length) {
|
||||
e.preventDefault();
|
||||
setFocusOption((prev) => prev === 0 ? 0 : prev - 1);
|
||||
} else if (key === "ArrowDown" && openAutocomplete && actualOptions.length) {
|
||||
e.preventDefault();
|
||||
setFocusOption((prev) => prev >= actualOptions.length - 1 ? actualOptions.length - 1 : prev + 1);
|
||||
} else if (key === "Enter" && openAutocomplete && actualOptions.length && !shiftKey) {
|
||||
e.preventDefault();
|
||||
setQuery(actualOptions[focusOption], index);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleKeyUp = (e: KeyboardEvent<HTMLDivElement>): void => {
|
||||
const handleKeyUp = (e: KeyboardEvent<HTMLDivElement>) => {
|
||||
const {key, ctrlKey, metaKey} = e;
|
||||
if (downMetaKeys.includes(key)) setDownMetaKeys(downMetaKeys.filter(k => k !== key));
|
||||
const ctrlMetaKey = ctrlKey || metaKey;
|
||||
|
@ -52,25 +80,36 @@ const QueryEditor: FC<QueryEditorProps> = ({
|
|||
}
|
||||
};
|
||||
|
||||
return <Autocomplete
|
||||
freeSolo
|
||||
fullWidth
|
||||
disableClearable
|
||||
options={autocomplete && !downMetaKeys.length ? queryOptions : []}
|
||||
onChange={(event, value) => setQuery(value, index)}
|
||||
onKeyDown={handleKeyDown}
|
||||
onKeyUp={handleKeyUp}
|
||||
value={value}
|
||||
renderInput={(params) =>
|
||||
<TextField
|
||||
{...params}
|
||||
label={`Query ${index + 1}`}
|
||||
multiline
|
||||
error={!!error}
|
||||
onChange={(e) => setQuery(e.target.value, index)}
|
||||
/>
|
||||
}
|
||||
/>;
|
||||
useEffect(() => {
|
||||
if (!wrapperEl.current) return;
|
||||
const target = wrapperEl.current.childNodes[focusOption] as HTMLElement;
|
||||
if (target?.scrollIntoView) target.scrollIntoView({block: "center"});
|
||||
}, [focusOption]);
|
||||
|
||||
return <Box ref={autocompleteAnchorEl}>
|
||||
<TextField
|
||||
defaultValue={query}
|
||||
fullWidth
|
||||
label={`Query ${index + 1}`}
|
||||
multiline
|
||||
error={!!error}
|
||||
onFocus={() => setFocusField(true)}
|
||||
onBlur={() => setFocusField(false)}
|
||||
onKeyUp={handleKeyUp}
|
||||
onKeyDown={handleKeyDown}
|
||||
onChange={(e) => setQuery(e.target.value, index)}
|
||||
/>
|
||||
<Popper open={openAutocomplete} anchorEl={autocompleteAnchorEl.current} placement="bottom-start">
|
||||
<Paper elevation={3} sx={{ maxHeight: 300, overflow: "auto" }}>
|
||||
<MenuList ref={wrapperEl} dense>
|
||||
{actualOptions.map((item, i) =>
|
||||
<MenuItem key={item} sx={{bgcolor: `rgba(0, 0, 0, ${i === focusOption ? 0.12 : 0})`}}>
|
||||
{item}
|
||||
</MenuItem>)}
|
||||
</MenuList>
|
||||
</Paper>
|
||||
</Popper>
|
||||
</Box>;
|
||||
};
|
||||
|
||||
export default QueryEditor;
|
|
@ -11,7 +11,7 @@ import {
|
|||
} from "../../utils/time";
|
||||
import {getFromStorage} from "../../utils/storage";
|
||||
import {getDefaultServer} from "../../utils/default-server-url";
|
||||
import {breakLineToQuery, getQueryArray, getQueryStringValue} from "../../utils/query-string";
|
||||
import {getQueryArray, getQueryStringValue} from "../../utils/query-string";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
export interface TimeState {
|
||||
|
@ -88,7 +88,7 @@ export function reducer(state: AppState, action: Action): AppState {
|
|||
case "SET_QUERY":
|
||||
return {
|
||||
...state,
|
||||
query: action.payload.map(q => breakLineToQuery(q))
|
||||
query: action.payload.map(q => q)
|
||||
};
|
||||
case "SET_QUERY_HISTORY":
|
||||
return {
|
||||
|
|
|
@ -48,7 +48,7 @@ export const setQueryStringValue = (newValue: Record<string, unknown>): void =>
|
|||
newQsValue.push(`g${i}.${queryKey}=${valueEncoded}`);
|
||||
}
|
||||
});
|
||||
newQsValue.push(`g${i}.expr=${breakLineToQuery(q)}`);
|
||||
newQsValue.push(`g${i}.expr=${encodeURIComponent(q)}`);
|
||||
});
|
||||
|
||||
setQueryStringWithoutPageReload(newQsValue.join("&"));
|
||||
|
@ -69,7 +69,3 @@ export const getQueryArray = (): string[] => {
|
|||
return getQueryStringValue(`g${i}.expr`, "") as string;
|
||||
});
|
||||
};
|
||||
|
||||
export const breakLineToQuery = (q: string): string => q.replace(/\n/g, "%20");
|
||||
|
||||
export const queryToBreakLine = (q: string): string => q.replace(/%20/g, "\n");
|
||||
|
|
|
@ -39,7 +39,8 @@ sort: 15
|
|||
* BUGFIX: fix possible data race when searching for time series matching `{key=~"value|"}` filter over time range covering multipe days. See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/2032). Thanks to @waldoweng for the provided fix.
|
||||
* BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent.html): do not send staleness markers on graceful shutdown. This follows Prometheus behavior. See [this comment](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2013#issuecomment-1006994079).
|
||||
* BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent.html): properly set `__address__` label in `dockerswarm_sd_config`. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2038). Thanks to @ashtuchkin for the fix.
|
||||
* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): fix incorrect calculations of graph limits on y axis. This could result in incorrect graph rendering in some cases. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2037).
|
||||
* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): fix incorrect calculations for graph limits on y axis. This could result in incorrect graph rendering in some cases. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2037).
|
||||
* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): fix handling for multi-line queries. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2039).
|
||||
|
||||
|
||||
## [v1.71.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.71.0)
|
||||
|
|
Loading…
Reference in a new issue