From cf0077b55223daed297fbe076e2f6e9a40239b23 Mon Sep 17 00:00:00 2001 From: Yury Molodov Date: Thu, 10 Aug 2023 11:34:25 +0200 Subject: [PATCH] vmui: allow displaying the full error message on click (#4760) https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4719 --- .../DateTimeInput/DateTimeInput.tsx | 2 +- .../components/Main/TextField/TextField.tsx | 8 +-- .../Main/TextField/TextFieldError.tsx | 56 +++++++++++++++++++ .../src/components/Main/TextField/style.scss | 27 +++++---- .../src/components/Main/Tooltip/Tooltip.tsx | 2 +- app/vmui/packages/vmui/src/styles/core.scss | 16 +++--- docs/CHANGELOG.md | 1 + 7 files changed, 86 insertions(+), 26 deletions(-) create mode 100644 app/vmui/packages/vmui/src/components/Main/TextField/TextFieldError.tsx diff --git a/app/vmui/packages/vmui/src/components/Main/DatePicker/DateTimeInput/DateTimeInput.tsx b/app/vmui/packages/vmui/src/components/Main/DatePicker/DateTimeInput/DateTimeInput.tsx index 6299c0144..7986e582f 100644 --- a/app/vmui/packages/vmui/src/components/Main/DatePicker/DateTimeInput/DateTimeInput.tsx +++ b/app/vmui/packages/vmui/src/components/Main/DatePicker/DateTimeInput/DateTimeInput.tsx @@ -36,7 +36,7 @@ const DateTimeInput: FC = ({ const [maskedValue, setMaskedValue] = useState(formatStringDate(value)); const [focusToTime, setFocusToTime] = useState(false); const [awaitChangeForEnter, setAwaitChangeForEnter] = useState(false); - const error = dayjs(maskedValue).isValid() ? "" : "Expected format: YYYY-MM-DD HH:mm:ss"; + const error = dayjs(maskedValue).isValid() ? "" : "Invalid date format"; const handleMaskedChange = (e: ChangeEvent) => { setMaskedValue(e.currentTarget.value); diff --git a/app/vmui/packages/vmui/src/components/Main/TextField/TextField.tsx b/app/vmui/packages/vmui/src/components/Main/TextField/TextField.tsx index 935b2ace0..2514bfb9d 100644 --- a/app/vmui/packages/vmui/src/components/Main/TextField/TextField.tsx +++ b/app/vmui/packages/vmui/src/components/Main/TextField/TextField.tsx @@ -3,6 +3,7 @@ import classNames from "classnames"; import { useMemo } from "preact/compat"; import { useAppState } from "../../../state/common/StateContext"; import useDeviceDetect from "../../../hooks/useDeviceDetect"; +import TextFieldError from "./TextFieldError"; import "./style.scss"; interface TextFieldProps { @@ -132,12 +133,7 @@ const TextField: FC = ({ ) } {label && {label}} - - {error} - + {helperText && !error && ( {helperText} diff --git a/app/vmui/packages/vmui/src/components/Main/TextField/TextFieldError.tsx b/app/vmui/packages/vmui/src/components/Main/TextField/TextFieldError.tsx new file mode 100644 index 000000000..3d3b1a95a --- /dev/null +++ b/app/vmui/packages/vmui/src/components/Main/TextField/TextFieldError.tsx @@ -0,0 +1,56 @@ +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 = ({ error }) => { + const errorRef = useRef(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 ( + + {error} + + ); +}; + +export default TextFieldError; diff --git a/app/vmui/packages/vmui/src/components/Main/TextField/style.scss b/app/vmui/packages/vmui/src/components/Main/TextField/style.scss index 70b463645..44a854bbf 100644 --- a/app/vmui/packages/vmui/src/components/Main/TextField/style.scss +++ b/app/vmui/packages/vmui/src/components/Main/TextField/style.scss @@ -40,14 +40,9 @@ overflow: hidden; text-overflow: ellipsis; display: -webkit-box; - -webkit-line-clamp: 2; /* number of lines to show */ - line-clamp: 2; + -webkit-line-clamp: 1; /* number of lines to show */ + line-clamp: 1; -webkit-box-orient: vertical; - - @media (max-width: 500px) { - -webkit-line-clamp: 1; /* number of lines to show */ - line-clamp: 1; - } } &__label { @@ -56,10 +51,22 @@ } &__error { - top: calc((100% - ($font-size-small/2)) - 2px); + position: relative; + top: calc($font-size-small/-2); + width: fit-content; + overflow-wrap: anywhere; color: $color-error; pointer-events: auto; user-select: text; + + &_full { + display: block; + overflow: visible; + } + + &_overflowed { + cursor: pointer; + } } &__helper-text { @@ -117,9 +124,9 @@ align-items: center; justify-content: center; max-width: 15px; - top: auto; + top: 0; left: $padding-small; - height: 100%; + height: 40px; position: absolute; color: $color-text-secondary; } diff --git a/app/vmui/packages/vmui/src/components/Main/Tooltip/Tooltip.tsx b/app/vmui/packages/vmui/src/components/Main/Tooltip/Tooltip.tsx index 29aed9537..dad669e0e 100644 --- a/app/vmui/packages/vmui/src/components/Main/Tooltip/Tooltip.tsx +++ b/app/vmui/packages/vmui/src/components/Main/Tooltip/Tooltip.tsx @@ -41,7 +41,7 @@ const Tooltip: FC = ({ return () => { window.removeEventListener("scroll", onScrollWindow); }; - }, [isOpen]); + }, [isOpen, title]); const popperStyle = useMemo(() => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment diff --git a/app/vmui/packages/vmui/src/styles/core.scss b/app/vmui/packages/vmui/src/styles/core.scss index 5e6be91b6..4d41f2829 100644 --- a/app/vmui/packages/vmui/src/styles/core.scss +++ b/app/vmui/packages/vmui/src/styles/core.scss @@ -52,6 +52,7 @@ input[type=number]::-webkit-outer-spin-button { left: $padding-global; bottom: $padding-global; z-index: 999; + animation: vm-slide-snackbar 150ms cubic-bezier(0.280, 0.840, 0.420, 1.1); &-content { display: grid; @@ -71,15 +72,14 @@ input[type=number]::-webkit-outer-spin-button { bottom: 0; left: 0; right: 0; - animation: vm-slide-snackbar 150ms cubic-bezier(0.280, 0.840, 0.420, 1.1); + } - @keyframes vm-slide-snackbar { - 0% { - transform: translateY(100%); - } - 100% { - transform: translateY(0); - } + @keyframes vm-slide-snackbar { + 0% { + transform: translateY(100%); + } + 100% { + transform: translateY(0); } } } diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 70a06e3aa..ea6aa1d31 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -34,6 +34,7 @@ The following `tip` changes can be tested by building VictoriaMetrics components * FEATURE: [vmctl](https://docs.victoriametrics.com/vmctl.html): add support of `week` step for [time-based chunking migration](https://docs.victoriametrics.com/vmctl.html#using-time-based-chunking-of-migration). See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4738). * FEATURE: [vmctl](https://docs.victoriametrics.com/vmctl.html): do not add `/api/v1/read` suffix to remote read storage address defined by `--remote-read-src-addr` if a `--remote-read-disable-path-append` command-line flag is set. It allows an overriding path for remote-read API via `--remote-read-src-addr`. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4655). * FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): add warning in query field of vmui for partial data responses. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4721). +* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): allow displaying the full error message on click for trimmed error messages in vmui. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4719). * FEATURE: [Official Grafana dashboards for VictoriaMetrics](https://grafana.com/orgs/victoriametrics): add `Concurrent inserts` panel to vmagent's dasbhoard. The new panel supposed to show whether the number of concurrent inserts processed by vmagent isn't reaching the limit. * FEATURE: [Official Grafana dashboards for VictoriaMetrics](https://grafana.com/orgs/victoriametrics): add panels for absolute Mem and CPU usage by vmalert. See related issue [here](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4627). * FEATURE: [Official Grafana dashboards for VictoriaMetrics](https://grafana.com/orgs/victoriametrics): correctly calculate `Bytes per point` value for single-server and cluster VM dashboards. Before, the calculation mistakenly accounted for the number of entries in indexdb in denominator, which could have shown lower values than expected.