vmui: change logic autocomplete (#2196)

* fix: change autocomplete display logic

* fix: change z-index for labels of input fields

* fix: change autocomplete display logic

* wip

* wip

Co-authored-by: Aliaksandr Valialkin <valyala@victoriametrics.com>
This commit is contained in:
Yury Molodov 2022-02-21 16:43:55 +03:00 committed by Aliaksandr Valialkin
parent 4211f85e52
commit cdd632985f
No known key found for this signature in database
GPG key ID: A72BEC6CD3D0DED1
7 changed files with 52 additions and 34 deletions

View file

@ -1,12 +1,12 @@
{ {
"files": { "files": {
"main.css": "./static/css/main.098d452b.css", "main.css": "./static/css/main.098d452b.css",
"main.js": "./static/js/main.c945b173.js", "main.js": "./static/js/main.afc823de.js",
"static/js/27.939f971b.chunk.js": "./static/js/27.939f971b.chunk.js", "static/js/27.939f971b.chunk.js": "./static/js/27.939f971b.chunk.js",
"index.html": "./index.html" "index.html": "./index.html"
}, },
"entrypoints": [ "entrypoints": [
"static/css/main.098d452b.css", "static/css/main.098d452b.css",
"static/js/main.c945b173.js" "static/js/main.afc823de.js"
] ]
} }

View file

@ -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.c945b173.js"></script><link href="./static/css/main.098d452b.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.afc823de.js"></script><link href="./static/css/main.098d452b.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

File diff suppressed because one or more lines are too long

View file

@ -6,7 +6,7 @@
* @license MIT * @license MIT
*/ */
/** @license MUI v5.4.1 /** @license MUI v5.4.2
* *
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.

File diff suppressed because one or more lines are too long

View file

@ -31,21 +31,23 @@ const QueryEditor: FC<QueryEditorProps> = ({
queryOptions queryOptions
}) => { }) => {
const [downMetaKeys, setDownMetaKeys] = useState<string[]>([]);
const [focusField, setFocusField] = useState(false); const [focusField, setFocusField] = useState(false);
const [focusOption, setFocusOption] = useState(-1); const [focusOption, setFocusOption] = useState(-1);
const autocompleteAnchorEl = useRef<HTMLDivElement>(null); const autocompleteAnchorEl = useRef<HTMLDivElement>(null);
const wrapperEl = useRef<HTMLUListElement>(null); const wrapperEl = useRef<HTMLUListElement>(null);
const openAutocomplete = useMemo(() => { const openAutocomplete = useMemo(() => {
return !(!autocomplete || downMetaKeys.length || query.length < 2 || !focusField); const words = (query.match(/[a-zA-Z_:.][a-zA-Z0-9_:.]*/gm) || []).length;
}, [query, downMetaKeys, autocomplete, focusField]); return !(!autocomplete || query.length < 2 || words > 1 || !focusField);
}, [query, autocomplete, focusField]);
const actualOptions = useMemo(() => { const actualOptions = useMemo(() => {
setFocusOption(0);
if (!openAutocomplete) return []; if (!openAutocomplete) return [];
try { try {
const regexp = new RegExp(String(query), "i"); const regexp = new RegExp(String(query), "i");
return queryOptions.filter((item) => regexp.test(item) && item !== query); const options = queryOptions.filter((item) => regexp.test(item) && (item !== query));
return options.sort((a,b) => (a.match(regexp)?.index || 0) - (b.match(regexp)?.index || 0));
} catch (e) { } catch (e) {
return []; return [];
} }
@ -53,31 +55,38 @@ const QueryEditor: FC<QueryEditorProps> = ({
const handleKeyDown = (e: KeyboardEvent<HTMLDivElement>) => { const handleKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {
const {key, ctrlKey, metaKey, shiftKey} = e; 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>) => {
const {key, ctrlKey, metaKey} = e;
if (downMetaKeys.includes(key)) setDownMetaKeys(downMetaKeys.filter(k => k !== key));
const ctrlMetaKey = ctrlKey || metaKey; const ctrlMetaKey = ctrlKey || metaKey;
if (key === "Enter" && ctrlMetaKey) { const arrowUp = key === "ArrowUp";
runQuery(); const arrowDown = key === "ArrowDown";
} else if (key === "ArrowUp" && ctrlMetaKey) { const enter = key === "Enter";
const hasAutocomplete = openAutocomplete && actualOptions.length;
if ((arrowUp || arrowDown || enter) && (hasAutocomplete || ctrlMetaKey)) {
e.preventDefault();
}
// ArrowUp
if (arrowUp && hasAutocomplete && !ctrlMetaKey) {
setFocusOption((prev) => prev === 0 ? 0 : prev - 1);
} else if (arrowUp && ctrlMetaKey) {
setHistoryIndex(-1, index); setHistoryIndex(-1, index);
} else if (key === "ArrowDown" && ctrlMetaKey) { }
// ArrowDown
if (arrowDown && hasAutocomplete && !ctrlMetaKey) {
setFocusOption((prev) => prev >= actualOptions.length - 1 ? actualOptions.length - 1 : prev + 1);
} else if (arrowDown && ctrlMetaKey) {
setHistoryIndex(1, index); setHistoryIndex(1, index);
} }
// Enter
if (enter && hasAutocomplete && !shiftKey && !ctrlMetaKey) {
setQuery(actualOptions[focusOption], index);
} else if (enter && ctrlKey) {
runQuery();
}
}; };
useEffect(() => { useEffect(() => {
@ -94,8 +103,16 @@ const QueryEditor: FC<QueryEditorProps> = ({
multiline multiline
error={!!error} error={!!error}
onFocus={() => setFocusField(true)} onFocus={() => setFocusField(true)}
onBlur={() => setFocusField(false)} onBlur={(e) => {
onKeyUp={handleKeyUp} const autocompleteItem = e.relatedTarget?.id || "";
const itemIndex = actualOptions.indexOf(autocompleteItem.replace("$autocomplete$", ""));
if (itemIndex !== -1) {
setQuery(actualOptions[itemIndex], index);
e.target.focus();
} else {
setFocusField(false);
}
}}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
onChange={(e) => setQuery(e.target.value, index)} onChange={(e) => setQuery(e.target.value, index)}
/> />
@ -103,7 +120,7 @@ const QueryEditor: FC<QueryEditorProps> = ({
<Paper elevation={3} sx={{ maxHeight: 300, overflow: "auto" }}> <Paper elevation={3} sx={{ maxHeight: 300, overflow: "auto" }}>
<MenuList ref={wrapperEl} dense> <MenuList ref={wrapperEl} dense>
{actualOptions.map((item, i) => {actualOptions.map((item, i) =>
<MenuItem key={item} sx={{bgcolor: `rgba(0, 0, 0, ${i === focusOption ? 0.12 : 0})`}}> <MenuItem id={`$autocomplete$${item}`} key={item} sx={{bgcolor: `rgba(0, 0, 0, ${i === focusOption ? 0.12 : 0})`}}>
{item} {item}
</MenuItem>)} </MenuItem>)}
</MenuList> </MenuList>

View file

@ -28,7 +28,8 @@ const THEME = createTheme({
root: { root: {
fontSize: "12px", fontSize: "12px",
letterSpacing: "normal", letterSpacing: "normal",
lineHeight: "1" lineHeight: "1",
zIndex: 0
} }
} }
}, },