Repository: VictoriaMetrics/VictoriaMetrics
Pull request #4760 (2023-08-01 19:05:58)

vmui: option to see/copy the full error message
Changed the display logic for long errors in the text field.
On the click on err msg, display the full text of the message.

#4719

<img width="800" alt="demo_close" src="https://github.com/VictoriaMetrics/VictoriaMetrics/assets/29711459/608b3bbe-8b48-41e5-99f5-fe06c7f60d9f">
<img width="800" alt="demo_open" src="https://github.com/VictoriaMetrics/VictoriaMetrics/assets/29711459/2501fc34-94de-479e-992a-3cc2ea3bee5c">



codecov[bot]: ## [Codecov](https://app.codecov.io/gh/VictoriaMetrics/VictoriaMetrics/pull/4760?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VictoriaMetrics) Report
Patch coverage has no change and project coverage change: **`+0.05%`** :tada:
> Comparison is base [(`5aed369`)](https://app.codecov.io/gh/VictoriaMetrics/VictoriaMetrics/commit/5aed369132b3e38d85bb29709b23d861503d9ff0?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VictoriaMetrics) 61.00% compared to head [(`71b8ff7`)](https://app.codecov.io/gh/VictoriaMetrics/VictoriaMetrics/pull/4760?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VictoriaMetrics) 61.06%.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master    #4760      +/-   ##
==========================================
+ Coverage   61.00%   61.06%   +0.05%     
==========================================
  Files         380      381       +1     
  Lines       71582    71586       +4     
==========================================
+ Hits        43672    43716      +44     
+ Misses      25524    25481      -43     
- Partials     2386     2389       +3     
```


[see 13 files with indirect coverage changes](https://app.codecov.io/gh/VictoriaMetrics/VictoriaMetrics/pull/4760/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VictoriaMetrics)


</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/VictoriaMetrics/VictoriaMetrics/pull/4760?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VictoriaMetrics).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VictoriaMetrics).


Patch:
diff --git a/app/vmagent/README.md b/app/vmagent/README.md
index 400908205..775efe352 100644
--- a/app/vmagent/README.md
+++ b/app/vmagent/README.md
@@ -1571,7 +1571,7 @@ See the docs at https://docs.victoriametrics.com/vmagent.html .
      Round metric values to this number of decimal digits after the point before writing them to remote storage. Examples: -remoteWrite.roundDigits=2 would round 1.236 to 1.24, while -remoteWrite.roundDigits=-1 would round 126.78 to 130. By default, digits rounding is disabled. Set it to 100 for disabling it for a particular remote storage. This option may be used for improving data compression for the stored metrics
      Supports array of values separated by comma or specified via multiple flags.
   -remoteWrite.sendTimeout array
-     Timeout for sending a single block of data to the corresponding -remoteWrite.url
+     Timeout for sending a single block of data to the corresponding -remoteWrite.url (default 1m)
      Supports array of values separated by comma or specified via multiple flags.
   -remoteWrite.shardByURL
      Whether to shard outgoing series across all the remote storage systems enumerated via -remoteWrite.url . By default the data is replicated across all the -remoteWrite.url . See https://docs.victoriametrics.com/vmagent.html#sharding-among-remote-storages
diff --git a/app/vmagent/remotewrite/client.go b/app/vmagent/remotewrite/client.go
index 36add0c3f..6340da463 100644
--- a/app/vmagent/remotewrite/client.go
+++ b/app/vmagent/remotewrite/client.go
@@ -29,7 +29,7 @@ var (
 	rateLimit = flagutil.NewArrayInt("remoteWrite.rateLimit", "Optional rate limit in bytes per second for data sent to the corresponding -remoteWrite.url. "+
 		"By default, the rate limit is disabled. It can be useful for limiting load on remote storage when big amounts of buffered data "+
 		"is sent after temporary unavailability of the remote storage")
-	sendTimeout = flagutil.NewArrayDuration("remoteWrite.sendTimeout", "Timeout for sending a single block of data to the corresponding -remoteWrite.url")
+	sendTimeout = flagutil.NewArrayDuration("remoteWrite.sendTimeout", "Timeout for sending a single block of data to the corresponding -remoteWrite.url (default 1m)")
 	proxyURL    = flagutil.NewArrayString("remoteWrite.proxyURL", "Optional proxy URL for writing data to the corresponding -remoteWrite.url. "+
 		"Supported proxies: http, https, socks5. Example: -remoteWrite.proxyURL=socks5://proxy:1234")
 
diff --git a/app/vmalert/README.md b/app/vmalert/README.md
index 72077ebef..342ae7a78 100644
--- a/app/vmalert/README.md
+++ b/app/vmalert/README.md
@@ -117,11 +117,11 @@ name: <string>
 [ limit: <int> | default = 0 ]
 
 # How many rules execute at once within a group. Increasing concurrency may speed
-# up round execution speed.
+# up group's evaluation duration (exposed via `vmalert_iteration_duration_seconds` metric).
 [ concurrency: <integer> | default = 1 ]
 
 # Optional type for expressions inside the rules. Supported values: "graphite" and "prometheus".
-# By default "prometheus" type is used.
+# By default, "prometheus" type is used.
 [ type: <string> ]
 
 # Optional list of HTTP URL parameters
@@ -519,7 +519,7 @@ Alertmanagers.
 
 To avoid recording rules results and alerts state duplication in VictoriaMetrics server
 don't forget to configure [deduplication](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#deduplication).
-The recommended value for `-dedup.minScrapeInterval` must be greater or equal to vmalert `evaluation_interval`.
+The recommended value for `-dedup.minScrapeInterval` must be multiple of vmalert's `evaluation_interval`.
 If you observe inconsistent or "jumping" values in series produced by vmalert, try disabling `-datasource.queryTimeAlignment`
 command line flag. Because of alignment, two or more vmalert HA pairs will produce results with the same timestamps.
 But due of backfilling (data delivered to the datasource with some delay) values of such results may differ,
diff --git a/app/vmalert/main.go b/app/vmalert/main.go
index 5a15eff22..4e81ce838 100644
--- a/app/vmalert/main.go
+++ b/app/vmalert/main.go
@@ -319,8 +319,9 @@ func configReload(ctx context.Context, m *manager, groupsCfg []config.Group, sig
 		validateTplFn = notifier.ValidateTemplates
 	}
 
-	// init reload metrics with positive values to improve alerting conditions
-	setConfigSuccess(fasttime.UnixTimestamp())
+	// init metrics for config state with positive values to improve alerting conditions
+	setConfigSuccessAt(fasttime.UnixTimestamp())
+
 	parseFn := config.Parse
 	for {
 		select {
@@ -358,11 +359,12 @@ func configReload(ctx context.Context, m *manager, groupsCfg []config.Group, sig
 		}
 		if configsEqual(newGroupsCfg, groupsCfg) {
 			templates.Reload()
-			// set success to 1 since previous reload
-			// could have been unsuccessful
+			// set success to 1 since previous reload could have been unsuccessful
+			// do not update configTimestamp as config version remains old.
 			configSuccess.Set(1)
-			setConfigError(nil)
-			// config didn't change - skip it
+			// reset the last config error since the config change was rolled back
+			setLastConfigErr(nil)
+			// config didn't change - skip iteration
 			continue
 		}
 		if err := m.update(ctx, newGroupsCfg, false); err != nil {
@@ -372,7 +374,7 @@ func configReload(ctx context.Context, m *manager, groupsCfg []config.Group, sig
 		}
 		templates.Reload()
 		groupsCfg = newGroupsCfg
-		setConfigSuccess(fasttime.UnixTimestamp())
+		setConfigSuccessAt(fasttime.UnixTimestamp())
 		logger.Infof("Rules reloaded successfully from %q", *rulePath)
 	}
 }
@@ -389,39 +391,36 @@ func configsEqual(a, b []config.Group) bool {
 	return true
 }
 
-// setConfigSuccess sets config reload status to 1.
-func setConfigSuccess(at uint64) {
+// setConfigSuccessAt updates config related metrics as successful.
+func setConfigSuccessAt(at uint64) {
 	configSuccess.Set(1)
 	configTimestamp.Set(at)
-	// reset the error if any
-	setConfigErr(nil)
+	// reset the lastConfigErr
+	setLastConfigErr(nil)
 }
 
-// setConfigError sets config reload status to 0.
+// setConfigError updates config related metrics according to the error.
 func setConfigError(err error) {
 	configReloadErrors.Inc()
 	configSuccess.Set(0)
-	setConfigErr(err)
+	setLastConfigErr(err)
 }
 
 var (
-	configErrMu sync.RWMutex
-	// configErr represent the error message from the last
-	// config reload.
-	configErr error
+	lastConfigErrMu sync.RWMutex
+	// lastConfigErr represent the error message from the last config reload.
+	// The message is used in web UI as notification
+	lastConfigErr error
 )
 
-func setConfigErr(err error) {
-	configErrMu.Lock()
-	configErr = err
-	configErrMu.Unlock()
+func setLastConfigErr(err error) {
+	lastConfigErrMu.Lock()
+	lastConfigErr = err
+	lastConfigErrMu.Unlock()
 }
 
-func configError() error {
-	configErrMu.RLock()
-	defer configErrMu.RUnlock()
-	if configErr != nil {
-		return configErr
-	}
-	return nil
+func getLastConfigError() error {
+	lastConfigErrMu.RLock()
+	defer lastConfigErrMu.RUnlock()
+	return lastConfigErr
 }
diff --git a/app/vmalert/remotewrite/remotewrite.go b/app/vmalert/remotewrite/remotewrite.go
index 8d4f935c1..f217bd78b 100644
--- a/app/vmalert/remotewrite/remotewrite.go
+++ b/app/vmalert/remotewrite/remotewrite.go
@@ -216,7 +216,9 @@ func (c *Client) flush(ctx context.Context, wr *prompbmarshal.WriteRequest) {
 		retryInterval = maxRetryInterval
 	}
 	timeStart := time.Now()
-	defer sendDuration.Add(time.Since(timeStart).Seconds())
+	defer func() {
+		sendDuration.Add(time.Since(timeStart).Seconds())
+	}()
 L:
 	for attempts := 0; ; attempts++ {
 		err := c.send(ctx, b)
diff --git a/app/vmalert/web.qtpl b/app/vmalert/web.qtpl
index 2cbf0a2ce..425ea6ea5 100644
--- a/app/vmalert/web.qtpl
+++ b/app/vmalert/web.qtpl
@@ -12,7 +12,7 @@
 
 
 {% func Welcome(r *http.Request) %}
-    {%= tpl.Header(r, navItems, "vmalert", configError()) %}
+    {%= tpl.Header(r, navItems, "vmalert", getLastConfigError()) %}
     <p>
         API:<br>
         {% for _, p := range apiLinks  %}
@@ -40,7 +40,7 @@ btn-primary
 
 {% func ListGroups(r *http.Request, originGroups []APIGroup) %}
     {%code prefix := utils.Prefix(r.URL.Path) %}
-    {%= tpl.Header(r, navItems, "Groups", configError()) %}
+    {%= tpl.Header(r, navItems, "Groups", getLastConfigError()) %}
         {%code
             filter := r.URL.Query().Get("filter")
             rOk := make(map[string]int)
@@ -168,7 +168,7 @@ btn-primary
 
 {% func ListAlerts(r *http.Request, groupAlerts []GroupAlerts) %}
     {%code prefix := utils.Prefix(r.URL.Path) %}
-    {%= tpl.Header(r, navItems, "Alerts", configError()) %}
+    {%= tpl.Header(r, navItems, "Alerts", getLastConfigError()) %}
     {% if len(groupAlerts) > 0 %}
          <a class="btn btn-primary" role="button" onclick="collapseAll()">Collapse All</a>
          <a class="btn btn-primary" role="button" onclick="expandAll()">Expand All</a>
@@ -255,7 +255,7 @@ btn-primary
 {% endfunc %}
 
 {% func ListTargets(r *http.Request, targets map[notifier.TargetType][]notifier.Target) %}
-    {%= tpl.Header(r, navItems, "Notifiers", configError()) %}
+    {%= tpl.Header(r, navItems, "Notifiers", getLastConfigError()) %}
     {% if len(targets) > 0 %}
          <a class="btn btn-primary" role="button" onclick="collapseAll()">Collapse All</a>
          <a class="btn btn-primary" role="button" onclick="expandAll()">Expand All</a>
@@ -312,7 +312,7 @@ btn-primary
 
 {% func Alert(r *http.Request, alert *APIAlert) %}
     {%code prefix := utils.Prefix(r.URL.Path) %}
-    {%= tpl.Header(r, navItems, "", configError()) %}
+    {%= tpl.Header(r, navItems, "", getLastConfigError()) %}
     {%code
         var labelKeys []string
         for k := range alert.Labels {
@@ -399,7 +399,7 @@ btn-primary
 
 {% func RuleDetails(r *http.Request, rule APIRule) %}
     {%code prefix := utils.Prefix(r.URL.Path) %}
-    {%= tpl.Header(r, navItems, "", configError()) %}
+    {%= tpl.Header(r, navItems, "", getLastConfigError()) %}
     {%code
         var labelKeys []string
         for k := range rule.Labels {
diff --git a/app/vmalert/web.qtpl.go b/app/vmalert/web.qtpl.go
index 0fa83c873..bb95cc89b 100644
--- a/app/vmalert/web.qtpl.go
+++ b/app/vmalert/web.qtpl.go
@@ -34,7 +34,7 @@ func StreamWelcome(qw422016 *qt422016.Writer, r *http.Request) {
 	qw422016.N().S(`
     `)
 //line app/vmalert/web.qtpl:15
-	tpl.StreamHeader(qw422016, r, navItems, "vmalert", configError())
+	tpl.StreamHeader(qw422016, r, navItems, "vmalert", getLastConfigError())
 //line app/vmalert/web.qtpl:15
 	qw422016.N().S(`
     <p>
@@ -207,7 +207,7 @@ func StreamListGroups(qw422016 *qt422016.Writer, r *http.Request, originGroups [
 	qw422016.N().S(`
     `)
 //line app/vmalert/web.qtpl:43
-	tpl.StreamHeader(qw422016, r, navItems, "Groups", configError())
+	tpl.StreamHeader(qw422016, r, navItems, "Groups", getLastConfigError())
 //line app/vmalert/web.qtpl:43
 	qw422016.N().S(`
         `)
@@ -647,7 +647,7 @@ func StreamListAlerts(qw422016 *qt422016.Writer, r *http.Request, groupAlerts []
 	qw422016.N().S(`
     `)
 //line app/vmalert/web.qtpl:171
-	tpl.StreamHeader(qw422016, r, navItems, "Alerts", configError())
+	tpl.StreamHeader(qw422016, r, navItems, "Alerts", getLastConfigError())
 //line app/vmalert/web.qtpl:171
 	qw422016.N().S(`
     `)
@@ -922,7 +922,7 @@ func StreamListTargets(qw422016 *qt422016.Writer, r *http.Request, targets map[n
 	qw422016.N().S(`
     `)
 //line app/vmalert/web.qtpl:258
-	tpl.StreamHeader(qw422016, r, navItems, "Notifiers", configError())
+	tpl.StreamHeader(qw422016, r, navItems, "Notifiers", getLastConfigError())
 //line app/vmalert/web.qtpl:258
 	qw422016.N().S(`
     `)
@@ -1102,7 +1102,7 @@ func StreamAlert(qw422016 *qt422016.Writer, r *http.Request, alert *APIAlert) {
 	qw422016.N().S(`
     `)
 //line app/vmalert/web.qtpl:315
-	tpl.StreamHeader(qw422016, r, navItems, "", configError())
+	tpl.StreamHeader(qw422016, r, navItems, "", getLastConfigError())
 //line app/vmalert/web.qtpl:315
 	qw422016.N().S(`
     `)
@@ -1311,7 +1311,7 @@ func StreamRuleDetails(qw422016 *qt422016.Writer, r *http.Request, rule APIRule)
 	qw422016.N().S(`
     `)
 //line app/vmalert/web.qtpl:402
-	tpl.StreamHeader(qw422016, r, navItems, "", configError())
+	tpl.StreamHeader(qw422016, r, navItems, "", getLastConfigError())
 //line app/vmalert/web.qtpl:402
 	qw422016.N().S(`
     `)
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<DateTimeInputProps> = ({
   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<HTMLInputElement>) => {
     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<TextFieldProps> = ({
       )
     }
     {label && <span className="vm-text-field__label">{label}</span>}
-    <span
-      className="vm-text-field__error"
-      data-show={!!error}
-    >
-      {error}
-    </span>
+    <TextFieldError error={error}/>
     {helperText && !error && (
       <span className="vm-text-field__helper-text">
         {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<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;
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<TooltipProps> = ({
     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/dashboards/victoriametrics-cluster.json b/dashboards/victoriametrics-cluster.json
index d4bdce4ab..aae1bbba2 100644
--- a/dashboards/victoriametrics-cluster.json
+++ b/dashboards/victoriametrics-cluster.json
@@ -624,7 +624,7 @@
             "uid": "$ds"
           },
           "exemplar": true,
-          "expr": "sum(vm_data_size_bytes{job=~\"$job_storage\"}) / sum(vm_rows{job=~\"$job_storage\"})",
+          "expr": "sum(vm_data_size_bytes{job=~\"$job_storage\"}) / sum(vm_rows{job=~\"$job_storage\", type!~\"indexdb.*\"})",
           "format": "time_series",
           "instant": true,
           "interval": "",
diff --git a/dashboards/victoriametrics.json b/dashboards/victoriametrics.json
index b3d0641c0..69a0d93b5 100644
--- a/dashboards/victoriametrics.json
+++ b/dashboards/victoriametrics.json
@@ -4434,7 +4434,7 @@
                 "uid": "$ds"
               },
               "editorMode": "code",
-              "expr": "sum(vm_data_size_bytes{job=~\"$job\", instance=~\"$instance\"}) \n/ sum(vm_rows{job=~\"$job\", instance=~\"$instance\"})",
+              "expr": "sum(vm_data_size_bytes{job=~\"$job\", instance=~\"$instance\"}) \n/ sum(vm_rows{job=~\"$job\", instance=~\"$instance\", type!~\"indexdb.*\"})",
               "format": "time_series",
               "interval": "",
               "intervalFactor": 1,
diff --git a/deployment/docker/victorialogs/vector-docker/docker-compose.yml b/deployment/docker/victorialogs/vector-docker/docker-compose.yml
index cf63b2c55..39b636093 100644
--- a/deployment/docker/victorialogs/vector-docker/docker-compose.yml
+++ b/deployment/docker/victorialogs/vector-docker/docker-compose.yml
@@ -20,11 +20,6 @@ services:
         condition: service_healthy
       victoriametrics:
         condition: service_healthy
-    healthcheck:
-      test: ["CMD", "curl", "-f", "http://localhost:8686/health"]
-      interval: 1s
-      timeout: 1s
-      retries: 10
 
   # Run `make package-victoria-logs` to build victoria-logs image
   victorialogs:
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index 7c681a14c..ea6aa1d31 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -34,11 +34,15 @@ 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.
 * FEATURE: [Alerting rules for VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics/tree/master/deployment/docker#alerts): `ConcurrentFlushesHitTheLimit` alerting rule was moved from [single-server](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/deployment/docker/alerts.yml) and [cluster](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/deployment/docker/alerts-cluster.yml) alerts to the [list of "health" alerts](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/deployment/docker/alerts-health.yml) as it could be related to many VictoriaMetrics components. 
 
 * BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent.html): use local scrape timestamps for the scraped metrics unless `honor_timestamps: true` option is explicitly set at [scrape_config](https://docs.victoriametrics.com/sd_configs.html#scrape_configs). This fixes gaps for metrics collected from [cadvisor](https://github.com/google/cadvisor) or similar exporters, which export metrics with invalid timestamps. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4697) and [this comment](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4697#issuecomment-1654614799) for details. The issue has been introduced in [v1.68.0](#v1680).
+* BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert.html): properly set `vmalert_config_last_reload_successful` value on configuration updates or rollbacks. The bug was introduced in [v1.92.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.92.0) in [this PR](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/4543).
+* BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert.html): fix `vmalert_remotewrite_send_duration_seconds_total` value, before it didn't count in the real time spending on remote write requests. See [this pr](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/4801) for details.
 * BUGFIX: [vmbackupmanager](https://docs.victoriametrics.com/vmbackupmanager.html): fix panic when creating a backup to a local filesystem on Windows. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4704).
 
 
diff --git a/docs/operator/CHANGELOG.md b/docs/operator/CHANGELOG.md
index db501ef38..7aa19622b 100644
--- a/docs/operator/CHANGELOG.md
+++ b/docs/operator/CHANGELOG.md
@@ -4,19 +4,21 @@
 
 ### Breaking changes
 
-- **[vmalert](https://docs.victoriametrics.com/operator/api.html#vmalert): Field `OAuth2` in (HTTPAuth)[https://docs.victoriametrics.com/operator/api.html#httpauth] was renamed to `oauth2`. See [this issue](https://github.com/VictoriaMetrics/operator/issues/522) and [this PR](https://github.com/VictoriaMetrics/operator/pull/689) for details.**
-- **[vmalert](https://docs.victoriametrics.com/operator/api.html#vmalert): Field `bearerTokenFilePath` in (BearerAuth)[https://docs.victoriametrics.com/operator/api.html#bearerauth] was renamed to `bearerTokenFile`. See [this issue](https://github.com/VictoriaMetrics/operator/issues/522) and [this PR](https://github.com/VictoriaMetrics/operator/pull/688/) for details.**
-- **These changes affect following fields:**
-  - **`VMAlert.spec.datasource.OAuth2` -> `VMAlert.spec.datasource.oauth2`,**
-  - **`VMAlert.spec.notifier.OAuth2` -> `VMAlert.spec.notifier.oauth2`,**
-  - **`VMAlert.spec.notifiers[].OAuth2` -> `VMAlert.spec.notifiers[].oauth2`,**
-  - **`VMAlert.spec.remoteRead.OAuth2` -> `VMAlert.spec.remoteRead.oauth2`,**
-  - **`VMAlert.spec.remoteWrite.OAuth2` -> `VMAlert.spec.remoteWrite.oauth2`,**
-  - **`VMAlert.spec.datasource.bearerTokenFilePath` --> `VMAlert.spec.datasource.bearerTokenFile`,**
-  - **`VMAlert.spec.notifier.bearerTokenFilePath` --> `VMAlert.spec.notifier.bearerTokenFile`,**
-  - **`VMAlert.spec.notifiers[].bearerTokenFile` --> `VMAlert.spec.notifiers[].bearerTokenFile`,**
-  - **`VMAlert.spec.remoteRead.bearerTokenFilePath` --> `VMAlert.spec.remoteRead.bearerTokenFile`,**
-  - **`VMAlert.spec.remoteWrite.bearerTokenFilePath` --> `VMAlert.spec.remoteWrite.bearerTokenFile`.**
+- **[vmalert](https://docs.victoriametrics.com/operator/api.html#vmalert): Field `OAuth2` was renamed to `oauth2` due to compatibility issue. If you defined `OAuth2` with below fields in vmalert objects using operator before v0.36.0, these fields must be reapplied with new tag `oauth2` after upgrading. See [this issue](https://github.com/VictoriaMetrics/operator/issues/522) and [this PR](https://github.com/VictoriaMetrics/operator/pull/689) for details.**
+  - **Affected fields:**
+    - **`VMAlert.spec.datasource.OAuth2` -> `VMAlert.spec.datasource.oauth2`,**
+    - **`VMAlert.spec.notifier.OAuth2` -> `VMAlert.spec.notifier.oauth2`,**
+    - **`VMAlert.spec.notifiers[].OAuth2` -> `VMAlert.spec.notifiers[].oauth2`,**
+    - **`VMAlert.spec.remoteRead.OAuth2` -> `VMAlert.spec.remoteRead.oauth2`,**
+    - **`VMAlert.spec.remoteWrite.OAuth2` -> `VMAlert.spec.remoteWrite.oauth2`,**
+
+- **[vmalert](https://docs.victoriametrics.com/operator/api.html#vmalert): Field `bearerTokenFilePath` was renamed to `bearerTokenFile` due to compatibility issue. If you defined `bearerTokenFilePath` with below fields in vmalert objects using operator before v0.36.0, these fields must be reapplied with new tag `bearerTokenFile` after upgrading. See [this issue](https://github.com/VictoriaMetrics/operator/issues/522) and [this PR](https://github.com/VictoriaMetrics/operator/pull/688/) for details.**
+  - **Affected fields:**
+    - **`VMAlert.spec.datasource.bearerTokenFilePath` --> `VMAlert.spec.datasource.bearerTokenFile`,**
+    - **`VMAlert.spec.notifier.bearerTokenFilePath` --> `VMAlert.spec.notifier.bearerTokenFile`,**
+    - **`VMAlert.spec.notifiers[].bearerTokenFile` --> `VMAlert.spec.notifiers[].bearerTokenFile`,**
+    - **`VMAlert.spec.remoteRead.bearerTokenFilePath` --> `VMAlert.spec.remoteRead.bearerTokenFile`,**
+    - **`VMAlert.spec.remoteWrite.bearerTokenFilePath` --> `VMAlert.spec.remoteWrite.bearerTokenFile`.**
 
 ### Fixes
 
@@ -29,6 +31,10 @@
 ### Features
 
 - [vmagent](https://docs.victoriametrics.com/operator/api.html#vmagent): add [example config](https://github.com/VictoriaMetrics/operator/blob/master/config/examples/vmagent_stateful_with_sharding.yaml) for vmagent statefulmode.
+- [vmagent](https://docs.victoriametrics.com/operator/api.html#vmagent)/[vmsingle](https://docs.victoriametrics.com/operator/api.html#vmsingle): adapt new features in streaming aggregation:
+  - support `streamAggr.dropInput`, see [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4243) for details;
+  - support list for `match` parameter, see [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4635) for details;
+  - support `staleness_interval`, see [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4667) for details.
 - [vmcluster](https://docs.victoriametrics.com/operator/api.html#vmagent): add [example config](https://github.com/VictoriaMetrics/operator/blob/master/config/examples/vmcluster_with_additional_claim.yaml) for cluster with custom storage claims.
 - [vmrule](https://docs.victoriametrics.com/operator/api.html#vmrule): support `update_entries_limit` field in rules, refer to [alerting rules](https://docs.victoriametrics.com/vmalert.html#alerting-rules). See [this PR](https://github.com/VictoriaMetrics/operator/pull/691) for details.
 - [vmrule](https://docs.victoriametrics.com/operator/api.html#vmrule): support `keep_firing_for` field in rules, refer to [alerting rules](https://docs.victoriametrics.com/vmalert.html#alerting-rules). See [this PR](https://github.com/VictoriaMetrics/operator/pull/711) for details.
diff --git a/docs/operator/api.md b/docs/operator/api.md
index f592a2362..813726aca 100644
--- a/docs/operator/api.md
+++ b/docs/operator/api.md
@@ -810,7 +810,7 @@ VMAgentSpec defines the desired state of VMAgent
 
 ## VMAgentStatus
 
-VMAgentStatus defines the observed state of VmAgent
+VMAgentStatus defines the observed state of VMAgent
 
 | Field | Description | Scheme | Required |
 | ----- | ----------- | ------ | -------- |
@@ -985,6 +985,7 @@ StreamAggrConfig defines the stream aggregation config
 | ----- | ----------- | ------ | -------- |
 | rules | Stream aggregation rules | [][StreamAggrRule](#streamaggrrule) | true |
 | keepInput | Allows writing both raw and aggregate data | bool | false |
+| dropInput | Allow drop all the input samples after the aggregation | bool | false |
 | dedupInterval | Allows setting different de-duplication intervals per each configured remote storage | string | false |
 
 [Back to TOC](#table-of-contents)
@@ -995,8 +996,9 @@ StreamAggrRule defines the rule in stream aggregation config
 
 | Field | Description | Scheme | Required |
 | ----- | ----------- | ------ | -------- |
-| match | Match is a label selector for filtering time series for the given selector.\n\nIf the match isn&#39;t set, then all the input time series are processed. | string | false |
+| match | Match is a label selector for filtering time series for the given selector.\n\nIf the match isn&#39;t set, then all the input time series are processed. | Match | false |
 | interval | Interval is the interval between aggregations. | string | true |
+| staleness_interval | StalenessInterval defines an interval after which the series state will be reset if no samples have been sent during it. | string | false |
 | outputs | Outputs is a list of output aggregate functions to produce.\n\nThe following names are allowed:\n\n- total - aggregates input counters - increase - counts the increase over input counters - count_series - counts the input series - count_samples - counts the input samples - sum_samples - sums the input samples - last - the last biggest sample value - min - the minimum sample value - max - the maximum sample value - avg - the average value across all the samples - stddev - standard deviation across all the samples - stdvar - standard variance across all the samples - histogram_bucket - creates VictoriaMetrics histogram for input samples - quantiles(phi1, ..., phiN) - quantiles&#39; estimation for phi in the range [0..1]\n\nThe output time series will have the following names:\n\n  input_name:aggr_&lt;interval&gt;_&lt;output&gt; | []string | true |
 | by | By is an optional list of labels for grouping input series.\n\nSee also Without.\n\nIf neither By nor Without are set, then the Outputs are calculated individually per each input time series. | []string | false |
 | without | Without is an optional list of labels, which must be excluded when grouping input series.\n\nSee also By.\n\nIf neither By nor Without are set, then the Outputs are calculated individually per each input time series. | []string | false |
@@ -1161,7 +1163,7 @@ VMAlertSpec defines the desired state of VMAlert
 
 ## VMAlertStatus
 
-VMAlertStatus defines the observed state of VmAlert
+VMAlertStatus defines the observed state of VMAlert
 
 | Field | Description | Scheme | Required |
 | ----- | ----------- | ------ | -------- |
diff --git a/docs/operator/vars.md b/docs/operator/vars.md
index be4340dee..006fdf525 100644
--- a/docs/operator/vars.md
+++ b/docs/operator/vars.md
@@ -10,7 +10,7 @@ aliases:
 - /operator/vars.html
 ---
 # Auto Generated vars for package config 
- updated at Thu Aug  3 03:30:07 UTC 2023 
+ updated at Wed Aug  9 14:55:29 UTC 2023 
 
 
 | varible name | variable default value | variable required | variable description |
diff --git a/docs/vmagent.md b/docs/vmagent.md
index 585ada019..41d14d650 100644
--- a/docs/vmagent.md
+++ b/docs/vmagent.md
@@ -1582,7 +1582,7 @@ See the docs at https://docs.victoriametrics.com/vmagent.html .
      Round metric values to this number of decimal digits after the point before writing them to remote storage. Examples: -remoteWrite.roundDigits=2 would round 1.236 to 1.24, while -remoteWrite.roundDigits=-1 would round 126.78 to 130. By default, digits rounding is disabled. Set it to 100 for disabling it for a particular remote storage. This option may be used for improving data compression for the stored metrics
      Supports array of values separated by comma or specified via multiple flags.
   -remoteWrite.sendTimeout array
-     Timeout for sending a single block of data to the corresponding -remoteWrite.url
+     Timeout for sending a single block of data to the corresponding -remoteWrite.url (default 1m)
      Supports array of values separated by comma or specified via multiple flags.
   -remoteWrite.shardByURL
      Whether to shard outgoing series across all the remote storage systems enumerated via -remoteWrite.url . By default the data is replicated across all the -remoteWrite.url . See https://docs.victoriametrics.com/vmagent.html#sharding-among-remote-storages
diff --git a/docs/vmalert.md b/docs/vmalert.md
index d941caf0c..ff47ec260 100644
--- a/docs/vmalert.md
+++ b/docs/vmalert.md
@@ -128,11 +128,11 @@ name: <string>
 [ limit: <int> | default = 0 ]
 
 # How many rules execute at once within a group. Increasing concurrency may speed
-# up round execution speed.
+# up group's evaluation duration (exposed via `vmalert_iteration_duration_seconds` metric).
 [ concurrency: <integer> | default = 1 ]
 
 # Optional type for expressions inside the rules. Supported values: "graphite" and "prometheus".
-# By default "prometheus" type is used.
+# By default, "prometheus" type is used.
 [ type: <string> ]
 
 # Optional list of HTTP URL parameters
@@ -530,7 +530,7 @@ Alertmanagers.
 
 To avoid recording rules results and alerts state duplication in VictoriaMetrics server
 don't forget to configure [deduplication](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#deduplication).
-The recommended value for `-dedup.minScrapeInterval` must be greater or equal to vmalert `evaluation_interval`.
+The recommended value for `-dedup.minScrapeInterval` must be multiple of vmalert's `evaluation_interval`.
 If you observe inconsistent or "jumping" values in series produced by vmalert, try disabling `-datasource.queryTimeAlignment`
 command line flag. Because of alignment, two or more vmalert HA pairs will produce results with the same timestamps.
 But due of backfilling (data delivered to the datasource with some delay) values of such results may differ,
diff --git a/docs/vmauth.md b/docs/vmauth.md
index c7965aedb..cf198945f 100644
--- a/docs/vmauth.md
+++ b/docs/vmauth.md
@@ -362,6 +362,8 @@ See the docs at https://docs.victoriametrics.com/vmauth.html .
      Prefix for environment variables if -envflag.enable is set
   -eula
      By specifying this flag, you confirm that you have an enterprise license and accept the EULA https://victoriametrics.com/assets/VM_EULA.pdf . This flag is available only in VictoriaMetrics enterprise. See https://docs.victoriametrics.com/enterprise.html
+  -failTimeout duration
+     Sets a delay period for load balancing to skip a malfunctioning backend. (defaults 3s)
   -flagsAuthKey string
      Auth key for /flags endpoint. It must be passed via authKey query arg. It overrides httpAuth.* settings
   -fs.disableMmap


Test patch:
diff --git a/app/vmalert/main_test.go b/app/vmalert/main_test.go
index ace111851..afa27bace 100644
--- a/app/vmalert/main_test.go
+++ b/app/vmalert/main_test.go
@@ -90,6 +90,7 @@ groups:
 	if err != nil {
 		t.Fatal(err)
 	}
+	defer func() { _ = os.Remove(f.Name()) }()
 	writeToFile(t, f.Name(), rules1)
 
 	*configCheckInterval = 200 * time.Millisecond
@@ -117,7 +118,29 @@ groups:
 		return len(m.groups)
 	}
 
+	checkCfg := func(err error) {
+		cErr := getLastConfigError()
+		cfgSuc := configSuccess.Get()
+		if err != nil {
+			if cErr == nil {
+				t.Fatalf("expected to have config error %s; got nil instead", cErr)
+			}
+			if cfgSuc != 0 {
+				t.Fatalf("expected to have metric configSuccess to be set to 0; got %d instead", cfgSuc)
+			}
+			return
+		}
+
+		if cErr != nil {
+			t.Fatalf("unexpected config error: %s", cErr)
+		}
+		if cfgSuc != 1 {
+			t.Fatalf("expected to have metric configSuccess to be set to 1; got %d instead", cfgSuc)
+		}
+	}
+
 	time.Sleep(*configCheckInterval * 2)
+	checkCfg(nil)
 	groupsLen := lenLocked(m)
 	if groupsLen != 1 {
 		t.Fatalf("expected to have exactly 1 group loaded; got %d", groupsLen)
@@ -125,6 +148,7 @@ groups:
 
 	writeToFile(t, f.Name(), rules2)
 	time.Sleep(*configCheckInterval * 2)
+	checkCfg(nil)
 	groupsLen = lenLocked(m)
 	if groupsLen != 2 {
 		fmt.Println(m.groups)
@@ -134,6 +158,7 @@ groups:
 	writeToFile(t, f.Name(), rules1)
 	procutil.SelfSIGHUP()
 	time.Sleep(*configCheckInterval / 2)
+	checkCfg(nil)
 	groupsLen = lenLocked(m)
 	if groupsLen != 1 {
 		t.Fatalf("expected to have exactly 1 group loaded; got %d", groupsLen)
@@ -142,6 +167,7 @@ groups:
 	writeToFile(t, f.Name(), `corrupted`)
 	procutil.SelfSIGHUP()
 	time.Sleep(*configCheckInterval / 2)
+	checkCfg(fmt.Errorf("config error"))
 	groupsLen = lenLocked(m)
 	if groupsLen != 1 { // should remain unchanged
 		t.Fatalf("expected to have exactly 1 group loaded; got %d", groupsLen)