vmui: change warning display for text fields (#4848) (#4863)

https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4848
This commit is contained in:
Yury Molodov 2023-08-21 15:42:55 +02:00 committed by GitHub
parent 8287749c05
commit ca44b8da1f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 112 additions and 112 deletions

View file

@ -5,8 +5,6 @@ import TextField from "../../Main/TextField/TextField";
import Autocomplete from "../../Main/Autocomplete/Autocomplete"; import Autocomplete from "../../Main/Autocomplete/Autocomplete";
import "./style.scss"; import "./style.scss";
import { QueryStats } from "../../../api/types"; import { QueryStats } from "../../../api/types";
import Tooltip from "../../Main/Tooltip/Tooltip";
import { WarningIcon } from "../../Main/Icons";
import { partialWarning, seriesFetchedWarning } from "./warningText"; import { partialWarning, seriesFetchedWarning } from "./warningText";
export interface QueryEditorProps { export interface QueryEditorProps {
@ -41,7 +39,7 @@ const QueryEditor: FC<QueryEditorProps> = ({
const [openAutocomplete, setOpenAutocomplete] = useState(false); const [openAutocomplete, setOpenAutocomplete] = useState(false);
const autocompleteAnchorEl = useRef<HTMLDivElement>(null); const autocompleteAnchorEl = useRef<HTMLDivElement>(null);
const warnings = [ const warning = [
{ {
show: stats?.seriesFetched === "0" && !stats.resultLength, show: stats?.seriesFetched === "0" && !stats.resultLength,
text: seriesFetchedWarning text: seriesFetchedWarning
@ -50,7 +48,7 @@ const QueryEditor: FC<QueryEditorProps> = ({
show: stats?.isPartial, show: stats?.isPartial,
text: partialWarning text: partialWarning
} }
].filter((warning) => warning.show); ].filter((w) => w.show).map(w => w.text).join("");
const handleSelect = (val: string) => { const handleSelect = (val: string) => {
onChange(val); onChange(val);
@ -104,6 +102,7 @@ const QueryEditor: FC<QueryEditorProps> = ({
type={"textarea"} type={"textarea"}
autofocus={!!value} autofocus={!!value}
error={error} error={error}
warning={warning}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
onChange={onChange} onChange={onChange}
disabled={disabled} disabled={disabled}
@ -119,20 +118,6 @@ const QueryEditor: FC<QueryEditorProps> = ({
onFoundOptions={handleChangeFoundOptions} onFoundOptions={handleChangeFoundOptions}
/> />
)} )}
{!!warnings.length && (
<div className="vm-query-editor-warning">
<Tooltip
placement="bottom-right"
title={(
<div className="vm-query-editor-warning__tooltip">
{warnings.map((warning, index) => <p key={index}>{warning.text}</p>)}
</div>
)}
>
<WarningIcon/>
</Tooltip>
</div>
)}
</div>; </div>;
}; };

View file

@ -7,29 +7,4 @@
max-height: 300px; max-height: 300px;
overflow: auto; 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;
p {
margin-bottom: $padding-small;
&:last-child {
margin-bottom: 0;
}
}
}
}
} }

View file

@ -3,7 +3,7 @@ import classNames from "classnames";
import { useMemo } from "preact/compat"; import { useMemo } from "preact/compat";
import { useAppState } from "../../../state/common/StateContext"; import { useAppState } from "../../../state/common/StateContext";
import useDeviceDetect from "../../../hooks/useDeviceDetect"; import useDeviceDetect from "../../../hooks/useDeviceDetect";
import TextFieldError from "./TextFieldError"; import TextFieldMessage from "./TextFieldMessage";
import "./style.scss"; import "./style.scss";
interface TextFieldProps { interface TextFieldProps {
@ -11,6 +11,7 @@ interface TextFieldProps {
value?: string | number value?: string | number
type?: HTMLInputTypeAttribute | "textarea" type?: HTMLInputTypeAttribute | "textarea"
error?: string error?: string
warning?: string
placeholder?: string placeholder?: string
endIcon?: ReactNode endIcon?: ReactNode
startIcon?: ReactNode startIcon?: ReactNode
@ -30,12 +31,13 @@ const TextField: FC<TextFieldProps> = ({
value, value,
type = "text", type = "text",
error = "", error = "",
warning = "",
helperText = "",
placeholder, placeholder,
endIcon, endIcon,
startIcon, startIcon,
disabled = false, disabled = false,
autofocus = false, autofocus = false,
helperText,
inputmode = "text", inputmode = "text",
onChange, onChange,
onEnter, onEnter,
@ -53,6 +55,7 @@ const TextField: FC<TextFieldProps> = ({
const inputClasses = classNames({ const inputClasses = classNames({
"vm-text-field__input": true, "vm-text-field__input": true,
"vm-text-field__input_error": error, "vm-text-field__input_error": error,
"vm-text-field__input_warning": !error && warning,
"vm-text-field__input_icon-start": startIcon, "vm-text-field__input_icon-start": startIcon,
"vm-text-field__input_disabled": disabled, "vm-text-field__input_disabled": disabled,
"vm-text-field__input_textarea": type === "textarea", "vm-text-field__input_textarea": type === "textarea",
@ -133,12 +136,11 @@ const TextField: FC<TextFieldProps> = ({
) )
} }
{label && <span className="vm-text-field__label">{label}</span>} {label && <span className="vm-text-field__label">{label}</span>}
<TextFieldError error={error}/> <TextFieldMessage
{helperText && !error && ( error={error}
<span className="vm-text-field__helper-text"> warning={warning}
{helperText} info={helperText}
</span> />
)}
</label> </label>
; ;
}; };

View file

@ -1,56 +0,0 @@
import React, { FC, useEffect, useRef, useState } from "react";
import useEventListener from "../../../hooks/useEventListener";
import classNames from "classnames";
import "./style.scss";
interface TextFieldErrorProps {
error: string;
}
const TextFieldError: FC<TextFieldErrorProps> = ({ error }) => {
const errorRef = useRef<HTMLSpanElement>(null);
const [isErrorTruncated, setIsErrorTruncated] = useState(false);
const [showFull, setShowFull] = useState(false);
const checkIfTextTruncated = () => {
const el = errorRef.current;
if (el) {
const { offsetWidth, scrollWidth, offsetHeight, scrollHeight } = el;
// The "+1" is for the scrollbar in Firefox
const overflowed = (offsetWidth + 1) < scrollWidth || (offsetHeight + 1) < scrollHeight;
setIsErrorTruncated(overflowed);
} else {
setIsErrorTruncated(false);
}
};
const handleClickError = () => {
if (!isErrorTruncated) return;
setShowFull(true);
setIsErrorTruncated(false);
};
useEffect(() => {
setShowFull(false);
checkIfTextTruncated();
}, [errorRef, error]);
useEventListener("resize", checkIfTextTruncated);
return (
<span
className={classNames({
"vm-text-field__error": true,
"vm-text-field__error_overflowed": isErrorTruncated,
"vm-text-field__error_full": showFull,
})}
data-show={!!error}
ref={errorRef}
onClick={handleClickError}
>
{error}
</span>
);
};
export default TextFieldError;

View file

@ -0,0 +1,72 @@
import React, { FC, useEffect, useRef, useState } from "react";
import useEventListener from "../../../hooks/useEventListener";
import classNames from "classnames";
import "./style.scss";
import { useMemo } from "preact/compat";
interface TextFieldErrorProps {
error: string;
warning: string;
info: string;
}
const TextFieldMessage: FC<TextFieldErrorProps> = ({ error, warning, info }) => {
console.log(warning);
const messageRef = useRef<HTMLSpanElement>(null);
const [isMessageTruncated, setIsMessageTruncated] = useState(false);
const [showFull, setShowFull] = useState(false);
const prefix = useMemo(() => {
if (error) return "ERROR: ";
if (warning) return "WARNING: ";
return "";
}, [error, warning]);
const message = `${prefix}${error || warning || info}`;
const checkIfTextTruncated = () => {
const el = messageRef.current;
if (el) {
const { offsetWidth, scrollWidth, offsetHeight, scrollHeight } = el;
// The "+1" is for the scrollbar in Firefox
const overflowed = (offsetWidth + 1) < scrollWidth || (offsetHeight + 1) < scrollHeight;
setIsMessageTruncated(overflowed);
} else {
setIsMessageTruncated(false);
}
};
const handleClickError = () => {
if (!isMessageTruncated) return;
setShowFull(true);
setIsMessageTruncated(false);
};
useEffect(() => {
setShowFull(false);
checkIfTextTruncated();
}, [messageRef, message]);
useEventListener("resize", checkIfTextTruncated);
if (!error && !warning && !info) return null;
return (
<span
className={classNames({
"vm-text-field__error": true,
"vm-text-field__warning": warning && !error,
"vm-text-field__helper-text": !warning && !error,
"vm-text-field__error_overflowed": isMessageTruncated,
"vm-text-field__error_full": showFull,
})}
data-show={!!message}
ref={messageRef}
onClick={handleClickError}
>
{message}
</span>
);
};
export default TextFieldMessage;

View file

@ -26,6 +26,7 @@
&__label, &__label,
&__error, &__error,
&__warning,
&__helper-text, { &__helper-text, {
position: absolute; position: absolute;
left: calc($padding-global/2); left: calc($padding-global/2);
@ -50,12 +51,13 @@
color: $color-text-secondary; color: $color-text-secondary;
} }
&__helper-text,
&__warning,
&__error { &__error {
position: relative; position: relative;
top: calc($font-size-small/-2); top: calc($font-size-small/-2);
width: fit-content; width: fit-content;
overflow-wrap: anywhere; overflow-wrap: anywhere;
color: $color-error;
pointer-events: auto; pointer-events: auto;
user-select: text; user-select: text;
@ -69,8 +71,15 @@
} }
} }
&__error {
color: $color-error;
}
&__warning {
color: $color-warning;
}
&__helper-text { &__helper-text {
bottom: calc($font-size-small/-2);
color: $color-text-secondary; color: $color-text-secondary;
} }
@ -93,14 +102,26 @@
} }
&_error { &_error {
border: 1px solid $color-error; border-color: $color-error;
&:hover { &:hover {
border: 1px solid $color-error; border-color: $color-error;
} }
&:focus { &:focus {
border: 1px solid $color-error; border-color: $color-error;
}
}
&_warning {
border-color: $color-warning;
&:hover {
border-color: $color-warning;
}
&:focus {
border-color: $color-warning;
} }
} }

View file

@ -26,6 +26,7 @@ The following `tip` changes can be tested by building VictoriaMetrics components
* FEATURE: [vmbackup](https://docs.victoriametrics.com/vmbackup.html): add support for server-side copy of existing backups. See [these docs](https://docs.victoriametrics.com/vmbackup.html#server-side-copy-of-the-existing-backup) for details. * FEATURE: [vmbackup](https://docs.victoriametrics.com/vmbackup.html): add support for server-side copy of existing backups. See [these docs](https://docs.victoriametrics.com/vmbackup.html#server-side-copy-of-the-existing-backup) for details.
* FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent.html): properly handle `unexpected EOF` error when parsing metrics in Prometheus exposition format. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4817). * FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent.html): properly handle `unexpected EOF` error when parsing metrics in Prometheus exposition format. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4817).
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): make the warning message more noticeable for text fields. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4848).
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): add button for auto-formatting PromQL/MetricsQL queries. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4681). Thanks to @aramattamara for the [pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/4694). * FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): add button for auto-formatting PromQL/MetricsQL queries. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4681). Thanks to @aramattamara for the [pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/4694).
* BUGFIX: do not allow starting VictoriaMetrics components with improperly set boolean command-line flags in the form `-boolFlagName value`, since this leads to silent incomplete flags' parsing. This form should be replaced with `-boolFlagName=value`. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4845). * BUGFIX: do not allow starting VictoriaMetrics components with improperly set boolean command-line flags in the form `-boolFlagName value`, since this leads to silent incomplete flags' parsing. This form should be replaced with `-boolFlagName=value`. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4845).