Repository: VictoriaMetrics/VictoriaMetrics
Pull request #1946 (2021-12-14 14:49:34)

OpenTSDB Migration Fix
Migration shouldn't fail because of a single bad request on OpenTSDB's side. This PR just ignores response failures during metric collection.
If there's a _better_ solution (counting failures and crashing if > X or something) I'm all ears, but OpenTSDB is a fickle system, so handling a few failures without stopping the whole process seemed appropriate.


Patch:
diff --git a/README.md b/README.md
index 9fa9498cb..5a444567c 100644
--- a/README.md
+++ b/README.md
@@ -416,9 +416,15 @@ The `/api/v1/export` endpoint should return the following response:
 Data sent to VictoriaMetrics via `Graphite plaintext protocol` may be read via the following APIs:
 
 * [Graphite API](#graphite-api-usage)
-* [Prometheus querying API](#prometheus-querying-api-usage). VictoriaMetrics supports `__graphite__` pseudo-label for selecting time series with Graphite-compatible filters in [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html). For example, `{__graphite__="foo.*.bar"}` is equivalent to `{__name__=~"foo[.][^.]*[.]bar"}`, but it works faster and it is easier to use when migrating from Graphite to VictoriaMetrics. See [docs for Graphite paths and wildcards](https://graphite.readthedocs.io/en/latest/render_api.html#paths-and-wildcards). VictoriaMetrics also supports [label_graphite_group](https://docs.victoriametrics.com/MetricsQL.html#label_graphite_group) function for extracting the given groups from Graphite metric name.
+* [Prometheus querying API](#prometheus-querying-api-usage). See also [selecting Graphite metrics](#selecting-graphite-metrics).
 * [go-graphite/carbonapi](https://github.com/go-graphite/carbonapi/blob/main/cmd/carbonapi/carbonapi.example.victoriametrics.yaml)
 
+## Selecting Graphite metrics
+
+VictoriaMetrics supports `__graphite__` pseudo-label for selecting time series with Graphite-compatible filters in [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html). For example, `{__graphite__="foo.*.bar"}` is equivalent to `{__name__=~"foo[.][^.]*[.]bar"}`, but it works faster and it is easier to use when migrating from Graphite to VictoriaMetrics. See [docs for Graphite paths and wildcards](https://graphite.readthedocs.io/en/latest/render_api.html#paths-and-wildcards). VictoriaMetrics also supports [label_graphite_group](https://docs.victoriametrics.com/MetricsQL.html#label_graphite_group) function for extracting the given groups from Graphite metric name.
+
+The `__graphite__` pseudo-label supports e.g. alternate regexp filters such as `(value1|...|valueN)`. They are transparently converted to `{value1,...,valueN}` syntax [used in Graphite](https://graphite.readthedocs.io/en/latest/render_api.html#paths-and-wildcards). This allows using [multi-value template variables in Grafana](https://grafana.com/docs/grafana/latest/variables/formatting-multi-value-variables/) inside `__graphite__` pseudo-label. For example, Grafana expands `{__graphite__=~"foo.($bar).baz"}` into `{__graphite__=~"foo.(x|y).baz"}` if `$bar` template variable contains `x` and `y` values. In this case the query is automatically converted into `{__graphite__=~"foo.{x,y}.baz"}` before execution.
+
 ## How to send data from OpenTSDB-compatible agents
 
 VictoriaMetrics supports [telnet put protocol](http://opentsdb.net/docs/build/html/api_telnet/put.html)
@@ -559,8 +565,7 @@ VictoriaMetrics accepts optional query args: `extra_label=<label_name>=<label_va
 
 [Contact us](mailto:sales@victoriametrics.com) if you need assistance with such a proxy.
 
-VictoriaMetrics supports `__graphite__` pseudo-label for filtering time series with Graphite-compatible filters in [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html).
-For example, `{__graphite__="foo.*.bar"}` is equivalent to `{__name__=~"foo[.][^.]*[.]bar"}`, but it works faster and it is easier to use when migrating from Graphite to VictoriaMetrics. See [docs for Graphite paths and wildcards](https://graphite.readthedocs.io/en/latest/render_api.html#paths-and-wildcards). See also [label_graphite_group](https://docs.victoriametrics.com/MetricsQL.html#label_graphite_group) function.
+VictoriaMetrics supports `__graphite__` pseudo-label for filtering time series with Graphite-compatible filters in [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html). See [these docs](#selecting-graphite-metrics).
 
 
 ### Graphite Render API usage
@@ -832,7 +837,7 @@ unix timestamp in seconds or [RFC3339](https://www.ietf.org/rfc/rfc3339.txt) val
 
 The exported CSV data can be imported to VictoriaMetrics via [/api/v1/import/csv](#how-to-import-csv-data).
 
-The [deduplication](#deduplication) isn't applied for the data exported in CSV. It is expected that the de-duplication is performed during data import.
+The [deduplication](#deduplication) is applied for the data exported in CSV by default. It is possible to export raw data without de-duplication by passing `reduce_mem_usage=1` query arg to `/api/v1/export/csv`.
 
 
 ### How to export data in native format
@@ -1078,7 +1083,7 @@ It is recommended leaving the following amounts of spare resources:
 
 * 50% of free RAM for reducing the probability of OOM (out of memory) crashes and slowdowns during temporary spikes in workload.
 * 50% of spare CPU for reducing the probability of slowdowns during temporary spikes in workload.
-* At least 30% of free storage space at the directory pointed by `-storageDataPath` command-line flag.
+* At least 30% of free storage space at the directory pointed by `-storageDataPath` command-line flag. See also `-storage.minFreeDiskSpaceBytes` command-line flag description [here](#list-of-command-line-flags).
 
 
 ## High availability
@@ -1166,20 +1171,13 @@ See [these docs](https://docs.victoriametrics.com/guides/guide-vmcluster-multipl
 
 ## Downsampling
 
-There is no downsampling support at the moment, but:
+[VictoriaMetrics Enterprise](https://victoriametrics.com/enterprise.html) supports multi-level downsampling with `-downsampling.period` command-line flag. For example:
 
-* VictoriaMetrics is optimized for querying big amounts of raw data. See benchmark results for heavy queries
-  in [this article](https://medium.com/@valyala/measuring-vertical-scalability-for-time-series-databases-in-google-cloud-92550d78d8ae).
-* VictoriaMetrics has good compression for on-disk data. See [this article](https://medium.com/@valyala/victoriametrics-achieving-better-compression-for-time-series-data-than-gorilla-317bc1f95932)
-  for details.
-* The downsampling doesn't improve query performance on a long time range if the time range contains big number of time series due to [high churn rate](https://docs.victoriametrics.com/FAQ.html#what-is-high-churn-rate). The query performance depends on the number of unique time series on the selected time range, while downsampling doesn't reduce the number of unique time series in the database - it can reduce only the number of samples per each time series.
+* `-downsampling.period=30d:5m` instructs VictoriaMetrics to [deduplicate](#deduplication) samples older than 30 days with 5 minutes interval.
 
-These properties reduce the need of downsampling. We plan to implement downsampling in the future.
-See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/36) for details.
+* `-downsampling.period=30d:5m,180d:1h` instructs VictoriaMetrics to deduplicate samples older than 30 days with 5 minutes interval and to deduplicate samples older than 180 days with 1 hour interval.
 
-It is possible to (ab)use [-dedup.minScrapeInterval](#deduplication) for basic downsampling.
-For instance, if interval between the ingested data points is 15s, then `-dedup.minScrapeInterval=5m` will leave
-only a single data point out of 20 initial data points per each 5m interval.
+Downsampling is applied independently per each time series. It can reduce disk space usage and improve query performance if it is applied to time series with big number of samples per each series. The downsampling doesn't improve query performance if the database contains big number of time series with small number of samples per each series (aka [high churn rate](https://docs.victoriametrics.com/FAQ.html#what-is-high-churn-rate)), since downsamlping doesn't reduce the number of time series. So the majority of time is spent on searching for the matching time series.
 
 
 ## Multi-tenancy
@@ -1377,10 +1375,7 @@ See also more advanced [cardinality limiter in vmagent](https://docs.victoriamet
   This prevents from ingesting metrics with too many labels. It is recommended [monitoring](#monitoring) `vm_metrics_with_dropped_labels_total`
   metric in order to determine whether `-maxLabelsPerTimeseries` must be adjusted for your workload.
 
-* If you store Graphite metrics like `foo.bar.baz` in VictoriaMetrics, then use `{__graphite__="foo.*.baz"}` syntax for selecting such metrics.
-  This expression is equivalent to `{__name__=~"foo[.][^.]*[.]baz"}`, but it works faster and it is easier to use when migrating from Graphite.
-  See [docs for Graphite paths and wildcards](https://graphite.readthedocs.io/en/latest/render_api.html#paths-and-wildcards).
-  See also [label_graphite_group](https://docs.victoriametrics.com/MetricsQL.html#label_graphite_group) function, which allows extracting the given groups from Graphite metric names.
+* If you store Graphite metrics like `foo.bar.baz` in VictoriaMetrics, then `{__graphite__="foo.*.baz"}` filter can be used for selecting such metrics. See [these docs](#selecting-graphite-metrics) for details.
 
 * VictoriaMetrics ignores `NaN` values during data ingestion.
 
@@ -1446,6 +1441,18 @@ We also provide [vmbackupmanager](https://docs.victoriametrics.com/vmbackupmanag
 Enterprise binaries can be downloaded and evaluated for free from [the releases page](https://github.com/VictoriaMetrics/VictoriaMetrics/releases).
 
 
+## Benchmarks
+
+Note, that vendors (including VictoriaMetrics) are often biased when doing such tests. E.g. they try highlighting 
+the best parts of their product, while highlighting the worst parts of competing products. 
+So we encourage users and all independent third parties to conduct their becnhmarks for various products 
+they are evaluating in production and publish the results.
+
+As a reference, please see [benchmarks](https://docs.victoriametrics.com/Articles.html#benchmarks) conducted by
+VictoriaMetrics team. Please also see the [helm chart](https://github.com/VictoriaMetrics/benchmark) 
+for running ingestion benchmarks based on node_exporter metrics.
+
+
 ## Profiling
 
 VictoriaMetrics provides handlers for collecting the following [Go profiles](https://blog.golang.org/profiling-go-programs):
@@ -1573,11 +1580,14 @@ Pass `-help` to VictoriaMetrics in order to see the list of supported command-li
     	The maximum size in bytes of a single DataDog POST request to /api/v1/series
     	Supports the following optional suffixes for size values: KB, MB, GB, KiB, MiB, GiB (default 67108864)
   -dedup.minScrapeInterval duration
-    	Leave only the first sample in every time series per each discrete interval equal to -dedup.minScrapeInterval > 0. See https://docs.victoriametrics.com/#deduplication for details
+    	Leave only the first sample in every time series per each discrete interval equal to -dedup.minScrapeInterval > 0. See https://docs.victoriametrics.com/#deduplication and https://docs.victoriametrics.com/#downsampling
   -deleteAuthKey string
     	authKey for metrics' deletion via /api/v1/admin/tsdb/delete_series and /tags/delSeries
   -denyQueriesOutsideRetention
     	Whether to deny queries outside of the configured -retentionPeriod. When set, then /api/v1/query_range would return '503 Service Unavailable' error for queries with 'from' value outside -retentionPeriod. This may be useful when multiple data sources with distinct retentions are hidden behind query-tee
+  -downsampling.period array
+    	Comma-separated downsampling periods in the format 'offset:period'. For example, '30d:10m' instructs to leave a single sample per 10 minutes for samples older than 30 days. See https://docs.victoriametrics.com/#downsampling for details
+    	Supports an array of values separated by comma or specified via multiple flags.
   -dryRun
     	Whether to check only -promscrape.config and then exit. Unknown config entries are allowed in -promscrape.config by default. This can be changed with -promscrape.config.strictParse
   -enableTCP6
@@ -1586,6 +1596,8 @@ Pass `-help` to VictoriaMetrics in order to see the list of supported command-li
     	Whether to enable reading flags from environment variables additionally to command line. Command line flag values have priority over values from environment vars. Flags are read only from command line if this flag isn't set. See https://docs.victoriametrics.com/#environment-variables for more details
   -envflag.prefix string
     	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
   -finalMergeDelay duration
     	The delay before starting final merge for per-month partition after no new data is ingested into it. Final merge may require additional disk IO and CPU resources. Final merge may increase query speed and reduce disk space usage in some cases. Zero value disables final merge
   -forceFlushAuthKey string
@@ -1770,6 +1782,10 @@ Pass `-help` to VictoriaMetrics in order to see the list of supported command-li
     	Whether to disable automatic response cache reset if a sample with timestamp outside -search.cacheTimestampOffset is inserted into VictoriaMetrics
   -search.disableCache
     	Whether to disable response caching. This may be useful during data backfilling
+  -search.graphiteMaxPointsPerSeries int
+    	The maximum number of points per series Graphite render API can return (default 1000000)
+  -search.graphiteStorageStep duration
+    	The interval between datapoints stored in the database. It is used at Graphite Render API handler for normalizing the interval between datapoints in case it isn't normalized. It can be overriden by sending 'storage_step' query arg to /render API or by sending the desired interval via 'Storage-Step' http header during querying /render API (default 10s)
   -search.latencyOffset duration
     	The time when data points become visible in query results after the collection. Too small value can result in incomplete last points for query results (default 30s)
   -search.logSlowQueryDuration duration
diff --git a/app/victoria-metrics/main.go b/app/victoria-metrics/main.go
index 060529447..cbed6f0f1 100644
--- a/app/victoria-metrics/main.go
+++ b/app/victoria-metrics/main.go
@@ -25,7 +25,7 @@ import (
 var (
 	httpListenAddr    = flag.String("httpListenAddr", ":8428", "TCP address to listen for http connections")
 	minScrapeInterval = flag.Duration("dedup.minScrapeInterval", 0, "Leave only the first sample in every time series per each discrete interval "+
-		"equal to -dedup.minScrapeInterval > 0. See https://docs.victoriametrics.com/#deduplication for details")
+		"equal to -dedup.minScrapeInterval > 0. See https://docs.victoriametrics.com/#deduplication and https://docs.victoriametrics.com/#downsampling")
 	dryRun = flag.Bool("dryRun", false, "Whether to check only -promscrape.config and then exit. "+
 		"Unknown config entries are allowed in -promscrape.config by default. This can be changed with -promscrape.config.strictParse")
 )
@@ -51,7 +51,7 @@ func main() {
 
 	logger.Infof("starting VictoriaMetrics at %q...", *httpListenAddr)
 	startTime := time.Now()
-	storage.SetMinScrapeIntervalForDeduplication(*minScrapeInterval)
+	storage.SetDedupInterval(*minScrapeInterval)
 	vmstorage.Init(promql.ResetRollupResultCacheIfNeeded)
 	vmselect.Init()
 	vminsert.Init()
diff --git a/app/vmalert/datasource/vm_prom_api.go b/app/vmalert/datasource/vm_prom_api.go
index 47a34e9e6..3bf358a24 100644
--- a/app/vmalert/datasource/vm_prom_api.go
+++ b/app/vmalert/datasource/vm_prom_api.go
@@ -159,13 +159,15 @@ func (s *VMStorage) setPrometheusReqParams(r *http.Request, query string) {
 		}
 	}
 	q.Set("query", query)
-	if s.evaluationInterval > 0 {
-		// set step as evaluationInterval by default
-		q.Set("step", s.evaluationInterval.String())
+	if s.evaluationInterval > 0 { // set step as evaluationInterval by default
+		// always convert to seconds to keep compatibility with older
+		// Prometheus versions. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1943
+		q.Set("step", fmt.Sprintf("%ds", int(s.evaluationInterval.Seconds())))
 	}
-	if s.queryStep > 0 {
-		// override step with user-specified value
-		q.Set("step", s.queryStep.String())
+	if s.queryStep > 0 { // override step with user-specified value
+		// always convert to seconds to keep compatibility with older
+		// Prometheus versions. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1943
+		q.Set("step", fmt.Sprintf("%ds", int(s.queryStep.Seconds())))
 	}
 	r.URL.RawQuery = q.Encode()
 }
diff --git a/app/vmctl/opentsdb/opentsdb.go b/app/vmctl/opentsdb/opentsdb.go
index 02a375c08..06684f039 100644
--- a/app/vmctl/opentsdb/opentsdb.go
+++ b/app/vmctl/opentsdb/opentsdb.go
@@ -187,18 +187,28 @@ func (c Client) GetData(series Meta, rt RetentionMeta, start int64, end int64) (
 	if err != nil {
 		return Metric{}, fmt.Errorf("failed to send GET request to %q: %s", q, err)
 	}
+	/*
+		There are three potential failures here, none of which should kill the entire
+		migration run:
+		1. bad response code
+		2. failure to read response body
+		3. bad format of response body
+	*/
 	if resp.StatusCode != 200 {
-		return Metric{}, fmt.Errorf("Bad return from OpenTSDB: %q: %v", resp.StatusCode, resp)
+		log.Println(fmt.Sprintf("bad response code from OpenTSDB query %v...skipping", resp.StatusCode))
+		return Metric{}, nil
 	}
 	defer func() { _ = resp.Body.Close() }()
 	body, err := ioutil.ReadAll(resp.Body)
 	if err != nil {
-		return Metric{}, fmt.Errorf("could not retrieve series data from %q: %s", q, err)
+		log.Println("couldn't read response body from OpenTSDB query...skipping")
+		return Metric{}, nil
 	}
 	var output []OtsdbMetric
 	err = json.Unmarshal(body, &output)
 	if err != nil {
-		return Metric{}, fmt.Errorf("failed to unmarshal response from %q [%v]: %s", q, body, err)
+		log.Println(fmt.Sprintf("couldn't marshall response body from OpenTSDB query (%s)...skipping", body))
+		return Metric{}, nil
 	}
 	/*
 		We expect results to look like:
@@ -227,6 +237,8 @@ func (c Client) GetData(series Meta, rt RetentionMeta, start int64, end int64) (
 		An empty array doesn't cast to a OtsdbMetric struct well, and there's no reason to try, so we should just skip it
 		Because we're trying to migrate data without transformations, seeing aggregate tags could mean
 		we're dropping series on the floor.
+
+		In all "bad" cases, we don't end the migration, we just don't process that particular message
 	*/
 	if len(output) < 1 {
 		// no results returned...return an empty object without error
@@ -234,11 +246,11 @@ func (c Client) GetData(series Meta, rt RetentionMeta, start int64, end int64) (
 	}
 	if len(output) > 1 {
 		// multiple series returned for a single query. We can't process this right, so...
-		return Metric{}, fmt.Errorf("Query returned multiple results: %v", output)
+		return Metric{}, nil
 	}
 	if len(output[0].AggregateTags) > 0 {
 		// This failure means we've suppressed potential series somehow...
-		return Metric{}, fmt.Errorf("Query somehow has aggregate tags: %v", output[0].AggregateTags)
+		return Metric{}, nil
 	}
 	data := Metric{}
 	data.Metric = output[0].Metric
@@ -249,7 +261,7 @@ func (c Client) GetData(series Meta, rt RetentionMeta, start int64, end int64) (
 	*/
 	data, err = modifyData(data, c.Normalize)
 	if err != nil {
-		return Metric{}, fmt.Errorf("invalid series data from %q: %s", q, err)
+		return Metric{}, nil
 	}
 
 	/*
diff --git a/app/vmselect/netstorage/netstorage.go b/app/vmselect/netstorage/netstorage.go
index 6ca6cd05b..54dfc4b1f 100644
--- a/app/vmselect/netstorage/netstorage.go
+++ b/app/vmselect/netstorage/netstorage.go
@@ -468,7 +468,8 @@ func (pts *packedTimeseries) Unpack(dst *Result, tbf *tmpBlocksFile, tr storage.
 	if firstErr != nil {
 		return firstErr
 	}
-	mergeSortBlocks(dst, sbs)
+	dedupInterval := storage.GetDedupInterval()
+	mergeSortBlocks(dst, sbs, dedupInterval)
 	return nil
 }
 
@@ -489,7 +490,7 @@ var sbPool sync.Pool
 
 var metricRowsSkipped = metrics.NewCounter(`vm_metric_rows_skipped_total{name="vmselect"}`)
 
-func mergeSortBlocks(dst *Result, sbh sortBlocksHeap) {
+func mergeSortBlocks(dst *Result, sbh sortBlocksHeap, dedupInterval int64) {
 	// Skip empty sort blocks, since they cannot be passed to heap.Init.
 	src := sbh
 	sbh = sbh[:0]
@@ -532,8 +533,7 @@ func mergeSortBlocks(dst *Result, sbh sortBlocksHeap) {
 			putSortBlock(top)
 		}
 	}
-
-	timestamps, values := storage.DeduplicateSamples(dst.Timestamps, dst.Values)
+	timestamps, values := storage.DeduplicateSamples(dst.Timestamps, dst.Values, dedupInterval)
 	dedups := len(dst.Timestamps) - len(timestamps)
 	dedupsDuringSelect.Add(dedups)
 	dst.Timestamps = timestamps
diff --git a/app/vmselect/prometheus/prometheus.go b/app/vmselect/prometheus/prometheus.go
index a913ead1e..20b46e677 100644
--- a/app/vmselect/prometheus/prometheus.go
+++ b/app/vmselect/prometheus/prometheus.go
@@ -129,6 +129,7 @@ func ExportCSVHandler(startTime time.Time, w http.ResponseWriter, r *http.Reques
 	if err != nil {
 		return err
 	}
+	reduceMemUsage := searchutils.GetBool(r, "reduce_mem_usage")
 	deadline := searchutils.GetDeadlineForExport(r, startTime)
 	tagFilterss, err := getTagFilterssFromRequest(r)
 	if err != nil {
@@ -140,30 +141,58 @@ func ExportCSVHandler(startTime time.Time, w http.ResponseWriter, r *http.Reques
 	defer bufferedwriter.Put(bw)
 
 	resultsCh := make(chan *quicktemplate.ByteBuffer, cgroup.AvailableCPUs())
-	doneCh := make(chan error)
-	go func() {
-		err := netstorage.ExportBlocks(sq, deadline, func(mn *storage.MetricName, b *storage.Block, tr storage.TimeRange) error {
-			if err := bw.Error(); err != nil {
-				return err
-			}
-			if err := b.UnmarshalData(); err != nil {
-				return fmt.Errorf("cannot unmarshal block during export: %s", err)
-			}
-			xb := exportBlockPool.Get().(*exportBlock)
-			xb.mn = mn
-			xb.timestamps, xb.values = b.AppendRowsWithTimeRangeFilter(xb.timestamps[:0], xb.values[:0], tr)
-			if len(xb.timestamps) > 0 {
-				bb := quicktemplate.AcquireByteBuffer()
-				WriteExportCSVLine(bb, xb, fieldNames)
-				resultsCh <- bb
-			}
-			xb.reset()
-			exportBlockPool.Put(xb)
-			return nil
-		})
-		close(resultsCh)
-		doneCh <- err
-	}()
+	writeCSVLine := func(xb *exportBlock) {
+		if len(xb.timestamps) == 0 {
+			return
+		}
+		bb := quicktemplate.AcquireByteBuffer()
+		WriteExportCSVLine(bb, xb, fieldNames)
+		resultsCh <- bb
+	}
+	doneCh := make(chan error, 1)
+	if !reduceMemUsage {
+		rss, err := netstorage.ProcessSearchQuery(sq, true, deadline)
+		if err != nil {
+			return fmt.Errorf("cannot fetch data for %q: %w", sq, err)
+		}
+		go func() {
+			err := rss.RunParallel(func(rs *netstorage.Result, workerID uint) error {
+				if err := bw.Error(); err != nil {
+					return err
+				}
+				xb := exportBlockPool.Get().(*exportBlock)
+				xb.mn = &rs.MetricName
+				xb.timestamps = rs.Timestamps
+				xb.values = rs.Values
+				writeCSVLine(xb)
+				xb.reset()
+				exportBlockPool.Put(xb)
+				return nil
+			})
+			close(resultsCh)
+			doneCh <- err
+		}()
+	} else {
+		go func() {
+			err := netstorage.ExportBlocks(sq, deadline, func(mn *storage.MetricName, b *storage.Block, tr storage.TimeRange) error {
+				if err := bw.Error(); err != nil {
+					return err
+				}
+				if err := b.UnmarshalData(); err != nil {
+					return fmt.Errorf("cannot unmarshal block during export: %s", err)
+				}
+				xb := exportBlockPool.Get().(*exportBlock)
+				xb.mn = mn
+				xb.timestamps, xb.values = b.AppendRowsWithTimeRangeFilter(xb.timestamps[:0], xb.values[:0], tr)
+				writeCSVLine(xb)
+				xb.reset()
+				exportBlockPool.Put(xb)
+				return nil
+			})
+			close(resultsCh)
+			doneCh <- err
+		}()
+	}
 	// Consume all the data from resultsCh.
 	for bb := range resultsCh {
 		// Do not check for error in bw.Write, since this error is checked inside netstorage.ExportBlocks above.
@@ -360,7 +389,7 @@ func exportHandler(w http.ResponseWriter, matches []string, etfs [][]storage.Tag
 	defer bufferedwriter.Put(bw)
 
 	resultsCh := make(chan *quicktemplate.ByteBuffer, cgroup.AvailableCPUs())
-	doneCh := make(chan error)
+	doneCh := make(chan error, 1)
 	if !reduceMemUsage {
 		rss, err := netstorage.ProcessSearchQuery(sq, true, deadline)
 		if err != nil {
diff --git a/app/vmselect/promql/rollup.go b/app/vmselect/promql/rollup.go
index 2ef33f6e4..4d2c653a1 100644
--- a/app/vmselect/promql/rollup.go
+++ b/app/vmselect/promql/rollup.go
@@ -82,11 +82,12 @@ var rollupFuncs = map[string]newRollupFunc{
 	// `timestamp` function must return timestamp for the last datapoint on the current window
 	// in order to properly handle offset and timestamps unaligned to the current step.
 	// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/415 for details.
-	"timestamp":        newRollupFuncOneArg(rollupTlast),
-	"tlast_over_time":  newRollupFuncOneArg(rollupTlast),
-	"tmax_over_time":   newRollupFuncOneArg(rollupTmax),
-	"tmin_over_time":   newRollupFuncOneArg(rollupTmin),
-	"zscore_over_time": newRollupFuncOneArg(rollupZScoreOverTime),
+	"timestamp":           newRollupFuncOneArg(rollupTlast),
+	"timestamp_with_name": newRollupFuncOneArg(rollupTlast), // + rollupFuncsKeepMetricGroup
+	"tlast_over_time":     newRollupFuncOneArg(rollupTlast),
+	"tmax_over_time":      newRollupFuncOneArg(rollupTmax),
+	"tmin_over_time":      newRollupFuncOneArg(rollupTmin),
+	"zscore_over_time":    newRollupFuncOneArg(rollupZScoreOverTime),
 }
 
 // rollupAggrFuncs are functions that can be passed to `aggr_over_time()`
@@ -130,6 +131,7 @@ var rollupAggrFuncs = map[string]rollupFunc{
 	"sum2_over_time":      rollupSum2,
 	"tfirst_over_time":    rollupTfirst,
 	"timestamp":           rollupTlast,
+	"timestamp_with_name": rollupTlast,
 	"tlast_over_time":     rollupTlast,
 	"tmax_over_time":      rollupTmax,
 	"tmin_over_time":      rollupTmin,
@@ -186,6 +188,7 @@ var rollupFuncsKeepMetricGroup = map[string]bool{
 	"quantiles_over_time":   true,
 	"rollup":                true,
 	"rollup_candlestick":    true,
+	"timestamp_with_name":   true,
 }
 
 func getRollupAggrFuncNames(expr metricsql.Expr) ([]string, error) {
diff --git a/app/vmselect/vmui/asset-manifest.json b/app/vmselect/vmui/asset-manifest.json
index 42c3a7471..1594d5e04 100644
--- a/app/vmselect/vmui/asset-manifest.json
+++ b/app/vmselect/vmui/asset-manifest.json
@@ -1,7 +1,7 @@
 {
   "files": {
     "main.css": "./static/css/main.83d9ae2d.chunk.css",
-    "main.js": "./static/js/main.6651c49c.chunk.js",
+    "main.js": "./static/js/main.fa15a895.chunk.js",
     "runtime-main.js": "./static/js/runtime-main.c4b656b8.js",
     "static/css/2.77671664.chunk.css": "./static/css/2.77671664.chunk.css",
     "static/js/2.ef1db8c8.chunk.js": "./static/js/2.ef1db8c8.chunk.js",
@@ -14,6 +14,6 @@
     "static/css/2.77671664.chunk.css",
     "static/js/2.ef1db8c8.chunk.js",
     "static/css/main.83d9ae2d.chunk.css",
-    "static/js/main.6651c49c.chunk.js"
+    "static/js/main.fa15a895.chunk.js"
   ]
 }
\ No newline at end of file
diff --git a/app/vmselect/vmui/index.html b/app/vmselect/vmui/index.html
index 8f87d479f..7bb01b38b 100644
--- a/app/vmselect/vmui/index.html
+++ b/app/vmselect/vmui/index.html
@@ -1,1 +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"/><link href="./static/css/2.77671664.chunk.css" rel="stylesheet"><link href="./static/css/main.83d9ae2d.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,i,a=r[0],c=r[1],l=r[2],s=0,p=[];s<a.length;s++)i=a[s],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&p.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(f&&f(r);p.length;)p.shift()();return u.push.apply(u,l||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,a=1;a<t.length;a++){var c=t[a];0!==o[c]&&(n=!1)}n&&(u.splice(r--,1),e=i(i.s=t[0]))}return e}var n={},o={1:0},u=[];function i(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,i),t.l=!0,t.exports}i.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise((function(r,n){t=o[e]=[r,n]}));r.push(t[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+"static/js/"+({}[e]||e)+"."+{3:"65648506"}[e]+".chunk.js"}(e);var c=new Error;u=function(r){a.onerror=a.onload=null,clearTimeout(l);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:a})}),12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(r)},i.m=e,i.c=n,i.d=function(e,r,t){i.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,r){if(1&r&&(e=i(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(i.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)i.d(t,n,function(r){return e[r]}.bind(null,n));return t},i.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(r,"a",r),r},i.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},i.p="./",i.oe=function(e){throw console.error(e),e};var a=this.webpackJsonpvmui=this.webpackJsonpvmui||[],c=a.push.bind(a);a.push=r,a=a.slice();for(var l=0;l<a.length;l++)r(a[l]);var f=c;t()}([])</script><script src="./static/js/2.ef1db8c8.chunk.js"></script><script src="./static/js/main.6651c49c.chunk.js"></script></body></html>
\ No newline at end of file
+<!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"/><link href="./static/css/2.77671664.chunk.css" rel="stylesheet"><link href="./static/css/main.83d9ae2d.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,i,a=r[0],c=r[1],l=r[2],s=0,p=[];s<a.length;s++)i=a[s],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&p.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(f&&f(r);p.length;)p.shift()();return u.push.apply(u,l||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,a=1;a<t.length;a++){var c=t[a];0!==o[c]&&(n=!1)}n&&(u.splice(r--,1),e=i(i.s=t[0]))}return e}var n={},o={1:0},u=[];function i(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,i),t.l=!0,t.exports}i.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise((function(r,n){t=o[e]=[r,n]}));r.push(t[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+"static/js/"+({}[e]||e)+"."+{3:"65648506"}[e]+".chunk.js"}(e);var c=new Error;u=function(r){a.onerror=a.onload=null,clearTimeout(l);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:a})}),12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(r)},i.m=e,i.c=n,i.d=function(e,r,t){i.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,r){if(1&r&&(e=i(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(i.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)i.d(t,n,function(r){return e[r]}.bind(null,n));return t},i.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(r,"a",r),r},i.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},i.p="./",i.oe=function(e){throw console.error(e),e};var a=this.webpackJsonpvmui=this.webpackJsonpvmui||[],c=a.push.bind(a);a.push=r,a=a.slice();for(var l=0;l<a.length;l++)r(a[l]);var f=c;t()}([])</script><script src="./static/js/2.ef1db8c8.chunk.js"></script><script src="./static/js/main.fa15a895.chunk.js"></script></body></html>
\ No newline at end of file
diff --git a/app/vmselect/vmui/static/js/main.6651c49c.chunk.js b/app/vmselect/vmui/static/js/main.fa15a895.chunk.js
similarity index 66%
rename from app/vmselect/vmui/static/js/main.6651c49c.chunk.js
rename to app/vmselect/vmui/static/js/main.fa15a895.chunk.js
index 07cf76c1e..ce99f8783 100644
--- a/app/vmselect/vmui/static/js/main.6651c49c.chunk.js
+++ b/app/vmselect/vmui/static/js/main.fa15a895.chunk.js
@@ -1,1 +1,1 @@
-(this.webpackJsonpvmui=this.webpackJsonpvmui||[]).push([[0],{204:function(e,t,n){},219:function(e,t){},223:function(e,t,n){},224:function(e,t,n){},234:function(e,t,n){"use strict";n.r(t);var a=n(1),r=n.n(a),c=n(53),i=n.n(c),o=(n(204),n(9)),s=n(318),l=n(317),u=n(0),d=Object(a.createContext)({showInfoMessage:function(){}}),j=function(e){var t=e.children,n=Object(a.useState)({}),r=Object(o.a)(n,2),c=r[0],i=r[1],j=Object(a.useState)(!1),b=Object(o.a)(j,2),O=b[0],p=b[1],h=Object(a.useState)(void 0),f=Object(o.a)(h,2),x=f[0],v=f[1];Object(a.useEffect)((function(){x&&(i({message:x,key:(new Date).getTime()}),p(!0))}),[x]);return Object(u.jsxs)(d.Provider,{value:{showInfoMessage:v},children:[Object(u.jsx)(s.a,{open:O,autoHideDuration:4e3,onClose:function(e,t){"clickaway"!==t&&(v(void 0),p(!1))},children:Object(u.jsx)(l.a,{children:c.message})},c.key),t]})},b=n(352),O=n(353),p=n(328),h=n(246),f=n(344),x=n(242),v=n(329),m=n(331),y=n(323),g=n(327),S=n(149),E=n.n(S),_=n(3),T=n(16),w=n(40),C=n.n(w),A=n(145),R=n.n(A),I=n(146),k=n.n(I),U=n(105),M=n.n(U);C.a.extend(R.a),C.a.extend(k.a);var H,D=window.innerWidth/2,N=1,L=1578e8,P="YYYY-MM-DD[T]HH:mm:ss",q=[{long:"days",short:"d",possible:"day"},{long:"weeks",short:"w",possible:"week"},{long:"months",short:"M",possible:"mon"},{long:"years",short:"y",possible:"year"},{long:"hours",short:"h",possible:"hour"},{long:"minutes",short:"m",possible:"min"},{long:"seconds",short:"s",possible:"sec"},{long:"milliseconds",short:"ms",possible:"millisecond"}],Y=q.map((function(e){return e.short})),B=function(e){return+M()(e).format("0.000")},F=function(e){var t=e.match(/\d+/g),n=e.match(/[a-zA-Z]+/g);if(n&&t&&Y.includes(n[0]))return Object(_.a)({},n[0],t[0])},Q=function(e,t){var n=(t||new Date).valueOf()/1e3,a=e.trim().split(" ").reduce((function(e,t){var n=F(t);return n?Object(T.a)(Object(T.a)({},e),n):Object(T.a)({},e)}),{}),r=C.a.duration(a).asSeconds();return{start:n-r,end:n,step:B(r/D)||.001,date:z(t||new Date)}},z=function(e){return C()(e).utc().format(P)},G=function(e){var t=Math.floor(e%1e3),n=Math.floor(e/1e3%60),a=Math.floor(e/1e3/60%60),r=Math.floor(e/1e3/3600%24),c=Math.floor(e/864e5),i=["d","h","m","s","ms"];return[c,r,a,n,t].map((function(e,t){return e?"".concat(e).concat(i[t]):""})).filter((function(e){return e})).join(" ")},W=function(e){return new Date(1e3*e)},V=function(e,t){t?window.localStorage.setItem(e,JSON.stringify({value:t})):K([e])},J=function(e){var t=window.localStorage.getItem(e);if(null!==t)try{var n;return null===(n=JSON.parse(t))||void 0===n?void 0:n.value}catch(a){return t}},K=function(e){return e.forEach((function(e){return window.localStorage.removeItem(e)}))},X=["BASIC_AUTH_DATA","BEARER_AUTH_DATA"],Z=n(147),$=n.n(Z),ee=n(117),te=n.n(ee),ne={"time.duration":"range_input","time.period.date":"end_input","time.period.step":"step_input",displayType:"tab"},ae=function(e){var t=new Map(Object.entries(ne)),n=te()(e,"query",""),a=[];n.forEach((function(n,r){t.forEach((function(t,n){var c=te()(e,n,"");if(c){var i=encodeURIComponent(c);a.push("g".concat(r,".").concat(t,"=").concat(i))}})),a.push("g".concat(r,".expr=").concat(n))})),function(e){var t=window;if(t){var n="".concat(t.location.protocol,"//").concat(t.location.host).concat(t.location.pathname,"?").concat(e);t.history.pushState({path:n},"",n)}}(a.join("&"))},re=function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:window.location.search,a=$.a.parse(n,{ignoreQueryPrefix:!0});return te()(a,e,t||"")},ce=re("g0.range_input","1h"),ie=(H=re("g0.end_input",new Date(C()().utc().format(P))),C()(H).utcOffset(0,!0).local().format(P)),oe=function(){var e,t=(null===(e=window.location.search.match(/g\d+.expr/gim))||void 0===e?void 0:e.length)||1;return new Array(t).fill(1).map((function(e,t){return re("g".concat(t,".expr"),"")}))}(),se={serverUrl:window.location.href.replace(/\/(?:prometheus\/)?(?:graph|vmui)\/.*/,"/prometheus/"),displayType:re("tab","chart"),query:oe,queryHistory:oe.map((function(e){return{index:0,values:[e]}})),time:{duration:ce,period:Q(ce,new Date(ie))},queryControls:{autoRefresh:!1,autocomplete:J("AUTOCOMPLETE")||!1,nocache:J("NO_CACHE")||!1}};function le(e,t){switch(t.type){case"SET_DISPLAY_TYPE":return Object(T.a)(Object(T.a)({},e),{},{displayType:t.payload});case"SET_SERVER":return Object(T.a)(Object(T.a)({},e),{},{serverUrl:t.payload});case"SET_QUERY":return Object(T.a)(Object(T.a)({},e),{},{query:t.payload});case"SET_QUERY_HISTORY":return Object(T.a)(Object(T.a)({},e),{},{queryHistory:t.payload});case"SET_QUERY_HISTORY_BY_INDEX":return e.queryHistory.splice(t.payload.queryNumber,1,t.payload.value),Object(T.a)(Object(T.a)({},e),{},{queryHistory:e.queryHistory});case"SET_DURATION":return Object(T.a)(Object(T.a)({},e),{},{time:Object(T.a)(Object(T.a)({},e.time),{},{duration:t.payload,period:Q(t.payload,W(e.time.period.end))})});case"SET_UNTIL":return Object(T.a)(Object(T.a)({},e),{},{time:Object(T.a)(Object(T.a)({},e.time),{},{period:Q(e.time.duration,t.payload)})});case"SET_PERIOD":var n=function(e){var t=e.to.valueOf()-e.from.valueOf();return G(t)}(t.payload);return Object(T.a)(Object(T.a)({},e),{},{queryControls:Object(T.a)(Object(T.a)({},e.queryControls),{},{autoRefresh:!1}),time:Object(T.a)(Object(T.a)({},e.time),{},{duration:n,period:Q(n,t.payload.to)})});case"TOGGLE_AUTOREFRESH":return Object(T.a)(Object(T.a)({},e),{},{queryControls:Object(T.a)(Object(T.a)({},e.queryControls),{},{autoRefresh:!e.queryControls.autoRefresh})});case"TOGGLE_AUTOCOMPLETE":return Object(T.a)(Object(T.a)({},e),{},{queryControls:Object(T.a)(Object(T.a)({},e.queryControls),{},{autocomplete:!e.queryControls.autocomplete})});case"NO_CACHE":return Object(T.a)(Object(T.a)({},e),{},{queryControls:Object(T.a)(Object(T.a)({},e.queryControls),{},{nocache:!e.queryControls.nocache})});case"RUN_QUERY":return Object(T.a)(Object(T.a)({},e),{},{time:Object(T.a)(Object(T.a)({},e.time),{},{period:Q(e.time.duration,W(e.time.period.end))})});case"RUN_QUERY_TO_NOW":return Object(T.a)(Object(T.a)({},e),{},{time:Object(T.a)(Object(T.a)({},e.time),{},{period:Q(e.time.duration)})});default:throw new Error}}var ue=Object(a.createContext)({}),de=function(){return Object(a.useContext)(ue).state},je=function(){return Object(a.useContext)(ue).dispatch},be=Object.entries(se).reduce((function(e,t){var n=Object(o.a)(t,2),a=n[0],r=n[1];return Object(T.a)(Object(T.a)({},e),{},Object(_.a)({},a,re(a)||r))}),{}),Oe=function(e){var t=e.children,n=Object(a.useReducer)(le,be),r=Object(o.a)(n,2),c=r[0],i=r[1];Object(a.useEffect)((function(){ae(c)}),[c]);var s=Object(a.useMemo)((function(){return{state:c,dispatch:i}}),[c,i]);return Object(u.jsx)(ue.Provider,{value:s,children:t})},pe=function(e){return Object(u.jsxs)(p.a,{position:"relative",display:"inline-flex",children:[Object(u.jsx)(v.a,Object(T.a)({variant:"determinate"},e)),Object(u.jsx)(p.a,{top:0,left:0,bottom:0,right:0,position:"absolute",display:"flex",alignItems:"center",justifyContent:"center",children:Object(u.jsx)(h.a,{variant:"caption",component:"div",children:"".concat(e.label,"s")})})]})},he=n(314),fe=n(10),xe=n(330),ve=Object(fe.a)(xe.a)((function(){return{padding:10,"& .MuiSwitch-track":{borderRadius:14,"&:before, &:after":{content:'""',position:"absolute",top:"50%",transform:"translateY(-50%)",width:14,height:14}},"& .MuiSwitch-thumb":{boxShadow:"none",width:12,height:12,margin:4}}})),me=Object(he.a)({colorizing:{color:"white"}}),ye=function(){var e=me(),t=je(),n=de().queryControls.autoRefresh,c=Object(a.useState)(5),i=Object(o.a)(c,2),s=i[0],l=i[1],d=Object(a.useState)(),j=Object(o.a)(d,2),b=j[0],O=j[1],h=r.a.useState(100),f=Object(o.a)(h,2),x=f[0],v=f[1];Object(a.useEffect)((function(){var e;return n&&(O((new Date).valueOf()),e=setInterval((function(){O((new Date).valueOf()),t({type:"RUN_QUERY_TO_NOW"})}),1e3*s)),function(){e&&clearInterval(e)}}),[s,n]),Object(a.useEffect)((function(){var e=setInterval((function(){if(n&&b){var e=((new Date).valueOf()-b)/1e3,t=Math.floor(e/s*100);v(t)}}),16);return function(){clearInterval(e)}}),[n,b,s]);var S=function(){l((function(e){switch(e){case 1:return 2;default:return 5;case 5:return 1}}))};return Object(u.jsxs)(p.a,{display:"flex",alignItems:"center",children:[Object(u.jsx)(m.a,{control:Object(u.jsx)(ve,{className:e.colorizing,checked:n,onChange:function(){t({type:"TOGGLE_AUTOREFRESH"})}}),label:"Auto-refresh"}),n&&Object(u.jsxs)(u.Fragment,{children:[Object(u.jsx)(pe,{className:e.colorizing,label:s,value:x,onClick:function(){S()}}),Object(u.jsx)(y.a,{title:"Change delay refresh",children:Object(u.jsx)(p.a,{ml:1,children:Object(u.jsx)(g.a,{onClick:function(){S()},children:Object(u.jsx)(E.a,{style:{color:"white"}})})})})]})]})},ge=n(152),Se=n.n(ge),Ee=n(150),_e=n.n(Ee),Te=n(151),we=n.n(Te),Ce=n(333),Ae=n(324),Re=n(332),Ie=Object(Re.a)({root:{display:"grid",gridTemplateColumns:"18px auto",gridGap:6,padding:"8px 12px",color:"white",lineHeight:"19px","&.Mui-selected":{color:"white"}}})(Ce.a),ke=function(){var e=de().displayType,t=je();return Object(u.jsxs)(Ae.a,{value:e,exclusive:!0,onChange:function(n,a){return t({type:"SET_DISPLAY_TYPE",payload:null!==a&&void 0!==a?a:e})},children:[Object(u.jsxs)(Ie,{value:"chart","aria-label":"display as chart",children:[Object(u.jsx)(_e.a,{}),Object(u.jsx)("span",{children:"Query Range as Chart"})]}),Object(u.jsxs)(Ie,{value:"code","aria-label":"display as code",children:[Object(u.jsx)(we.a,{}),Object(u.jsx)("span",{children:"Instant Query as JSON"})]}),Object(u.jsxs)(Ie,{value:"table","aria-label":"display as table",children:[Object(u.jsx)(Se.a,{}),Object(u.jsx)("span",{children:"Instant Query as Table"})]})]})},Ue=n(21),Me=n(153),He={customStep:{enable:!1,value:1},yaxis:{limits:{enable:!1,range:{1:[0,0]}}}};function De(e,t){switch(t.type){case"TOGGLE_ENABLE_YAXIS_LIMITS":return Object(T.a)(Object(T.a)({},e),{},{yaxis:Object(T.a)(Object(T.a)({},e.yaxis),{},{limits:Object(T.a)(Object(T.a)({},e.yaxis.limits),{},{enable:!e.yaxis.limits.enable})})});case"TOGGLE_CUSTOM_STEP":return Object(T.a)(Object(T.a)({},e),{},{customStep:Object(T.a)(Object(T.a)({},e.customStep),{},{enable:!e.customStep.enable})});case"SET_CUSTOM_STEP":return Object(T.a)(Object(T.a)({},e),{},{customStep:Object(T.a)(Object(T.a)({},e.customStep),{},{value:t.payload})});case"SET_YAXIS_LIMITS":return Object(T.a)(Object(T.a)({},e),{},{yaxis:Object(T.a)(Object(T.a)({},e.yaxis),{},{limits:Object(T.a)(Object(T.a)({},e.yaxis.limits),{},{range:t.payload})})});default:throw new Error}}var Ne,Le=Object(a.createContext)({}),Pe=function(){return Object(a.useContext)(Le).state},qe=function(){return Object(a.useContext)(Le).dispatch},Ye=function(e){var t=e.children,n=Object(a.useReducer)(De,He),r=Object(o.a)(n,2),c=r[0],i=r[1],s=Object(a.useMemo)((function(){return{state:c,dispatch:i}}),[c,i]);return Object(u.jsx)(Le.Provider,{value:s,children:t})},Be=function(e){if(7!=e.length)return"0, 0, 0";var t=parseInt(e.slice(1,3),16),n=parseInt(e.slice(3,5),16),a=parseInt(e.slice(5,7),16);return"".concat(t,", ").concat(n,", ").concat(a)},Fe={height:500,legend:{show:!1},cursor:{drag:{x:!1,y:!1},focus:{prox:30},bind:{mouseup:function(){return null},mousedown:function(){return null},click:function(){return null},dblclick:function(){return null},mouseenter:function(){return null}}}},Qe=function(e,t){return t.map((function(e){return e>1e3?M()(e).format("0.0a"):e}))},ze=function(e,t){return function(e){for(var t=0,n=0;n<e.length;n++)t=e.charCodeAt(n)+((t<<5)-t);for(var a="#",r=0;r<3;r++)a+=("00"+(t>>8*r&255).toString(16)).substr(-2);return a}("".concat(e).concat(t))},Ge=function(e){return e<=1?[]:[4*e,1.2*e]},We=function(e){for(var t=e.length,n=-1/0;t--;)e[t]>n&&(n=e[t]);return n},Ve=function(e){for(var t=e.length,n=1/0;t--;)e[t]<n&&(n=e[t]);return n},Je=function(e){return Array.from(new Set(e.map((function(e){return e.scale})))).map((function(e){var t={scale:e,show:!0,font:"10px Arial",values:Qe};return e?Number(e)%2?t:Object(T.a)(Object(T.a)({},t),{},{side:1}):{space:80}}))},Ke=function(e){var t,n,a=e.u,r=e.tooltipIdx,c=e.metrics,i=e.series,o=e.tooltip,s=e.tooltipOffset,l=r.seriesIdx,u=r.dataIdx,d=a.data[l][u],j=a.data[0][u],b=(null===(t=c[l-1])||void 0===t?void 0:t.metric)||{},O=ze(Number(i[l].scale||0),i[l].label||""),p=a.over.getBoundingClientRect(),h=p.width,f=p.height,x=a.valToPos(d||0,(null===(n=i[l])||void 0===n?void 0:n.scale)||"1"),v=a.valToPos(j,"x"),m=o.getBoundingClientRect(),y=m.width,g=m.height,S=v+y>=h,E=x+g>=f;o.style.display="grid",o.style.top="".concat(s.top+x+10-(E?g+10:0),"px"),o.style.left="".concat(s.left+v+10-(S?y+20:0),"px");var _=C()(new Date(1e3*j)).format("YYYY-MM-DD HH:mm:ss:SSS (Z)"),T=Object.keys(b).filter((function(e){return"__name__"!==e})).map((function(e){return"<div><b>".concat(e,"</b>: ").concat(b[e],"</div>")})).join(""),w='<div class="u-tooltip__marker" style="background: '.concat(O,'"></div>');o.innerHTML="<div>".concat(_,'</div>\n                       <div class="u-tooltip-data">\n                         ').concat(w).concat(b.__name__||"",': <b class="u-tooltip-data__value">').concat(d,'</b>\n                       </div>\n                       <div class="u-tooltip__info">').concat(T,"</div>")},Xe=n(154),Ze=n.n(Xe);n(222),n(223);!function(e){e.xRange="xRange",e.yRange="yRange",e.data="data"}(Ne||(Ne={}));var $e,et=function(e){var t=e.data,n=e.series,r=e.metrics,c=void 0===r?[]:r,i=e.limits,s=je(),l=de().time.period,d=Pe().yaxis,j=Object(a.useRef)(null),b=Object(a.useRef)(null),O=Object(a.useState)(!1),p=Object(o.a)(O,2),h=p[0],f=p[1],x=Object(a.useState)({min:l.start,max:l.end}),v=Object(o.a)(x,2),m=v[0],y=v[1],g=Object(a.useState)(),S=Object(o.a)(g,2),E=S[0],_=S[1],w=document.createElement("div");w.className="u-tooltip";var C={seriesIdx:1,dataIdx:0},A={left:0,top:0},R=Object(a.useCallback)(Ze()((function(e){var t=e.min,n=e.max;s({type:"SET_PERIOD",payload:{from:new Date(1e3*t),to:new Date(1e3*n)}})}),500),[]),I=function(e){var t=e.u,n=e.min,a=e.max,r=1e3*(a-n);r<N||r>L||(t.setScale("x",{min:n,max:a}),y({min:n,max:a}),R({min:n,max:a}))},k=function(){return[m.min,m.max]},U=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1,a=arguments.length>3?arguments[3]:void 0;return d.limits.enable?d.limits.range[a]:t&&n?[t-.05*t,n+.05*n]:i[a]},M=Object(T.a)(Object(T.a)({},Fe),{},{series:n,axes:Je(n),scales:Object(T.a)({},function(){var e={x:{range:k}};return Object.keys(d.limits.range).forEach((function(t){e[t]={range:function(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;return U(e,n,a,t)}}})),e}()),width:j.current?j.current.offsetWidth:400,plugins:[{hooks:{ready:function(e){var t,n=.85;A.left=parseFloat(e.over.style.left),A.top=parseFloat(e.over.style.top),null===(t=e.root.querySelector(".u-wrap"))||void 0===t||t.appendChild(w),e.over.addEventListener("mousedown",(function(t){return function(e){var t=e.e,n=e.factor,a=void 0===n?.85:n,r=e.u,c=e.setPanning,i=e.setPlotScale;if(0===t.button){t.preventDefault(),c(!0);var o=t.clientX,s=r.posToVal(1,"x")-r.posToVal(0,"x"),l=r.scales.x.min||0,u=r.scales.x.max||0,d=function(e){e.preventDefault();var t=s*((e.clientX-o)*a);i({u:r,min:l-t,max:u-t})};document.addEventListener("mousemove",d),document.addEventListener("mouseup",(function e(){c(!1),document.removeEventListener("mousemove",d),document.removeEventListener("mouseup",e)}))}}({u:e,e:t,setPanning:f,setPlotScale:I,factor:n})})),e.over.addEventListener("wheel",(function(t){if(t.ctrlKey||t.metaKey){t.preventDefault();var a=e.over.getBoundingClientRect().width,r=e.cursor.left&&e.cursor.left>0?e.cursor.left:0,c=e.posToVal(r,"x"),i=(e.scales.x.max||0)-(e.scales.x.min||0),o=t.deltaY<0?i*n:i/n,s=c-r/a*o,l=s+o;e.batch((function(){return I({u:e,min:s,max:l})}))}}))},setCursor:function(e){C.dataIdx!==e.cursor.idx&&(C.dataIdx=e.cursor.idx||0,C.seriesIdx&&C.dataIdx&&Ke({u:e,tooltipIdx:C,metrics:c,series:n,tooltip:w,tooltipOffset:A}))},setSeries:function(e,t){C.seriesIdx!==t&&(C.seriesIdx=t||0,t&&C.dataIdx?Ke({u:e,tooltipIdx:C,metrics:c,series:n,tooltip:w,tooltipOffset:A}):w.style.display="none")}}}]}),H=function(e){if(E){switch(e){case Ne.xRange:E.scales.x.range=k;break;case Ne.yRange:Object.keys(d.limits.range).forEach((function(e){E.scales[e]&&(E.scales[e].range=function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;return U(t,n,a,e)})}));break;case Ne.data:E.setData(t)}E.redraw()}};return Object(a.useEffect)((function(){return y({min:l.start,max:l.end})}),[l]),Object(a.useEffect)((function(){if(b.current){var e=new Me.a(M,t,b.current);return _(e),y({min:l.start,max:l.end}),e.destroy}}),[b.current,n]),Object(a.useEffect)((function(){return H(Ne.data)}),[t]),Object(a.useEffect)((function(){return H(Ne.xRange)}),[m]),Object(a.useEffect)((function(){return H(Ne.yRange)}),[d]),Object(u.jsx)("div",{ref:j,style:{pointerEvents:h?"none":"auto",height:"500px"},children:Object(u.jsx)("div",{ref:b})})},tt=(n(224),function(e){var t=e.labels,n=e.onChange,r=de().query,c=Object(a.useMemo)((function(){return Array.from(new Set(t.map((function(e){return e.group}))))}),[t]);return Object(u.jsx)("div",{className:"legendWrapper",children:c.map((function(e){return Object(u.jsxs)("div",{className:"legendGroup",children:[Object(u.jsxs)("div",{className:"legendGroupTitle",children:[Object(u.jsx)("svg",{className:"legendGroupLine",width:"33",height:"3",version:"1.1",xmlns:"http://www.w3.org/2000/svg",children:Object(u.jsx)("line",{strokeWidth:"3",x1:"0",y1:"0",x2:"33",y2:"0",stroke:"#363636",strokeDasharray:Ge(e).join(",")})}),Object(u.jsxs)("b",{children:['"',r[e-1],'"']}),":"]}),Object(u.jsx)("div",{children:t.filter((function(t){return t.group===e})).map((function(e){return Object(u.jsxs)("div",{className:e.checked?"legendItem":"legendItem legendItemHide",onClick:function(t){return n(e,t.ctrlKey||t.metaKey)},children:[Object(u.jsx)("div",{className:"legendMarker",style:{borderColor:e.color,backgroundColor:"rgba(".concat(Be(e.color),", 0.1)")}}),Object(u.jsx)("div",{className:"legendLabel",children:e.label})]},"".concat(e.group,".").concat(e.label))}))})]},e)}))})}),nt=n(115),at=["__name__"],rt=function(e,t){var n=function(e){if(0===Object.keys(e.metric).length)return"Query result";var t=e.metric,n=t.__name__,a=Object(nt.a)(t,at);return"".concat(n||""," {").concat(Object.entries(a).map((function(e){return"".concat(e[0],": ").concat(e[1])})).join(", "),"}")}(e);return{label:n,dash:Ge(e.group),width:1.5,stroke:ze(e.group,n),show:!it(n,e.group,t),scale:String(e.group)}},ct=function(e,t){return{group:t,label:e.label||"",color:e.stroke,checked:e.show||!1}},it=function(e,t,n){return n.includes("".concat(t,".").concat(e))},ot=n(156),st=n.n(ot),lt=n(315),ut=n(106),dt=n.n(ut),jt=function(){var e=Pe().yaxis,t=qe(),n=Object(a.useMemo)((function(){return Object.keys(e.limits.range)}),[e.limits.range]),r=Object(a.useCallback)(dt()((function(n,a,r){var c=e.limits.range;c[a][r]=+n.target.value,t({type:"SET_YAXIS_LIMITS",payload:c})}),500),[e.limits.range]);return Object(u.jsxs)(p.a,{display:"grid",alignItems:"center",gap:2,children:[Object(u.jsx)(m.a,{control:Object(u.jsx)(ve,{checked:e.limits.enable,onChange:function(){t({type:"TOGGLE_ENABLE_YAXIS_LIMITS"})}}),label:"Fix the limits for y-axis"}),Object(u.jsx)(p.a,{display:"grid",alignItems:"center",gap:2,children:n.map((function(t){return Object(u.jsxs)(p.a,{display:"grid",gridTemplateColumns:"120px 120px",gap:1,children:[Object(u.jsx)(lt.a,{label:"Min ".concat(t),type:"number",size:"small",variant:"outlined",disabled:!e.limits.enable,defaultValue:e.limits.range[t][0],onChange:function(e){return r(e,t,0)}}),Object(u.jsx)(lt.a,{label:"Max ".concat(t),type:"number",size:"small",variant:"outlined",disabled:!e.limits.enable,defaultValue:e.limits.range[t][1],onChange:function(e){return r(e,t,1)}})]},t)}))})]})},bt=n(325),Ot=n(178),pt=n(155),ht=n.n(pt),ft=n(157),xt=n.n(ft),vt=Object(he.a)({popover:{position:"absolute",display:"grid",gridGap:"16px",padding:"0 0 25px",zIndex:2},popoverHeader:{display:"flex",alignItems:"center",justifyContent:"space-between",background:"#3F51B5",padding:"6px 6px 6px 12px",borderRadius:"4px 4px 0 0",color:"#FFF",cursor:"move"},popoverBody:{display:"grid",gridGap:"6px",padding:"0 14px"}}),mt=function(){var e=Object(a.useState)(!1),t=Object(o.a)(e,2),n=t[0],r=t[1],c=Object(a.useRef)(null),i=vt();return Object(u.jsxs)(p.a,{display:"flex",px:2,children:[Object(u.jsxs)(bt.a,{onClick:function(){return r((function(e){return!e}))},variant:"outlined",children:[Object(u.jsx)(st.a,{sx:{fontSize:16,marginRight:"4px"}}),Object(u.jsxs)("span",{style:{lineHeight:1,paddingTop:"1px"},children:[n?"Hide":"Show"," graph settings"]})]}),n&&Object(u.jsx)(ht.a,{nodeRef:c,defaultPosition:{x:173,y:0},handle:"#handle",children:Object(u.jsxs)(Ot.a,{elevation:3,className:i.popover,ref:c,children:[Object(u.jsxs)("div",{id:"handle",className:i.popoverHeader,children:[Object(u.jsx)(h.a,{variant:"body1",children:Object(u.jsx)("b",{children:"Graph Settings"})}),Object(u.jsx)(g.a,{size:"small",onClick:function(){return r(!1)},children:Object(u.jsx)(xt.a,{style:{color:"white"}})})]}),Object(u.jsx)(p.a,{className:i.popoverBody,children:Object(u.jsx)(jt,{})})]})})]})},yt=function(e){var t=e.data,n=void 0===t?[]:t,r=qe(),c=Object(a.useState)([[]]),i=Object(o.a)(c,2),s=i[0],l=i[1],d=Object(a.useState)([]),j=Object(o.a)(d,2),b=j[0],O=j[1],p=Object(a.useState)([]),h=Object(o.a)(p,2),f=h[0],x=h[1],v=Object(a.useState)([]),m=Object(o.a)(v,2),y=m[0],g=m[1],S=Object(a.useState)({1:[0,1]}),E=Object(o.a)(S,2),_=E[0],T=E[1],w=function(e){var t=function(e){var t={};for(var n in e){var a=e[n],r=Ve(a),c=We(a);t[n]=[r-.05*r,c+.05*c]}return t}(e);T(t),r({type:"SET_YAXIS_LIMITS",payload:t})};return Object(a.useEffect)((function(){var e=[],t={},a=[],r=[];null===n||void 0===n||n.forEach((function(n){var c=rt(n,y);r.push(c),a.push(ct(c,n.group)),n.values.forEach((function(a){e.push(a[0]),t[n.group]?t[n.group].push(+a[1]):t[n.group]=[+a[1]]}))}));var c=function(e){var t=Array.from(new Set(e)).sort((function(e,t){return e-t})),n=Ve(t.map((function(e,n){return t[n+1]-e}))),a=t[0]||0;return new Array(t.length).fill(a).map((function(e,t){return B(e+n*t)}))}(e);l([c].concat(Object(Ue.a)(n.map((function(e){return new Array(c.length).fill(1).map((function(t,n){return e.values[n]?+e.values[n][1]:null}))}))))),w(t);var i=[{}].concat(r);JSON.stringify(i)!==JSON.stringify(b)&&(O(i),x(a))}),[n]),Object(a.useEffect)((function(){var e=[],t=[];null===n||void 0===n||n.forEach((function(n){var a=rt(n,y);t.push(a),e.push(ct(a,n.group))})),O([{}].concat(t)),x(e)}),[y]),Object(u.jsx)(u.Fragment,{children:n.length>0?Object(u.jsxs)("div",{children:[Object(u.jsx)(mt,{}),Object(u.jsx)(et,{data:s,series:b,metrics:n,limits:_}),Object(u.jsx)(tt,{labels:f,onChange:function(e,t){g(function(e){var t=e.hideSeries,n=e.legend,a=e.metaKey,r=e.series,c="".concat(n.group,".").concat(n.label),i=it(n.label,n.group,t),o=r.map((function(e){return"".concat(e.scale,".").concat(e.label)}));return a&&i?Object(Ue.a)(o.filter((function(e){return e!==c}))):a&&!i?t.length>=r.length-1?[]:Object(Ue.a)(o.filter((function(e){return e!==c}))):i?t.filter((function(e){return e!==c})):[].concat(Object(Ue.a)(t),[c])}({hideSeries:y,legend:e,metaKey:t,series:b}))}})]}):Object(u.jsx)("div",{style:{textAlign:"center"},children:"No data to show"})})},gt=n(338),St=n(339),Et=n(340),_t=n(341),Tt=n(342),wt=n(343),Ct=Object(he.a)({deemphasized:{opacity:.4}}),At=function(e){var t=e.data,n=Ct(),r=function(e){return Object(a.useMemo)((function(){var t={};return e.forEach((function(e){return Object.entries(e.metric).forEach((function(e){return t[e[0]]?t[e[0]].options.add(e[1]):t[e[0]]={options:new Set([e[1]])}}))})),Object.entries(t).map((function(e){return{key:e[0],variations:e[1].options.size}})).sort((function(e,t){return e.variations-t.variations}))}),[e])}(t),c=Object(a.useMemo)((function(){return null===t||void 0===t?void 0:t.map((function(e){return{metadata:r.map((function(t){return e.metric[t.key]||"-"})),value:e.value?e.value[1]:"-"}}))}),[r,t]);return Object(u.jsx)(u.Fragment,{children:c.length>0?Object(u.jsx)(gt.a,{component:Ot.a,children:Object(u.jsxs)(St.a,{"aria-label":"simple table",children:[Object(u.jsx)(Et.a,{children:Object(u.jsxs)(_t.a,{children:[r.map((function(e,t){return Object(u.jsx)(Tt.a,{style:{textTransform:"capitalize"},children:e.key},t)})),Object(u.jsx)(Tt.a,{align:"right",children:"Value"})]})}),Object(u.jsx)(wt.a,{children:c.map((function(e,t){return Object(u.jsxs)(_t.a,{children:[e.metadata.map((function(e,a){var r=c[t-1]&&c[t-1].metadata[a];return Object(u.jsx)(Tt.a,{className:r===e?n.deemphasized:void 0,children:e},a)})),Object(u.jsx)(Tt.a,{align:"right",children:e.value})]},t)}))})]})}):Object(u.jsx)("div",{style:{textAlign:"center"},children:"No data to show"})})},Rt=n(321),It=n(350),kt=n(351),Ut=n(326),Mt=n(6),Ht=n(13),Dt=n(110),Nt=n(172),Lt=n(174);!function(e){e.emptyServer="Please enter Server URL",e.validServer="Please provide a valid Server URL",e.validQuery="Please enter a valid Query and execute it"}($e||($e={}));var Pt=function(e){var t=e.index,n=e.query,r=e.queryHistory,c=e.setHistoryIndex,i=e.setQuery,s=e.runQuery,l=e.server,d=e.oneLiner,j=void 0!==d&&d,b=e.autocomplete,O=e.error,p=Object(a.useRef)(null),h=Object(a.useState)(),f=Object(o.a)(h,2),x=f[0],v=f[1],m=Object(a.useState)(!1),y=Object(o.a)(m,2),g=y[0],S=y[1];Object(a.useEffect)((function(){return p.current&&v(new Ht.d({parent:p.current})),function(){return null===x||void 0===x?void 0:x.destroy()}}),[]),Object(a.useEffect)((function(){var e=new Nt.a;e.activateCompletion(b),e.setComplete({remote:{url:l}});var a=Ht.d.updateListener.of((function(e){e.focusChanged&&S((null===x||void 0===x?void 0:x.hasFocus)||!1),e.docChanged&&i(e.state.doc.toJSON().map((function(e){return e.trim()})).join(""),t)}));null===x||void 0===x||x.setState(Mt.f.create({doc:n,extensions:[Lt.a,Ht.k.of(Dt.a),a,e.asExtension()]}))}),[l,x,b,r]);return Object(u.jsxs)("div",{className:"query-editor-container \n    ".concat(g?"query-editor-container_focus":"","\n    query-editor-container-").concat(j?"one-line":"multi-line","\n    ").concat(O===$e.validQuery?"query-editor-container_error":""),children:[Object(u.jsx)("label",{className:"query-editor-label",children:"Query"}),Object(u.jsx)("div",{className:"query-editor",ref:p,onKeyUp:function(e){var n=e.key,a=e.ctrlKey,r=e.metaKey,i=a||r;"Enter"===n&&i?s():"ArrowUp"===n&&i?c(-1,t):"ArrowDown"===n&&i&&c(1,t)}})]})},qt=n(336),Yt=n(312),Bt=function(){return Object(u.jsx)(gt.a,{component:Ot.a,children:Object(u.jsxs)(St.a,{"aria-label":"simple table",size:"small",children:[Object(u.jsx)(Et.a,{children:Object(u.jsxs)(_t.a,{children:[Object(u.jsx)(Tt.a,{children:"Long"}),Object(u.jsx)(Tt.a,{children:"Short"})]})}),Object(u.jsx)(wt.a,{children:q.map((function(e,t){return Object(u.jsxs)(_t.a,{children:[Object(u.jsx)(Tt.a,{component:"th",scope:"row",children:e.long}),Object(u.jsx)(Tt.a,{children:e.short})]},t)}))})]})})},Ft=Object(he.a)({inlineBtn:{"&:hover":{cursor:"pointer"}}}),Qt=function(e){var t=e.handler,n=e.text,a=Ft();return Object(u.jsx)(f.a,{component:"span",className:a.inlineBtn,onClick:t,children:n})},zt=Object(he.a)({container:{display:"grid",gridTemplateColumns:"auto auto",height:"100%",padding:"18px 14px",borderRadius:"4px",borderColor:"#b9b9b9",borderStyle:"solid",borderWidth:"1px"}}),Gt=function(e){var t=e.setDuration,n=zt(),c=Object(a.useState)(!1),i=Object(o.a)(c,2),s=i[0],l=i[1],d=r.a.useState(null),j=Object(o.a)(d,2),b=j[0],O=j[1],f=Object(a.useState)(),x=Object(o.a)(f,2),v=x[0],m=x[1],y=de().time,g=y.period.end,S=y.duration,E=je(),_=Object(a.useState)(S),w=Object(o.a)(_,2),A=w[0],R=w[1];Object(a.useEffect)((function(){R(S)}),[S]),Object(a.useEffect)((function(){m(function(e){return C()(e).format(P)}(W(g)))}),[g]),Object(a.useEffect)((function(){if(!s){var e=function(e){var t=e.trim().split(" ").reduce((function(e,t){var n=F(t);return n?Object(T.a)(Object(T.a)({},e),n):Object(T.a)({},e)}),{}),n=C.a.duration(t).asMilliseconds();return n<N?G(N):n>L?G(L):e}(A);R(e),t(e)}}),[A,s]);var I=function(){O(null)},k=Boolean(b);return Object(u.jsxs)(p.a,{className:n.container,children:[Object(u.jsxs)(p.a,{px:1,children:[Object(u.jsx)(p.a,{children:Object(u.jsx)(lt.a,{label:"Duration",value:A,onChange:function(e){R(e.target.value)},variant:"standard",fullWidth:!0,onKeyUp:function(e){if("Enter"===e.key){var t=e.target;t.blur(),R(t.value)}},onBlur:function(){l(!1)},onFocus:function(){l(!0)}})}),Object(u.jsx)(p.a,{mt:2,children:Object(u.jsxs)(h.a,{variant:"body2",children:[Object(u.jsx)("span",{"aria-owns":k?"mouse-over-popover":void 0,"aria-haspopup":"true",style:{cursor:"pointer"},onMouseEnter:function(e){O(e.currentTarget)},onMouseLeave:I,children:"Possible options:\xa0"}),Object(u.jsx)(qt.a,{open:k,anchorEl:b,anchorOrigin:{vertical:"bottom",horizontal:"left"},transformOrigin:{vertical:"top",horizontal:"left"},style:{pointerEvents:"none"},onClose:I,disableRestoreFocus:!0,children:Object(u.jsx)(Bt,{})}),Object(u.jsx)(Qt,{handler:function(){return R("5m")},text:"5m"}),",\xa0",Object(u.jsx)(Qt,{handler:function(){return R("1h")},text:"1h"}),",\xa0",Object(u.jsx)(Qt,{handler:function(){return R("1h 30m")},text:"1h 30m"})]})})]}),Object(u.jsxs)(p.a,{px:1,children:[Object(u.jsx)(p.a,{children:Object(u.jsx)(Yt.a,{label:"Until",ampm:!1,value:v,onChange:function(e){return E({type:"SET_UNTIL",payload:e})},onError:console.log,inputFormat:"DD/MM/YYYY HH:mm:ss",mask:"__/__/____ __:__:__",renderInput:function(e){return Object(u.jsx)(lt.a,Object(T.a)(Object(T.a)({},e),{},{variant:"standard"}))}})}),Object(u.jsx)(p.a,{mt:2,children:Object(u.jsxs)(h.a,{variant:"body2",children:["Will be changed to current time for auto-refresh mode.\xa0",Object(u.jsx)(Qt,{handler:function(){return E({type:"RUN_QUERY_TO_NOW"})},text:"Switch to now"})]})})]})]})},Wt=n(162),Vt=n.n(Wt),Jt=n(164),Kt=n.n(Jt),Xt=n(165),Zt=n.n(Xt),$t=n(163),en=n.n($t),tn=n(302),nn=n(161),an=n.n(nn),rn=n(309),cn=n(307),on=n(347),sn=n(349),ln=n(316),un=n(345),dn=n(335),jn=n(322),bn=n(334),On=n(346),pn=n(320),hn=n(337),fn=n(348),xn=n(308),vn=["children","value","index"],mn=function(e){var t=e.children,n=e.value,a=e.index,r=Object(nt.a)(e,vn);return Object(u.jsx)("div",Object(T.a)(Object(T.a)({role:"tabpanel",hidden:n!==a,id:"auth-config-tabpanel-".concat(a),"aria-labelledby":"auth-config-tab-".concat(a)},r),{},{children:n===a&&Object(u.jsx)(p.a,{py:2,children:t})}))},yn=n(159),gn=n.n(yn),Sn=n(160),En=n.n(Sn),_n={authMethod:"NO_AUTH",saveAuthLocally:!1},Tn=J("AUTH_TYPE"),wn=J("BASIC_AUTH_DATA"),Cn=J("BEARER_AUTH_DATA"),An=Object(T.a)(Object(T.a)({},_n),{},{authMethod:Tn||_n.authMethod,basicData:wn,bearerData:Cn,saveAuthLocally:!(!wn&&!Cn)}),Rn=function(){K(X)};function In(e,t){switch(t.type){case"SET_BASIC_AUTH":return t.payload.checkbox?V("BASIC_AUTH_DATA",t.payload.value):Rn(),V("AUTH_TYPE","BASIC_AUTH"),Object(T.a)(Object(T.a)({},e),{},{authMethod:"BASIC_AUTH",basicData:t.payload.value});case"SET_BEARER_AUTH":return t.payload.checkbox?V("BEARER_AUTH_DATA",t.payload.value):Rn(),V("AUTH_TYPE","BEARER_AUTH"),Object(T.a)(Object(T.a)({},e),{},{authMethod:"BEARER_AUTH",bearerData:t.payload.value});case"SET_NO_AUTH":return!t.payload.checkbox&&Rn(),V("AUTH_TYPE","NO_AUTH"),Object(T.a)(Object(T.a)({},e),{},{authMethod:"NO_AUTH"});default:throw new Error}}var kn=Object(a.createContext)({}),Un=function(){return Object(a.useContext)(kn).state},Mn=function(e){var t=e.children,n=Object(a.useReducer)(In,An),r=Object(o.a)(n,2),c=r[0],i=r[1],s=Object(a.useMemo)((function(){return{state:c,dispatch:i}}),[c,i]);return Object(u.jsx)(kn.Provider,{value:s,children:t})},Hn=Object(he.a)((function(){return Object(xn.a)({tabsContent:{height:"200px"}})})),Dn="Bearer ",Nn=[{title:"No auth",id:"NO_AUTH"},{title:"Basic Auth",id:"BASIC_AUTH"},{title:"Bearer Token",id:"BEARER_AUTH"}],Ln=function(e){var t=Hn(),n=e.onClose,r=e.open,c=Un(),i=c.saveAuthLocally,s=c.basicData,l=c.bearerData,d=c.authMethod,j=Object(a.useContext)(kn).dispatch,b=Object(a.useState)(i),O=Object(o.a)(b,2),f=O[0],x=O[1],v=Object(a.useState)(s||{password:"",login:""}),y=Object(o.a)(v,2),g=y[0],S=y[1],E=Object(a.useState)((null===l||void 0===l?void 0:l.token)||Dn),_=Object(o.a)(E,2),w=_[0],C=_[1],A=Object(a.useState)(Nn.findIndex((function(e){return e.id===d}))||0),R=Object(o.a)(A,2),I=R[0],k=R[1],U=function(){n()};return Object(u.jsxs)(cn.a,{onClose:U,"aria-labelledby":"simple-dialog-title",open:r,children:[Object(u.jsx)(rn.a,{id:"simple-dialog-title",children:"Request Auth Settings"}),Object(u.jsxs)(on.a,{children:[Object(u.jsx)(sn.a,{children:"This affects Authorization header sent to the server you specify. Not shown in URL and can be optionally stored on a client side"}),Object(u.jsx)(ln.a,{value:I,onChange:function(e,t){k(t)},indicatorColor:"primary",textColor:"primary",children:Nn.map((function(e){return Object(u.jsx)(un.a,{label:e.title},e.id)}))}),Object(u.jsxs)(p.a,{p:0,display:"flex",flexDirection:"column",className:t.tabsContent,children:[Object(u.jsxs)(p.a,{flexGrow:1,children:[Object(u.jsx)(mn,{value:I,index:0,children:Object(u.jsx)(h.a,{style:{fontStyle:"italic"},children:"No Authorization Header"})}),Object(u.jsxs)(mn,{value:I,index:1,children:[Object(u.jsxs)(dn.a,{margin:"dense",fullWidth:!0,children:[Object(u.jsx)(jn.a,{htmlFor:"basic-login",children:"User"}),Object(u.jsx)(bn.a,{id:"basic-login",startAdornment:Object(u.jsx)(On.a,{position:"start",children:Object(u.jsx)(gn.a,{})}),required:!0,onChange:function(e){return S((function(t){return Object(T.a)(Object(T.a)({},t),{},{login:e.target.value||""})}))},value:(null===g||void 0===g?void 0:g.login)||""})]}),Object(u.jsxs)(dn.a,{margin:"dense",fullWidth:!0,children:[Object(u.jsx)(jn.a,{htmlFor:"basic-pass",children:"Password"}),Object(u.jsx)(bn.a,{id:"basic-pass",startAdornment:Object(u.jsx)(On.a,{position:"start",children:Object(u.jsx)(En.a,{})}),onChange:function(e){return S((function(t){return Object(T.a)(Object(T.a)({},t),{},{password:e.target.value||""})}))},value:(null===g||void 0===g?void 0:g.password)||""})]})]}),Object(u.jsx)(mn,{value:I,index:2,children:Object(u.jsx)(lt.a,{id:"bearer-auth",label:"Bearer token",multiline:!0,fullWidth:!0,value:w,onChange:function(e){var t=e.target.value;t.startsWith(Dn)?C(t):C(Dn)},InputProps:{onPaste:function(e){var t=e.clipboardData.getData("text/plain");t.startsWith(Dn)?C(t):C(Dn+t),e.preventDefault()}},maxRows:6})})]}),Object(u.jsxs)(dn.a,{children:[Object(u.jsx)(m.a,{control:Object(u.jsx)(pn.a,{checked:f,onChange:function(){return x((function(e){return!e}))},name:"checkedB",color:"primary"}),label:"Persist Auth Data Locally"}),Object(u.jsx)(hn.a,{children:f?"Auth Data and the Selected method will be saved to LocalStorage":"Auth Data won't be saved. All previously saved Auth Data will be removed"})]})]})]}),Object(u.jsx)(fn.a,{children:Object(u.jsx)(bt.a,{onClick:function(){switch(I){case 0:j({type:"SET_NO_AUTH",payload:{checkbox:f}});break;case 1:j({type:"SET_BASIC_AUTH",payload:{checkbox:f,value:g}});break;case 2:j({type:"SET_BEARER_AUTH",payload:{checkbox:f,value:{token:w}}})}U()},color:"primary",children:"Apply"})})]})},Pn=function(e){var t=e.error,n=de().serverUrl,r=je(),c=Object(a.useState)(!1),i=Object(o.a)(c,2),s=i[0],l=i[1];return Object(u.jsxs)(u.Fragment,{children:[Object(u.jsxs)(p.a,{display:"grid",gridTemplateColumns:"1fr auto",gap:"4px",alignItems:"center",width:"100%",mb:2,minHeight:50,children:[Object(u.jsx)(lt.a,{variant:"outlined",fullWidth:!0,label:"Server URL",value:n,error:t===$e.validServer||t===$e.emptyServer,inputProps:{style:{fontFamily:"Monospace"}},onChange:function(e){var t=e.target.value;r({type:"SET_SERVER",payload:t})}}),Object(u.jsx)(p.a,{children:Object(u.jsx)(y.a,{title:"Request Auth Settings",children:Object(u.jsx)(g.a,{onClick:function(){return l(!0)},children:Object(u.jsx)(an.a,{})})})})]}),Object(u.jsx)(Ln,{open:s,onClose:function(){return l(!1)}})]})},qn=function(){var e=Pe().customStep,t=qe(),n=Object(a.useState)(!1),r=Object(o.a)(n,2),c=r[0],i=r[1],s=de().time,l=s.period.step,d=s.duration,j=Object(a.useCallback)(dt()((function(e){var n=+e.target.value;n>0?(t({type:"SET_CUSTOM_STEP",payload:n}),i(!1)):i(!0)}),500),[e.value]),b=function(){i(!1),t({type:"TOGGLE_CUSTOM_STEP"})};return Object(a.useEffect)((function(){e.enable&&b()}),[d]),Object(a.useEffect)((function(){e.enable||t({type:"SET_CUSTOM_STEP",payload:l||1})}),[l]),Object(u.jsxs)(p.a,{display:"grid",gridTemplateColumns:"auto 120px",alignItems:"center",children:[Object(u.jsx)(m.a,{control:Object(u.jsx)(ve,{checked:e.enable,onChange:b}),label:"Override step value"}),e.enable&&Object(u.jsx)(lt.a,{label:"Step value",type:"number",size:"small",variant:"outlined",defaultValue:e.value,error:c,helperText:c?"step is out of allowed range":" ",onChange:j})]})},Yn=function(){var e=de().queryControls,t=e.autocomplete,n=e.nocache,a=je();return Object(u.jsxs)(p.a,{display:"flex",alignItems:"center",children:[Object(u.jsx)(p.a,{children:Object(u.jsx)(m.a,{label:"Enable autocomplete",control:Object(u.jsx)(ve,{checked:t,onChange:function(){a({type:"TOGGLE_AUTOCOMPLETE"}),V("AUTOCOMPLETE",!t)}})})}),Object(u.jsx)(p.a,{ml:2,children:Object(u.jsx)(m.a,{label:"Enable cache",control:Object(u.jsx)(ve,{checked:!n,onChange:function(){a({type:"NO_CACHE"}),V("NO_CACHE",!n)}})})}),Object(u.jsx)(p.a,{ml:2,children:Object(u.jsx)(qn,{})})]})},Bn=function(e){var t=e.error,n=de(),r=n.serverUrl,c=n.query,i=n.queryHistory,s=n.time.duration,l=n.queryControls.autocomplete,d=je(),j=Object(a.useState)(!0),b=Object(o.a)(j,2),O=b[0],f=b[1],x=Object(a.useRef)(null),v=Object(a.useRef)(c);Object(a.useEffect)((function(){v.current=c}),[c]);var m=function(){d({type:"SET_QUERY_HISTORY",payload:c.map((function(e,t){var n=i[t]||{values:[]},a=e===n.values[n.values.length-1];return{index:n.values.length-Number(a),values:!a&&e?[].concat(Object(Ue.a)(n.values),[e]):n.values}}))}),d({type:"SET_QUERY",payload:c}),d({type:"RUN_QUERY"})},S=function(e,t){var n=Object(Ue.a)(v.current);n[t]=e,d({type:"SET_QUERY",payload:n})},E=function(e,t){var n=i[t],a=n.index,r=n.values,c=a+e;c<0||c>=r.length||(S(r[c]||"",t),d({type:"SET_QUERY_HISTORY_BY_INDEX",payload:{value:{values:r,index:c},queryNumber:t}}))};return Object(u.jsx)(u.Fragment,{children:Object(u.jsxs)(Rt.a,{expanded:O,onChange:function(){return f((function(e){return!e}))},children:[Object(u.jsxs)(It.a,{expandIcon:Object(u.jsx)(g.a,{children:Object(u.jsx)(Vt.a,{})}),"aria-controls":"panel1a-content",id:"panel1a-header",sx:{alignItems:"flex-start",padding:"15px"},children:[Object(u.jsx)(p.a,{mr:2,children:Object(u.jsx)(h.a,{variant:"h6",component:"h2",children:"Query Configuration"})}),Object(u.jsx)(p.a,{flexGrow:1,onClick:function(e){return e.stopPropagation()},onFocusCapture:function(e){return e.stopPropagation()},children:Object(u.jsx)(tn.a,{disablePortal:!O,container:x.current,children:c.map((function(e,n){return Object(u.jsxs)(p.a,{display:"grid",gridTemplateColumns:"1fr auto",gap:"4px",width:"100%",mb:n===c.length-1?0:2,children:[Object(u.jsx)(Pt,{server:r,query:c[n],index:n,oneLiner:!O,autocomplete:l,queryHistory:i[n],error:t,setHistoryIndex:E,runQuery:m,setQuery:S}),0===n&&Object(u.jsx)(y.a,{title:"Execute Query",children:Object(u.jsx)(g.a,{onClick:m,children:Object(u.jsx)(en.a,{})})}),n>0&&Object(u.jsx)(y.a,{title:"Remove Query",children:Object(u.jsx)(g.a,{onClick:function(){return function(e){var t=Object(Ue.a)(v.current);t.splice(e,1),d({type:"SET_QUERY",payload:t})}(n)},children:Object(u.jsx)(Kt.a,{})})})]},n)}))})})]}),Object(u.jsx)(kt.a,{children:Object(u.jsxs)(Ut.a,{container:!0,columnSpacing:2,children:[Object(u.jsxs)(Ut.a,{item:!0,xs:6,minWidth:400,children:[Object(u.jsx)(Pn,{error:t}),Object(u.jsx)("div",{ref:x}),c.length<2&&Object(u.jsx)(p.a,{display:"inline-block",minHeight:"40px",mt:2,children:Object(u.jsxs)(bt.a,{onClick:function(){return d({type:"SET_QUERY",payload:[].concat(Object(Ue.a)(v.current),[""])})},variant:"outlined",children:[Object(u.jsx)(Zt.a,{sx:{fontSize:16,marginRight:"4px"}}),Object(u.jsx)("span",{style:{lineHeight:1,paddingTop:"1px"},children:"Query"})]})})]}),Object(u.jsx)(Ut.a,{item:!0,xs:!0,children:Object(u.jsx)(Gt,{setDuration:function(e){return d({type:"SET_DURATION",payload:e})},duration:s})}),Object(u.jsx)(Ut.a,{item:!0,xs:12,pt:1,children:Object(u.jsx)(Yn,{})})]})})]})})},Fn=n(81),Qn=n.n(Fn),zn=n(166),Gn=n(167),Wn=function(){var e=de(),t=e.query,n=e.displayType,r=e.serverUrl,c=e.time.period,i=e.queryControls.nocache,s=Un(),l=s.basicData,u=s.bearerData,d=s.authMethod,j=Pe().customStep,b=Object(a.useState)(!1),O=Object(o.a)(b,2),p=O[0],h=O[1],f=Object(a.useState)(),x=Object(o.a)(f,2),v=x[0],m=x[1],y=Object(a.useState)(),g=Object(o.a)(y,2),S=g[0],E=g[1],_=Object(a.useState)(),w=Object(o.a)(_,2),C=w[0],A=w[1],R=Object(a.useState)(),I=Object(o.a)(R,2),k=I[0],U=I[1];Object(a.useEffect)((function(){C&&(m(void 0),E(void 0))}),[C]);var M=Object(a.useMemo)((function(){if(!k)return!0;var e=(k.end-k.start)/3,t=e/(c.end-c.start)>=.7,n=c.end>k.end+e,a=c.start<k.start-e;return t||n||a}),[c]),H=function(){var e=Object(zn.a)(Qn.a.mark((function e(){var t,a,r,i,o,s;return Qn.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(null===D||void 0===D?void 0:D.length){e.next=2;break}return e.abrupt("return");case 2:return h(!0),U(c),t=new Headers,"BASIC_AUTH"===d&&t.set("Authorization","Basic "+btoa("".concat((null===l||void 0===l?void 0:l.login)||"",":").concat((null===l||void 0===l?void 0:l.password)||""))),"BEARER_AUTH"===d&&t.set("Authorization",(null===u||void 0===u?void 0:u.token)||""),e.prev=7,e.delegateYield(Qn.a.mark((function e(){var c,l,u,d,j;return Qn.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,Promise.all(D.map((function(e){return fetch(e,{headers:t})})));case 2:c=e.sent,l=[],u=1,a=!1,r=!1,e.prev=7,o=Object(Gn.a)(c);case 9:return e.next=11,o.next();case 11:if(!(a=!(s=e.sent).done)){e.next=20;break}return d=s.value,e.next=15,d.json();case 15:j=e.sent,d.ok?(A(void 0),l.push.apply(l,Object(Ue.a)(j.data.result.map((function(e){return e.group=u,e})))),u++):A("".concat(j.errorType,"\r\n").concat(null===j||void 0===j?void 0:j.error));case 17:a=!1,e.next=9;break;case 20:e.next=26;break;case 22:e.prev=22,e.t0=e.catch(7),r=!0,i=e.t0;case 26:if(e.prev=26,e.prev=27,!a||null==o.return){e.next=31;break}return e.next=31,o.return();case 31:if(e.prev=31,!r){e.next=34;break}throw i;case 34:return e.finish(31);case 35:return e.finish(26);case 36:"chart"===n?m(l):E(l);case 37:case"end":return e.stop()}}),e,null,[[7,22,26,36],[27,,31,35]])}))(),"t0",9);case 9:e.next=14;break;case 11:e.prev=11,e.t1=e.catch(7),e.t1 instanceof Error&&A("".concat(e.t1.name,": ").concat(e.t1.message));case 14:h(!1);case 15:case"end":return e.stop()}}),e,null,[[7,11]])})));return function(){return e.apply(this,arguments)}}(),D=Object(a.useMemo)((function(){if(c)if(r)if(t.every((function(e){return!e.trim()})))A($e.validQuery);else{if(function(e){var t;try{t=new URL(e)}catch(n){return!1}return"http:"===t.protocol||"https:"===t.protocol}(r)){var e=(c.end-c.start)/2,a=Object(T.a)(Object(T.a)({},c),{},{start:c.start-e,end:c.end+e});return j.enable&&(a.step=j.value),t.filter((function(e){return e.trim()})).map((function(e){return"chart"===n?function(e,t,n,a){return"".concat(e,"/api/v1/query_range?query=").concat(encodeURIComponent(t),"&start=").concat(n.start,"&end=").concat(n.end,"&step=").concat(n.step).concat(a?"&nocache=1":"")}(r,e,a,i):function(e,t,n){return"".concat(e,"/api/v1/query?query=").concat(encodeURIComponent(t),"&start=").concat(n.start,"&end=").concat(n.end,"&step=").concat(n.step)}(r,e,c)}))}A($e.validServer)}else A($e.emptyServer)}),[r,c,n,j]);return Object(a.useEffect)((function(){U(void 0)}),[t]),Object(a.useEffect)((function(){H()}),[r,n,j]),Object(a.useEffect)((function(){M&&H()}),[c]),{fetchUrl:D,isLoading:p,graphData:v,liveData:S,error:C}},Vn=function(e){var t=e.data,n=Object(a.useContext)(d).showInfoMessage,r=Object(a.useMemo)((function(){return JSON.stringify(t,null,2)}),[t]);return Object(u.jsxs)(p.a,{position:"relative",children:[Object(u.jsx)(p.a,{flexDirection:"column",justifyContent:"flex-end",display:"flex",style:{position:"fixed",right:"16px"},children:Object(u.jsx)(bt.a,{variant:"outlined",onClick:function(e){navigator.clipboard.writeText(r),n("Formatted JSON has been copied"),e.preventDefault()},children:"Copy JSON"})}),Object(u.jsx)("pre",{children:r})]})},Jn=function(){var e=de(),t=e.displayType,n=e.time.period,a=Wn(),r=a.isLoading,c=a.liveData,i=a.graphData,o=a.error;return Object(u.jsxs)(u.Fragment,{children:[Object(u.jsx)(b.a,{position:"static",children:Object(u.jsxs)(O.a,{children:[Object(u.jsxs)(p.a,{display:"flex",children:[Object(u.jsxs)(h.a,{variant:"h5",children:[Object(u.jsx)("span",{style:{fontWeight:"bolder"},children:"VM"}),Object(u.jsx)("span",{style:{fontWeight:"lighter"},children:"UI"})]}),Object(u.jsx)("div",{style:{fontSize:"10px",marginTop:"-2px"},children:Object(u.jsx)("div",{children:"BETA"})})]}),Object(u.jsx)("div",{style:{fontSize:"10px",position:"absolute",top:"40px",opacity:".4"},children:Object(u.jsx)(f.a,{color:"inherit",href:"https://github.com/VictoriaMetrics/VictoriaMetrics/issues/new",target:"_blank",children:"Create an issue"})}),Object(u.jsx)(p.a,{ml:4,flexGrow:1,children:Object(u.jsx)(ye,{})}),Object(u.jsx)(ke,{})]})}),Object(u.jsxs)(p.a,{p:4,display:"grid",gridTemplateRows:"auto 1fr",gap:"20px",style:{minHeight:"calc(100vh - 64px)"},children:[Object(u.jsx)(p.a,{children:Object(u.jsx)(Bn,{error:o})}),Object(u.jsxs)(p.a,{height:"100%",children:[r&&Object(u.jsx)(x.a,{in:r,style:{transitionDelay:r?"300ms":"0ms"},children:Object(u.jsx)(p.a,{alignItems:"center",justifyContent:"center",flexDirection:"column",display:"flex",style:{width:"100%",maxWidth:"calc(100vw - 32px)",position:"absolute",height:"50%",background:"linear-gradient(rgba(255,255,255,.7), rgba(255,255,255,.7), rgba(255,255,255,0))"},children:Object(u.jsx)(v.a,{})})}),Object(u.jsxs)(p.a,{height:"100%",bgcolor:"#fff",children:[o&&Object(u.jsx)(l.a,{color:"error",severity:"error",style:{fontSize:"14px",whiteSpace:"pre-wrap"},children:o}),i&&n&&"chart"===t&&Object(u.jsx)(yt,{data:i}),c&&"code"===t&&Object(u.jsx)(Vn,{data:c}),c&&"table"===t&&Object(u.jsx)(At,{data:c})]})]})]})]})},Kn=n(311),Xn=n(354),Zn=n(173),$n=Object(Zn.a)({palette:{primary:{main:"#3F51B5"},secondary:{main:"#F50057"},error:{main:"#FF4141"}},components:{MuiFormHelperText:{styleOverrides:{root:{position:"absolute",top:"36px",left:"2px",margin:0}}},MuiInputLabel:{styleOverrides:{root:{fontSize:"12px",letterSpacing:"normal",lineHeight:"1"}}},MuiInputBase:{styleOverrides:{root:{"&.Mui-focused fieldset":{borderWidth:"1px !important"}}}},MuiSwitch:{defaultProps:{color:"secondary"}},MuiAccordion:{styleOverrides:{root:{boxShadow:"rgba(0, 0, 0, 0.16) 0px 1px 4px;"}}},MuiPaper:{styleOverrides:{elevation3:{boxShadow:"rgba(0, 0, 0, 0.2) 0px 3px 8px;"}}},MuiIconButton:{defaultProps:{size:"large"},styleOverrides:{sizeLarge:{borderRadius:"20%",height:"40px",width:"41px"},sizeMedium:{borderRadius:"20%"},sizeSmall:{borderRadius:"20%"}}}},typography:{fontSize:10}}),ea=n(310),ta=n(306),na=n(168),aa=function(){return Object(u.jsxs)(u.Fragment,{children:[Object(u.jsx)(ea.a,{})," ",Object(u.jsxs)(ta.b,{dateAdapter:na.a,children:[" ",Object(u.jsx)(Kn.a,{injectFirst:!0,children:Object(u.jsxs)(Xn.a,{theme:$n,children:["  ",Object(u.jsxs)(Oe,{children:[" ",Object(u.jsxs)(Mn,{children:[" ",Object(u.jsxs)(Ye,{children:[" ",Object(u.jsxs)(j,{children:[" ",Object(u.jsx)(Jn,{})]})]})]})]})]})})]})]})},ra=function(e){e&&e instanceof Function&&n.e(3).then(n.bind(null,356)).then((function(t){var n=t.getCLS,a=t.getFID,r=t.getFCP,c=t.getLCP,i=t.getTTFB;n(e),a(e),r(e),c(e),i(e)}))};i.a.render(Object(u.jsx)(r.a.StrictMode,{children:Object(u.jsx)(aa,{})}),document.getElementById("root")),ra()}},[[234,1,2]]]);
\ No newline at end of file
+(this.webpackJsonpvmui=this.webpackJsonpvmui||[]).push([[0],{204:function(e,t,n){},219:function(e,t){},223:function(e,t,n){},224:function(e,t,n){},234:function(e,t,n){"use strict";n.r(t);var a=n(1),r=n.n(a),c=n(53),i=n.n(c),o=(n(204),n(9)),s=n(318),l=n(317),u=n(0),d=Object(a.createContext)({showInfoMessage:function(){}}),j=function(e){var t=e.children,n=Object(a.useState)({}),r=Object(o.a)(n,2),c=r[0],i=r[1],j=Object(a.useState)(!1),b=Object(o.a)(j,2),p=b[0],O=b[1],h=Object(a.useState)(void 0),f=Object(o.a)(h,2),x=f[0],v=f[1];Object(a.useEffect)((function(){x&&(i({message:x,key:(new Date).getTime()}),O(!0))}),[x]);return Object(u.jsxs)(d.Provider,{value:{showInfoMessage:v},children:[Object(u.jsx)(s.a,{open:p,autoHideDuration:4e3,onClose:function(e,t){"clickaway"!==t&&(v(void 0),O(!1))},children:Object(u.jsx)(l.a,{children:c.message})},c.key),t]})},b=n(352),p=n(353),O=n(328),h=n(246),f=n(344),x=n(242),v=n(329),m=n(331),y=n(323),g=n(327),S=n(149),E=n.n(S),_=n(3),T=n(16),w=n(40),C=n.n(w),A=n(145),R=n.n(A),I=n(146),k=n.n(I),U=n(105),M=n.n(U);C.a.extend(R.a),C.a.extend(k.a);var H,D=window.innerWidth/2,N=1,L=1578e8,P="YYYY-MM-DD[T]HH:mm:ss",q=[{long:"days",short:"d",possible:"day"},{long:"weeks",short:"w",possible:"week"},{long:"months",short:"M",possible:"mon"},{long:"years",short:"y",possible:"year"},{long:"hours",short:"h",possible:"hour"},{long:"minutes",short:"m",possible:"min"},{long:"seconds",short:"s",possible:"sec"},{long:"milliseconds",short:"ms",possible:"millisecond"}],Y=q.map((function(e){return e.short})),B=function(e){return+M()(e).format("0.000")},F=function(e){var t=e.match(/\d+/g),n=e.match(/[a-zA-Z]+/g);if(n&&t&&Y.includes(n[0]))return Object(_.a)({},n[0],t[0])},Q=function(e,t){var n=(t||new Date).valueOf()/1e3,a=e.trim().split(" ").reduce((function(e,t){var n=F(t);return n?Object(T.a)(Object(T.a)({},e),n):Object(T.a)({},e)}),{}),r=C.a.duration(a).asSeconds();return{start:n-r,end:n,step:B(r/D)||.001,date:z(t||new Date)}},z=function(e){return C()(e).utc().format(P)},G=function(e){var t=Math.floor(e%1e3),n=Math.floor(e/1e3%60),a=Math.floor(e/1e3/60%60),r=Math.floor(e/1e3/3600%24),c=Math.floor(e/864e5),i=["d","h","m","s","ms"];return[c,r,a,n,t].map((function(e,t){return e?"".concat(e).concat(i[t]):""})).filter((function(e){return e})).join(" ")},W=function(e){return new Date(1e3*e)},V=function(e,t){t?window.localStorage.setItem(e,JSON.stringify({value:t})):K([e])},J=function(e){var t=window.localStorage.getItem(e);if(null!==t)try{var n;return null===(n=JSON.parse(t))||void 0===n?void 0:n.value}catch(a){return t}},K=function(e){return e.forEach((function(e){return window.localStorage.removeItem(e)}))},X=["BASIC_AUTH_DATA","BEARER_AUTH_DATA"],Z=n(147),$=n.n(Z),ee=n(117),te=n.n(ee),ne={"time.duration":"range_input","time.period.date":"end_input","time.period.step":"step_input",displayType:"tab"},ae=function(e){var t=new Map(Object.entries(ne)),n=te()(e,"query",""),a=[];n.forEach((function(n,r){t.forEach((function(t,n){var c=te()(e,n,"");if(c){var i=encodeURIComponent(c);a.push("g".concat(r,".").concat(t,"=").concat(i))}})),a.push("g".concat(r,".expr=").concat(n))})),function(e){var t=window;if(t){var n="".concat(t.location.protocol,"//").concat(t.location.host).concat(t.location.pathname,"?").concat(e);t.history.pushState({path:n},"",n)}}(a.join("&"))},re=function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:window.location.search,a=$.a.parse(n,{ignoreQueryPrefix:!0});return te()(a,e,t||"")},ce=re("g0.range_input","1h"),ie=(H=re("g0.end_input",new Date(C()().utc().format(P))),C()(H).utcOffset(0,!0).local().format(P)),oe=function(){var e,t=(null===(e=window.location.search.match(/g\d+.expr/gim))||void 0===e?void 0:e.length)||1;return new Array(t).fill(1).map((function(e,t){return re("g".concat(t,".expr"),"")}))}(),se={serverUrl:window.location.href.replace(/\/(?:prometheus\/)?(?:graph|vmui)\/.*/,"/prometheus/"),displayType:re("tab","chart"),query:oe,queryHistory:oe.map((function(e){return{index:0,values:[e]}})),time:{duration:ce,period:Q(ce,new Date(ie))},queryControls:{autoRefresh:!1,autocomplete:J("AUTOCOMPLETE")||!1,nocache:J("NO_CACHE")||!1}};function le(e,t){switch(t.type){case"SET_DISPLAY_TYPE":return Object(T.a)(Object(T.a)({},e),{},{displayType:t.payload});case"SET_SERVER":return Object(T.a)(Object(T.a)({},e),{},{serverUrl:t.payload});case"SET_QUERY":return Object(T.a)(Object(T.a)({},e),{},{query:t.payload});case"SET_QUERY_HISTORY":return Object(T.a)(Object(T.a)({},e),{},{queryHistory:t.payload});case"SET_QUERY_HISTORY_BY_INDEX":return e.queryHistory.splice(t.payload.queryNumber,1,t.payload.value),Object(T.a)(Object(T.a)({},e),{},{queryHistory:e.queryHistory});case"SET_DURATION":return Object(T.a)(Object(T.a)({},e),{},{time:Object(T.a)(Object(T.a)({},e.time),{},{duration:t.payload,period:Q(t.payload,W(e.time.period.end))})});case"SET_UNTIL":return Object(T.a)(Object(T.a)({},e),{},{time:Object(T.a)(Object(T.a)({},e.time),{},{period:Q(e.time.duration,t.payload)})});case"SET_PERIOD":var n=function(e){var t=e.to.valueOf()-e.from.valueOf();return G(t)}(t.payload);return Object(T.a)(Object(T.a)({},e),{},{queryControls:Object(T.a)(Object(T.a)({},e.queryControls),{},{autoRefresh:!1}),time:Object(T.a)(Object(T.a)({},e.time),{},{duration:n,period:Q(n,t.payload.to)})});case"TOGGLE_AUTOREFRESH":return Object(T.a)(Object(T.a)({},e),{},{queryControls:Object(T.a)(Object(T.a)({},e.queryControls),{},{autoRefresh:!e.queryControls.autoRefresh})});case"TOGGLE_AUTOCOMPLETE":return Object(T.a)(Object(T.a)({},e),{},{queryControls:Object(T.a)(Object(T.a)({},e.queryControls),{},{autocomplete:!e.queryControls.autocomplete})});case"NO_CACHE":return Object(T.a)(Object(T.a)({},e),{},{queryControls:Object(T.a)(Object(T.a)({},e.queryControls),{},{nocache:!e.queryControls.nocache})});case"RUN_QUERY":return Object(T.a)(Object(T.a)({},e),{},{time:Object(T.a)(Object(T.a)({},e.time),{},{period:Q(e.time.duration,W(e.time.period.end))})});case"RUN_QUERY_TO_NOW":return Object(T.a)(Object(T.a)({},e),{},{time:Object(T.a)(Object(T.a)({},e.time),{},{period:Q(e.time.duration)})});default:throw new Error}}var ue=Object(a.createContext)({}),de=function(){return Object(a.useContext)(ue).state},je=function(){return Object(a.useContext)(ue).dispatch},be=Object.entries(se).reduce((function(e,t){var n=Object(o.a)(t,2),a=n[0],r=n[1];return Object(T.a)(Object(T.a)({},e),{},Object(_.a)({},a,re(a)||r))}),{}),pe=function(e){var t=e.children,n=Object(a.useReducer)(le,be),r=Object(o.a)(n,2),c=r[0],i=r[1];Object(a.useEffect)((function(){ae(c)}),[c]);var s=Object(a.useMemo)((function(){return{state:c,dispatch:i}}),[c,i]);return Object(u.jsx)(ue.Provider,{value:s,children:t})},Oe=function(e){return Object(u.jsxs)(O.a,{position:"relative",display:"inline-flex",children:[Object(u.jsx)(v.a,Object(T.a)({variant:"determinate"},e)),Object(u.jsx)(O.a,{top:0,left:0,bottom:0,right:0,position:"absolute",display:"flex",alignItems:"center",justifyContent:"center",children:Object(u.jsx)(h.a,{variant:"caption",component:"div",children:"".concat(e.label,"s")})})]})},he=n(314),fe=n(10),xe=n(330),ve=Object(fe.a)(xe.a)((function(){return{padding:10,"& .MuiSwitch-track":{borderRadius:14,"&:before, &:after":{content:'""',position:"absolute",top:"50%",transform:"translateY(-50%)",width:14,height:14}},"& .MuiSwitch-thumb":{boxShadow:"none",width:12,height:12,margin:4}}})),me=Object(he.a)({colorizing:{color:"white"}}),ye=function(){var e=me(),t=je(),n=de().queryControls.autoRefresh,c=Object(a.useState)(5),i=Object(o.a)(c,2),s=i[0],l=i[1],d=Object(a.useState)(),j=Object(o.a)(d,2),b=j[0],p=j[1],h=r.a.useState(100),f=Object(o.a)(h,2),x=f[0],v=f[1];Object(a.useEffect)((function(){var e;return n&&(p((new Date).valueOf()),e=setInterval((function(){p((new Date).valueOf()),t({type:"RUN_QUERY_TO_NOW"})}),1e3*s)),function(){e&&clearInterval(e)}}),[s,n]),Object(a.useEffect)((function(){var e=setInterval((function(){if(n&&b){var e=((new Date).valueOf()-b)/1e3,t=Math.floor(e/s*100);v(t)}}),16);return function(){clearInterval(e)}}),[n,b,s]);var S=function(){l((function(e){switch(e){case 1:return 2;default:return 5;case 5:return 1}}))};return Object(u.jsxs)(O.a,{display:"flex",alignItems:"center",children:[Object(u.jsx)(m.a,{control:Object(u.jsx)(ve,{className:e.colorizing,checked:n,onChange:function(){t({type:"TOGGLE_AUTOREFRESH"})}}),label:"Auto-refresh"}),n&&Object(u.jsxs)(u.Fragment,{children:[Object(u.jsx)(Oe,{className:e.colorizing,label:s,value:x,onClick:function(){S()}}),Object(u.jsx)(y.a,{title:"Change delay refresh",children:Object(u.jsx)(O.a,{ml:1,children:Object(u.jsx)(g.a,{onClick:function(){S()},children:Object(u.jsx)(E.a,{style:{color:"white"}})})})})]})]})},ge=n(152),Se=n.n(ge),Ee=n(150),_e=n.n(Ee),Te=n(151),we=n.n(Te),Ce=n(333),Ae=n(324),Re=n(332),Ie=Object(Re.a)({root:{display:"grid",gridTemplateColumns:"18px auto",gridGap:6,padding:"8px 12px",color:"white",lineHeight:"19px","&.Mui-selected":{color:"white"}}})(Ce.a),ke=function(){var e=de().displayType,t=je();return Object(u.jsxs)(Ae.a,{value:e,exclusive:!0,onChange:function(n,a){return t({type:"SET_DISPLAY_TYPE",payload:null!==a&&void 0!==a?a:e})},children:[Object(u.jsxs)(Ie,{value:"chart","aria-label":"display as chart",children:[Object(u.jsx)(_e.a,{}),Object(u.jsx)("span",{children:"Query Range as Chart"})]}),Object(u.jsxs)(Ie,{value:"code","aria-label":"display as code",children:[Object(u.jsx)(we.a,{}),Object(u.jsx)("span",{children:"Instant Query as JSON"})]}),Object(u.jsxs)(Ie,{value:"table","aria-label":"display as table",children:[Object(u.jsx)(Se.a,{}),Object(u.jsx)("span",{children:"Instant Query as Table"})]})]})},Ue=n(21),Me=n(153),He={customStep:{enable:!1,value:1},yaxis:{limits:{enable:!1,range:{1:[0,0]}}}};function De(e,t){switch(t.type){case"TOGGLE_ENABLE_YAXIS_LIMITS":return Object(T.a)(Object(T.a)({},e),{},{yaxis:Object(T.a)(Object(T.a)({},e.yaxis),{},{limits:Object(T.a)(Object(T.a)({},e.yaxis.limits),{},{enable:!e.yaxis.limits.enable})})});case"TOGGLE_CUSTOM_STEP":return Object(T.a)(Object(T.a)({},e),{},{customStep:Object(T.a)(Object(T.a)({},e.customStep),{},{enable:!e.customStep.enable})});case"SET_CUSTOM_STEP":return Object(T.a)(Object(T.a)({},e),{},{customStep:Object(T.a)(Object(T.a)({},e.customStep),{},{value:t.payload})});case"SET_YAXIS_LIMITS":return Object(T.a)(Object(T.a)({},e),{},{yaxis:Object(T.a)(Object(T.a)({},e.yaxis),{},{limits:Object(T.a)(Object(T.a)({},e.yaxis.limits),{},{range:t.payload})})});default:throw new Error}}var Ne,Le=Object(a.createContext)({}),Pe=function(){return Object(a.useContext)(Le).state},qe=function(){return Object(a.useContext)(Le).dispatch},Ye=function(e){var t=e.children,n=Object(a.useReducer)(De,He),r=Object(o.a)(n,2),c=r[0],i=r[1],s=Object(a.useMemo)((function(){return{state:c,dispatch:i}}),[c,i]);return Object(u.jsx)(Le.Provider,{value:s,children:t})},Be=function(e){if(7!=e.length)return"0, 0, 0";var t=parseInt(e.slice(1,3),16),n=parseInt(e.slice(3,5),16),a=parseInt(e.slice(5,7),16);return"".concat(t,", ").concat(n,", ").concat(a)},Fe={height:500,legend:{show:!1},cursor:{drag:{x:!1,y:!1},focus:{prox:30},bind:{mouseup:function(){return null},mousedown:function(){return null},click:function(){return null},dblclick:function(){return null},mouseenter:function(){return null}}}},Qe=function(e,t){return t.map((function(e){return e>1e3?M()(e).format("0.0a"):e}))},ze=function(e,t){return function(e){for(var t=0,n=0;n<e.length;n++)t=e.charCodeAt(n)+((t<<5)-t);for(var a="#",r=0;r<3;r++)a+=("00"+(t>>8*r&255).toString(16)).substr(-2);return a}("".concat(e).concat(t))},Ge=function(e){return e<=1?[]:[4*e,1.2*e]},We=function(e){for(var t=e.length,n=-1/0;t--;)e[t]>n&&(n=e[t]);return n},Ve=function(e){for(var t=e.length,n=1/0;t--;)e[t]<n&&(n=e[t]);return n},Je=function(e){return Array.from(new Set(e.map((function(e){return e.scale})))).map((function(e){var t={scale:e,show:!0,font:"10px Arial",values:Qe};return e?Number(e)%2?t:Object(T.a)(Object(T.a)({},t),{},{side:1}):{space:80}}))},Ke=function(e){var t,n,a=e.u,r=e.tooltipIdx,c=e.metrics,i=e.series,o=e.tooltip,s=e.tooltipOffset,l=r.seriesIdx,u=r.dataIdx,d=a.data[l][u],j=a.data[0][u],b=(null===(t=c[l-1])||void 0===t?void 0:t.metric)||{},p=ze(Number(i[l].scale||0),i[l].label||""),O=a.over.getBoundingClientRect(),h=O.width,f=O.height,x=a.valToPos(d||0,(null===(n=i[l])||void 0===n?void 0:n.scale)||"1"),v=a.valToPos(j,"x"),m=o.getBoundingClientRect(),y=m.width,g=m.height,S=v+y>=h,E=x+g>=f;o.style.display="grid",o.style.top="".concat(s.top+x+10-(E?g+10:0),"px"),o.style.left="".concat(s.left+v+10-(S?y+20:0),"px");var _=C()(new Date(1e3*j)).format("YYYY-MM-DD HH:mm:ss:SSS (Z)"),T=Object.keys(b).filter((function(e){return"__name__"!==e})).map((function(e){return"<div><b>".concat(e,"</b>: ").concat(b[e],"</div>")})).join(""),w='<div class="u-tooltip__marker" style="background: '.concat(p,'"></div>');o.innerHTML="<div>".concat(_,'</div>\n                       <div class="u-tooltip-data">\n                         ').concat(w).concat(b.__name__||"",': <b class="u-tooltip-data__value">').concat(d,'</b>\n                       </div>\n                       <div class="u-tooltip__info">').concat(T,"</div>")},Xe=n(154),Ze=n.n(Xe);n(222),n(223);!function(e){e.xRange="xRange",e.yRange="yRange",e.data="data"}(Ne||(Ne={}));var $e,et=function(e){var t=e.data,n=e.series,r=e.metrics,c=void 0===r?[]:r,i=e.limits,s=je(),l=de().time.period,d=Pe().yaxis,j=Object(a.useRef)(null),b=Object(a.useRef)(null),p=Object(a.useState)(!1),O=Object(o.a)(p,2),h=O[0],f=O[1],x=Object(a.useState)({min:l.start,max:l.end}),v=Object(o.a)(x,2),m=v[0],y=v[1],g=Object(a.useState)(),S=Object(o.a)(g,2),E=S[0],_=S[1],w=document.createElement("div");w.className="u-tooltip";var C={seriesIdx:1,dataIdx:0},A={left:0,top:0},R=Object(a.useCallback)(Ze()((function(e){var t=e.min,n=e.max;s({type:"SET_PERIOD",payload:{from:new Date(1e3*t),to:new Date(1e3*n)}})}),500),[]),I=function(e){var t=e.u,n=e.min,a=e.max,r=1e3*(a-n);r<N||r>L||(t.setScale("x",{min:n,max:a}),y({min:n,max:a}),R({min:n,max:a}))},k=function(){return[m.min,m.max]},U=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1,a=arguments.length>3?arguments[3]:void 0;return d.limits.enable?d.limits.range[a]:t&&n?[t-.05*t,n+.05*n]:i[a]},M=Object(T.a)(Object(T.a)({},Fe),{},{series:n,axes:Je(n),scales:Object(T.a)({},function(){var e={x:{range:k}};return Object.keys(d.limits.range).forEach((function(t){e[t]={range:function(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;return U(e,n,a,t)}}})),e}()),width:j.current?j.current.offsetWidth:400,plugins:[{hooks:{ready:function(e){var t,n=.85;A.left=parseFloat(e.over.style.left),A.top=parseFloat(e.over.style.top),null===(t=e.root.querySelector(".u-wrap"))||void 0===t||t.appendChild(w),e.over.addEventListener("mousedown",(function(t){return function(e){var t=e.e,n=e.factor,a=void 0===n?.85:n,r=e.u,c=e.setPanning,i=e.setPlotScale;if(0===t.button){t.preventDefault(),c(!0);var o=t.clientX,s=r.posToVal(1,"x")-r.posToVal(0,"x"),l=r.scales.x.min||0,u=r.scales.x.max||0,d=function(e){e.preventDefault();var t=s*((e.clientX-o)*a);i({u:r,min:l-t,max:u-t})};document.addEventListener("mousemove",d),document.addEventListener("mouseup",(function e(){c(!1),document.removeEventListener("mousemove",d),document.removeEventListener("mouseup",e)}))}}({u:e,e:t,setPanning:f,setPlotScale:I,factor:n})})),e.over.addEventListener("wheel",(function(t){if(t.ctrlKey||t.metaKey){t.preventDefault();var a=e.over.getBoundingClientRect().width,r=e.cursor.left&&e.cursor.left>0?e.cursor.left:0,c=e.posToVal(r,"x"),i=(e.scales.x.max||0)-(e.scales.x.min||0),o=t.deltaY<0?i*n:i/n,s=c-r/a*o,l=s+o;e.batch((function(){return I({u:e,min:s,max:l})}))}}))},setCursor:function(e){C.dataIdx!==e.cursor.idx&&(C.dataIdx=e.cursor.idx||0,C.seriesIdx&&C.dataIdx&&Ke({u:e,tooltipIdx:C,metrics:c,series:n,tooltip:w,tooltipOffset:A}))},setSeries:function(e,t){C.seriesIdx!==t&&(C.seriesIdx=t||0,t&&C.dataIdx?Ke({u:e,tooltipIdx:C,metrics:c,series:n,tooltip:w,tooltipOffset:A}):w.style.display="none")}}}]}),H=function(e){if(E){switch(e){case Ne.xRange:E.scales.x.range=k;break;case Ne.yRange:Object.keys(d.limits.range).forEach((function(e){E.scales[e]&&(E.scales[e].range=function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;return U(t,n,a,e)})}));break;case Ne.data:E.setData(t)}E.redraw()}};return Object(a.useEffect)((function(){return y({min:l.start,max:l.end})}),[l]),Object(a.useEffect)((function(){if(b.current){var e=new Me.a(M,t,b.current);return _(e),y({min:l.start,max:l.end}),e.destroy}}),[b.current,n]),Object(a.useEffect)((function(){return H(Ne.data)}),[t]),Object(a.useEffect)((function(){return H(Ne.xRange)}),[m]),Object(a.useEffect)((function(){return H(Ne.yRange)}),[d]),Object(u.jsx)("div",{ref:j,style:{pointerEvents:h?"none":"auto",height:"500px"},children:Object(u.jsx)("div",{ref:b})})},tt=(n(224),function(e){var t=e.labels,n=e.onChange,r=de().query,c=Object(a.useMemo)((function(){return Array.from(new Set(t.map((function(e){return e.group}))))}),[t]);return Object(u.jsx)("div",{className:"legendWrapper",children:c.map((function(e){return Object(u.jsxs)("div",{className:"legendGroup",children:[Object(u.jsxs)("div",{className:"legendGroupTitle",children:[Object(u.jsx)("svg",{className:"legendGroupLine",width:"33",height:"3",version:"1.1",xmlns:"http://www.w3.org/2000/svg",children:Object(u.jsx)("line",{strokeWidth:"3",x1:"0",y1:"0",x2:"33",y2:"0",stroke:"#363636",strokeDasharray:Ge(e).join(",")})}),Object(u.jsxs)("b",{children:['"',r[e-1],'"']}),":"]}),Object(u.jsx)("div",{children:t.filter((function(t){return t.group===e})).map((function(e){return Object(u.jsxs)("div",{className:e.checked?"legendItem":"legendItem legendItemHide",onClick:function(t){return n(e,t.ctrlKey||t.metaKey)},children:[Object(u.jsx)("div",{className:"legendMarker",style:{borderColor:e.color,backgroundColor:"rgba(".concat(Be(e.color),", 0.1)")}}),Object(u.jsx)("div",{className:"legendLabel",children:e.label})]},"".concat(e.group,".").concat(e.label))}))})]},e)}))})}),nt=n(115),at=["__name__"],rt=function(e,t){var n=function(e){if(0===Object.keys(e.metric).length)return"Query result";var t=e.metric,n=t.__name__,a=Object(nt.a)(t,at);return"".concat(n||""," {").concat(Object.entries(a).map((function(e){return"".concat(e[0],": ").concat(e[1])})).join(", "),"}")}(e);return{label:n,dash:Ge(e.group),width:1.5,stroke:ze(e.group,n),show:!it(n,e.group,t),scale:String(e.group)}},ct=function(e,t){return{group:t,label:e.label||"",color:e.stroke,checked:e.show||!1}},it=function(e,t,n){return n.includes("".concat(t,".").concat(e))},ot=n(156),st=n.n(ot),lt=n(315),ut=n(106),dt=n.n(ut),jt=function(){var e=Pe().yaxis,t=qe(),n=Object(a.useMemo)((function(){return Object.keys(e.limits.range)}),[e.limits.range]),r=Object(a.useCallback)(dt()((function(n,a,r){var c=e.limits.range;c[a][r]=+n.target.value,t({type:"SET_YAXIS_LIMITS",payload:c})}),500),[e.limits.range]);return Object(u.jsxs)(O.a,{display:"grid",alignItems:"center",gap:2,children:[Object(u.jsx)(m.a,{control:Object(u.jsx)(ve,{checked:e.limits.enable,onChange:function(){t({type:"TOGGLE_ENABLE_YAXIS_LIMITS"})}}),label:"Fix the limits for y-axis"}),Object(u.jsx)(O.a,{display:"grid",alignItems:"center",gap:2,children:n.map((function(t){return Object(u.jsxs)(O.a,{display:"grid",gridTemplateColumns:"120px 120px",gap:1,children:[Object(u.jsx)(lt.a,{label:"Min ".concat(t),type:"number",size:"small",variant:"outlined",disabled:!e.limits.enable,defaultValue:e.limits.range[t][0],onChange:function(e){return r(e,t,0)}}),Object(u.jsx)(lt.a,{label:"Max ".concat(t),type:"number",size:"small",variant:"outlined",disabled:!e.limits.enable,defaultValue:e.limits.range[t][1],onChange:function(e){return r(e,t,1)}})]},t)}))})]})},bt=n(325),pt=n(178),Ot=n(155),ht=n.n(Ot),ft=n(157),xt=n.n(ft),vt=Object(he.a)({popover:{position:"absolute",display:"grid",gridGap:"16px",padding:"0 0 25px",zIndex:2},popoverHeader:{display:"flex",alignItems:"center",justifyContent:"space-between",background:"#3F51B5",padding:"6px 6px 6px 12px",borderRadius:"4px 4px 0 0",color:"#FFF",cursor:"move"},popoverBody:{display:"grid",gridGap:"6px",padding:"0 14px"}}),mt=function(){var e=Object(a.useState)(!1),t=Object(o.a)(e,2),n=t[0],r=t[1],c=Object(a.useRef)(null),i=vt();return Object(u.jsxs)(O.a,{display:"flex",px:2,children:[Object(u.jsxs)(bt.a,{onClick:function(){return r((function(e){return!e}))},variant:"outlined",children:[Object(u.jsx)(st.a,{sx:{fontSize:16,marginRight:"4px"}}),Object(u.jsxs)("span",{style:{lineHeight:1,paddingTop:"1px"},children:[n?"Hide":"Show"," graph settings"]})]}),n&&Object(u.jsx)(ht.a,{nodeRef:c,defaultPosition:{x:173,y:0},handle:"#handle",children:Object(u.jsxs)(pt.a,{elevation:3,className:i.popover,ref:c,children:[Object(u.jsxs)("div",{id:"handle",className:i.popoverHeader,children:[Object(u.jsx)(h.a,{variant:"body1",children:Object(u.jsx)("b",{children:"Graph Settings"})}),Object(u.jsx)(g.a,{size:"small",onClick:function(){return r(!1)},children:Object(u.jsx)(xt.a,{style:{color:"white"}})})]}),Object(u.jsx)(O.a,{className:i.popoverBody,children:Object(u.jsx)(jt,{})})]})})]})},yt=function(e){var t=e.data,n=void 0===t?[]:t,r=qe(),c=Object(a.useState)([[]]),i=Object(o.a)(c,2),s=i[0],l=i[1],d=Object(a.useState)([]),j=Object(o.a)(d,2),b=j[0],p=j[1],O=Object(a.useState)([]),h=Object(o.a)(O,2),f=h[0],x=h[1],v=Object(a.useState)([]),m=Object(o.a)(v,2),y=m[0],g=m[1],S=Object(a.useState)({1:[0,1]}),E=Object(o.a)(S,2),_=E[0],T=E[1],w=function(e){var t=function(e){var t={};for(var n in e){var a=e[n],r=Ve(a),c=We(a);t[n]=[r-.05*r,c+.05*c]}return t}(e);T(t),r({type:"SET_YAXIS_LIMITS",payload:t})};return Object(a.useEffect)((function(){var e=[],t={},a=[],r=[];null===n||void 0===n||n.forEach((function(n){var c=rt(n,y);r.push(c),a.push(ct(c,n.group)),n.values.forEach((function(a){e.push(a[0]),t[n.group]?t[n.group].push(+a[1]):t[n.group]=[+a[1]]}))}));var c=function(e){var t=Array.from(new Set(e)).sort((function(e,t){return e-t})),n=Ve(t.map((function(e,n){return t[n+1]-e}))),a=t[0]||0;return new Array(t.length).fill(a).map((function(e,t){return B(e+n*t)}))}(e);l([c].concat(Object(Ue.a)(n.map((function(e){return new Array(c.length).fill(1).map((function(t,n){return e.values[n]?+e.values[n][1]:null}))}))))),w(t);var i=[{}].concat(r);JSON.stringify(i)!==JSON.stringify(b)&&(p(i),x(a))}),[n]),Object(a.useEffect)((function(){var e=[],t=[];null===n||void 0===n||n.forEach((function(n){var a=rt(n,y);t.push(a),e.push(ct(a,n.group))})),p([{}].concat(t)),x(e)}),[y]),Object(u.jsx)(u.Fragment,{children:n.length>0?Object(u.jsxs)("div",{children:[Object(u.jsx)(mt,{}),Object(u.jsx)(et,{data:s,series:b,metrics:n,limits:_}),Object(u.jsx)(tt,{labels:f,onChange:function(e,t){g(function(e){var t=e.hideSeries,n=e.legend,a=e.metaKey,r=e.series,c="".concat(n.group,".").concat(n.label),i=it(n.label,n.group,t),o=r.map((function(e){return"".concat(e.scale,".").concat(e.label)}));return a&&i?Object(Ue.a)(o.filter((function(e){return e!==c}))):a&&!i?t.length>=r.length-1?[]:Object(Ue.a)(o.filter((function(e){return e!==c}))):i?t.filter((function(e){return e!==c})):[].concat(Object(Ue.a)(t),[c])}({hideSeries:y,legend:e,metaKey:t,series:b}))}})]}):Object(u.jsx)("div",{style:{textAlign:"center"},children:"No data to show"})})},gt=n(338),St=n(339),Et=n(340),_t=n(341),Tt=n(342),wt=n(343),Ct=Object(he.a)({deemphasized:{opacity:.4}}),At=function(e){var t=e.data,n=Ct(),r=function(e){return Object(a.useMemo)((function(){var t={};return e.forEach((function(e){return Object.entries(e.metric).forEach((function(e){return t[e[0]]?t[e[0]].options.add(e[1]):t[e[0]]={options:new Set([e[1]])}}))})),Object.entries(t).map((function(e){return{key:e[0],variations:e[1].options.size}})).sort((function(e,t){return e.variations-t.variations}))}),[e])}(t),c=Object(a.useMemo)((function(){return null===t||void 0===t?void 0:t.map((function(e){return{metadata:r.map((function(t){return e.metric[t.key]||"-"})),value:e.value?e.value[1]:"-"}}))}),[r,t]);return Object(u.jsx)(u.Fragment,{children:c.length>0?Object(u.jsx)(gt.a,{component:pt.a,children:Object(u.jsxs)(St.a,{"aria-label":"simple table",children:[Object(u.jsx)(Et.a,{children:Object(u.jsxs)(_t.a,{children:[r.map((function(e,t){return Object(u.jsx)(Tt.a,{style:{textTransform:"capitalize"},children:e.key},t)})),Object(u.jsx)(Tt.a,{align:"right",children:"Value"})]})}),Object(u.jsx)(wt.a,{children:c.map((function(e,t){return Object(u.jsxs)(_t.a,{children:[e.metadata.map((function(e,a){var r=c[t-1]&&c[t-1].metadata[a];return Object(u.jsx)(Tt.a,{className:r===e?n.deemphasized:void 0,children:e},a)})),Object(u.jsx)(Tt.a,{align:"right",children:e.value})]},t)}))})]})}):Object(u.jsx)("div",{style:{textAlign:"center"},children:"No data to show"})})},Rt=n(321),It=n(350),kt=n(351),Ut=n(326),Mt=n(6),Ht=n(13),Dt=n(110),Nt=n(172),Lt=n(174);!function(e){e.emptyServer="Please enter Server URL",e.validServer="Please provide a valid Server URL",e.validQuery="Please enter a valid Query and execute it"}($e||($e={}));var Pt=function(e){var t=e.index,n=e.query,r=e.queryHistory,c=e.setHistoryIndex,i=e.setQuery,s=e.runQuery,l=e.server,d=e.oneLiner,j=void 0!==d&&d,b=e.autocomplete,p=e.error,O=Object(a.useRef)(null),h=Object(a.useState)(),f=Object(o.a)(h,2),x=f[0],v=f[1],m=Object(a.useState)(!1),y=Object(o.a)(m,2),g=y[0],S=y[1];Object(a.useEffect)((function(){return O.current&&v(new Ht.d({parent:O.current})),function(){return null===x||void 0===x?void 0:x.destroy()}}),[]),Object(a.useEffect)((function(){var e=new Nt.a;e.activateCompletion(b),e.setComplete({remote:{url:l}});var a=Ht.d.updateListener.of((function(e){e.focusChanged&&S((null===x||void 0===x?void 0:x.hasFocus)||!1),e.docChanged&&i(e.state.doc.toJSON().map((function(e){return e.trim()})).join(""),t)}));null===x||void 0===x||x.setState(Mt.f.create({doc:n,extensions:[Lt.a,Ht.k.of(Dt.a),a,e.asExtension()]}))}),[l,x,b,r]);return Object(u.jsxs)("div",{className:"query-editor-container \n    ".concat(g?"query-editor-container_focus":"","\n    query-editor-container-").concat(j?"one-line":"multi-line","\n    ").concat(p===$e.validQuery?"query-editor-container_error":""),children:[Object(u.jsx)("label",{className:"query-editor-label",children:"Query"}),Object(u.jsx)("div",{className:"query-editor",ref:O,onKeyUp:function(e){var n=e.key,a=e.ctrlKey,r=e.metaKey,i=a||r;"Enter"===n&&i?s():"ArrowUp"===n&&i?c(-1,t):"ArrowDown"===n&&i&&c(1,t)}})]})},qt=n(336),Yt=n(312),Bt=function(){return Object(u.jsx)(gt.a,{component:pt.a,children:Object(u.jsxs)(St.a,{"aria-label":"simple table",size:"small",children:[Object(u.jsx)(Et.a,{children:Object(u.jsxs)(_t.a,{children:[Object(u.jsx)(Tt.a,{children:"Long"}),Object(u.jsx)(Tt.a,{children:"Short"})]})}),Object(u.jsx)(wt.a,{children:q.map((function(e,t){return Object(u.jsxs)(_t.a,{children:[Object(u.jsx)(Tt.a,{component:"th",scope:"row",children:e.long}),Object(u.jsx)(Tt.a,{children:e.short})]},t)}))})]})})},Ft=Object(he.a)({inlineBtn:{"&:hover":{cursor:"pointer"}}}),Qt=function(e){var t=e.handler,n=e.text,a=Ft();return Object(u.jsx)(f.a,{component:"span",className:a.inlineBtn,onClick:t,children:n})},zt=Object(he.a)({container:{display:"grid",gridTemplateColumns:"auto auto",height:"100%",padding:"18px 14px",borderRadius:"4px",borderColor:"#b9b9b9",borderStyle:"solid",borderWidth:"1px"}}),Gt=function(e){var t=e.setDuration,n=zt(),c=Object(a.useState)(!1),i=Object(o.a)(c,2),s=i[0],l=i[1],d=r.a.useState(null),j=Object(o.a)(d,2),b=j[0],p=j[1],f=Object(a.useState)(),x=Object(o.a)(f,2),v=x[0],m=x[1],y=de().time,g=y.period.end,S=y.duration,E=je(),_=Object(a.useState)(S),w=Object(o.a)(_,2),A=w[0],R=w[1];Object(a.useEffect)((function(){R(S)}),[S]),Object(a.useEffect)((function(){m(function(e){return C()(e).format(P)}(W(g)))}),[g]),Object(a.useEffect)((function(){if(!s){var e=function(e){var t=e.trim().split(" ").reduce((function(e,t){var n=F(t);return n?Object(T.a)(Object(T.a)({},e),n):Object(T.a)({},e)}),{}),n=C.a.duration(t).asMilliseconds();return n<N?G(N):n>L?G(L):e}(A);R(e),t(e)}}),[A,s]);var I=function(){p(null)},k=Boolean(b);return Object(u.jsxs)(O.a,{className:n.container,children:[Object(u.jsxs)(O.a,{px:1,children:[Object(u.jsx)(O.a,{children:Object(u.jsx)(lt.a,{label:"Duration",value:A,onChange:function(e){R(e.target.value)},variant:"standard",fullWidth:!0,onKeyUp:function(e){if("Enter"===e.key){var t=e.target;t.blur(),R(t.value)}},onBlur:function(){l(!1)},onFocus:function(){l(!0)}})}),Object(u.jsx)(O.a,{mt:2,children:Object(u.jsxs)(h.a,{variant:"body2",children:[Object(u.jsx)("span",{"aria-owns":k?"mouse-over-popover":void 0,"aria-haspopup":"true",style:{cursor:"pointer"},onMouseEnter:function(e){p(e.currentTarget)},onMouseLeave:I,children:"Possible options:\xa0"}),Object(u.jsx)(qt.a,{open:k,anchorEl:b,anchorOrigin:{vertical:"bottom",horizontal:"left"},transformOrigin:{vertical:"top",horizontal:"left"},style:{pointerEvents:"none"},onClose:I,disableRestoreFocus:!0,children:Object(u.jsx)(Bt,{})}),Object(u.jsx)(Qt,{handler:function(){return R("5m")},text:"5m"}),",\xa0",Object(u.jsx)(Qt,{handler:function(){return R("1h")},text:"1h"}),",\xa0",Object(u.jsx)(Qt,{handler:function(){return R("1h 30m")},text:"1h 30m"})]})})]}),Object(u.jsxs)(O.a,{px:1,children:[Object(u.jsx)(O.a,{children:Object(u.jsx)(Yt.a,{label:"Until",ampm:!1,value:v,onChange:function(e){return E({type:"SET_UNTIL",payload:e})},onError:console.log,inputFormat:"DD/MM/YYYY HH:mm:ss",mask:"__/__/____ __:__:__",renderInput:function(e){return Object(u.jsx)(lt.a,Object(T.a)(Object(T.a)({},e),{},{variant:"standard"}))}})}),Object(u.jsx)(O.a,{mt:2,children:Object(u.jsxs)(h.a,{variant:"body2",children:["Will be changed to current time for auto-refresh mode.\xa0",Object(u.jsx)(Qt,{handler:function(){return E({type:"RUN_QUERY_TO_NOW"})},text:"Switch to now"})]})})]})]})},Wt=n(162),Vt=n.n(Wt),Jt=n(164),Kt=n.n(Jt),Xt=n(165),Zt=n.n(Xt),$t=n(163),en=n.n($t),tn=n(302),nn=n(161),an=n.n(nn),rn=n(309),cn=n(307),on=n(347),sn=n(349),ln=n(316),un=n(345),dn=n(335),jn=n(322),bn=n(334),pn=n(346),On=n(320),hn=n(337),fn=n(348),xn=n(308),vn=["children","value","index"],mn=function(e){var t=e.children,n=e.value,a=e.index,r=Object(nt.a)(e,vn);return Object(u.jsx)("div",Object(T.a)(Object(T.a)({role:"tabpanel",hidden:n!==a,id:"auth-config-tabpanel-".concat(a),"aria-labelledby":"auth-config-tab-".concat(a)},r),{},{children:n===a&&Object(u.jsx)(O.a,{py:2,children:t})}))},yn=n(159),gn=n.n(yn),Sn=n(160),En=n.n(Sn),_n={authMethod:"NO_AUTH",saveAuthLocally:!1},Tn=J("AUTH_TYPE"),wn=J("BASIC_AUTH_DATA"),Cn=J("BEARER_AUTH_DATA"),An=Object(T.a)(Object(T.a)({},_n),{},{authMethod:Tn||_n.authMethod,basicData:wn,bearerData:Cn,saveAuthLocally:!(!wn&&!Cn)}),Rn=function(){K(X)};function In(e,t){switch(t.type){case"SET_BASIC_AUTH":return t.payload.checkbox?V("BASIC_AUTH_DATA",t.payload.value):Rn(),V("AUTH_TYPE","BASIC_AUTH"),Object(T.a)(Object(T.a)({},e),{},{authMethod:"BASIC_AUTH",basicData:t.payload.value});case"SET_BEARER_AUTH":return t.payload.checkbox?V("BEARER_AUTH_DATA",t.payload.value):Rn(),V("AUTH_TYPE","BEARER_AUTH"),Object(T.a)(Object(T.a)({},e),{},{authMethod:"BEARER_AUTH",bearerData:t.payload.value});case"SET_NO_AUTH":return!t.payload.checkbox&&Rn(),V("AUTH_TYPE","NO_AUTH"),Object(T.a)(Object(T.a)({},e),{},{authMethod:"NO_AUTH"});default:throw new Error}}var kn=Object(a.createContext)({}),Un=function(){return Object(a.useContext)(kn).state},Mn=function(e){var t=e.children,n=Object(a.useReducer)(In,An),r=Object(o.a)(n,2),c=r[0],i=r[1],s=Object(a.useMemo)((function(){return{state:c,dispatch:i}}),[c,i]);return Object(u.jsx)(kn.Provider,{value:s,children:t})},Hn=Object(he.a)((function(){return Object(xn.a)({tabsContent:{height:"200px"}})})),Dn="Bearer ",Nn=[{title:"No auth",id:"NO_AUTH"},{title:"Basic Auth",id:"BASIC_AUTH"},{title:"Bearer Token",id:"BEARER_AUTH"}],Ln=function(e){var t=Hn(),n=e.onClose,r=e.open,c=Un(),i=c.saveAuthLocally,s=c.basicData,l=c.bearerData,d=c.authMethod,j=Object(a.useContext)(kn).dispatch,b=Object(a.useState)(i),p=Object(o.a)(b,2),f=p[0],x=p[1],v=Object(a.useState)(s||{password:"",login:""}),y=Object(o.a)(v,2),g=y[0],S=y[1],E=Object(a.useState)((null===l||void 0===l?void 0:l.token)||Dn),_=Object(o.a)(E,2),w=_[0],C=_[1],A=Object(a.useState)(Nn.findIndex((function(e){return e.id===d}))||0),R=Object(o.a)(A,2),I=R[0],k=R[1],U=function(){n()};return Object(u.jsxs)(cn.a,{onClose:U,"aria-labelledby":"simple-dialog-title",open:r,children:[Object(u.jsx)(rn.a,{id:"simple-dialog-title",children:"Request Auth Settings"}),Object(u.jsxs)(on.a,{children:[Object(u.jsx)(sn.a,{children:"This affects Authorization header sent to the server you specify. Not shown in URL and can be optionally stored on a client side"}),Object(u.jsx)(ln.a,{value:I,onChange:function(e,t){k(t)},indicatorColor:"primary",textColor:"primary",children:Nn.map((function(e){return Object(u.jsx)(un.a,{label:e.title},e.id)}))}),Object(u.jsxs)(O.a,{p:0,display:"flex",flexDirection:"column",className:t.tabsContent,children:[Object(u.jsxs)(O.a,{flexGrow:1,children:[Object(u.jsx)(mn,{value:I,index:0,children:Object(u.jsx)(h.a,{style:{fontStyle:"italic"},children:"No Authorization Header"})}),Object(u.jsxs)(mn,{value:I,index:1,children:[Object(u.jsxs)(dn.a,{margin:"dense",fullWidth:!0,children:[Object(u.jsx)(jn.a,{htmlFor:"basic-login",children:"User"}),Object(u.jsx)(bn.a,{id:"basic-login",startAdornment:Object(u.jsx)(pn.a,{position:"start",children:Object(u.jsx)(gn.a,{})}),required:!0,onChange:function(e){return S((function(t){return Object(T.a)(Object(T.a)({},t),{},{login:e.target.value||""})}))},value:(null===g||void 0===g?void 0:g.login)||""})]}),Object(u.jsxs)(dn.a,{margin:"dense",fullWidth:!0,children:[Object(u.jsx)(jn.a,{htmlFor:"basic-pass",children:"Password"}),Object(u.jsx)(bn.a,{id:"basic-pass",startAdornment:Object(u.jsx)(pn.a,{position:"start",children:Object(u.jsx)(En.a,{})}),onChange:function(e){return S((function(t){return Object(T.a)(Object(T.a)({},t),{},{password:e.target.value||""})}))},value:(null===g||void 0===g?void 0:g.password)||""})]})]}),Object(u.jsx)(mn,{value:I,index:2,children:Object(u.jsx)(lt.a,{id:"bearer-auth",label:"Bearer token",multiline:!0,fullWidth:!0,value:w,onChange:function(e){var t=e.target.value;t.startsWith(Dn)?C(t):C(Dn)},InputProps:{onPaste:function(e){var t=e.clipboardData.getData("text/plain");t.startsWith(Dn)?C(t):C(Dn+t),e.preventDefault()}},maxRows:6})})]}),Object(u.jsxs)(dn.a,{children:[Object(u.jsx)(m.a,{control:Object(u.jsx)(On.a,{checked:f,onChange:function(){return x((function(e){return!e}))},name:"checkedB",color:"primary"}),label:"Persist Auth Data Locally"}),Object(u.jsx)(hn.a,{children:f?"Auth Data and the Selected method will be saved to LocalStorage":"Auth Data won't be saved. All previously saved Auth Data will be removed"})]})]})]}),Object(u.jsx)(fn.a,{children:Object(u.jsx)(bt.a,{onClick:function(){switch(I){case 0:j({type:"SET_NO_AUTH",payload:{checkbox:f}});break;case 1:j({type:"SET_BASIC_AUTH",payload:{checkbox:f,value:g}});break;case 2:j({type:"SET_BEARER_AUTH",payload:{checkbox:f,value:{token:w}}})}U()},color:"primary",children:"Apply"})})]})},Pn=function(){var e,t=(null===(e=document.getElementById("root"))||void 0===e?void 0:e.dataset.params)||"{}";return JSON.parse(t)},qn=function(){return!!Object.keys(Pn()).length},Yn=function(e){var t=e.error,n=qn(),r=Pn().serverURL,c=de().serverUrl,i=je(),s=Object(a.useState)(!1),l=Object(o.a)(s,2),d=l[0],j=l[1];return Object(a.useEffect)((function(){n&&i({type:"SET_SERVER",payload:r})}),[r]),Object(u.jsxs)(u.Fragment,{children:[Object(u.jsxs)(O.a,{display:"grid",gridTemplateColumns:"1fr auto",gap:"4px",alignItems:"center",width:"100%",mb:2,minHeight:50,children:[Object(u.jsx)(lt.a,{variant:"outlined",fullWidth:!0,label:"Server URL",value:c||"",disabled:n,error:t===$e.validServer||t===$e.emptyServer,inputProps:{style:{fontFamily:"Monospace"}},onChange:function(e){var t=e.target.value;i({type:"SET_SERVER",payload:t})}}),Object(u.jsx)(O.a,{children:Object(u.jsx)(y.a,{title:"Request Auth Settings",children:Object(u.jsx)(g.a,{onClick:function(){return j(!0)},children:Object(u.jsx)(an.a,{})})})})]}),Object(u.jsx)(Ln,{open:d,onClose:function(){return j(!1)}})]})},Bn=function(){var e=Pe().customStep,t=qe(),n=Object(a.useState)(!1),r=Object(o.a)(n,2),c=r[0],i=r[1],s=de().time,l=s.period.step,d=s.duration,j=Object(a.useCallback)(dt()((function(e){var n=+e.target.value;n>0?(t({type:"SET_CUSTOM_STEP",payload:n}),i(!1)):i(!0)}),500),[e.value]),b=function(){i(!1),t({type:"TOGGLE_CUSTOM_STEP"})};return Object(a.useEffect)((function(){e.enable&&b()}),[d]),Object(a.useEffect)((function(){e.enable||t({type:"SET_CUSTOM_STEP",payload:l||1})}),[l]),Object(u.jsxs)(O.a,{display:"grid",gridTemplateColumns:"auto 120px",alignItems:"center",children:[Object(u.jsx)(m.a,{control:Object(u.jsx)(ve,{checked:e.enable,onChange:b}),label:"Override step value"}),e.enable&&Object(u.jsx)(lt.a,{label:"Step value",type:"number",size:"small",variant:"outlined",defaultValue:e.value,error:c,helperText:c?"step is out of allowed range":" ",onChange:j})]})},Fn=function(){var e=de().queryControls,t=e.autocomplete,n=e.nocache,a=je();return Object(u.jsxs)(O.a,{display:"flex",alignItems:"center",children:[Object(u.jsx)(O.a,{children:Object(u.jsx)(m.a,{label:"Enable autocomplete",control:Object(u.jsx)(ve,{checked:t,onChange:function(){a({type:"TOGGLE_AUTOCOMPLETE"}),V("AUTOCOMPLETE",!t)}})})}),Object(u.jsx)(O.a,{ml:2,children:Object(u.jsx)(m.a,{label:"Enable cache",control:Object(u.jsx)(ve,{checked:!n,onChange:function(){a({type:"NO_CACHE"}),V("NO_CACHE",!n)}})})}),Object(u.jsx)(O.a,{ml:2,children:Object(u.jsx)(Bn,{})})]})},Qn=function(e){var t=e.error,n=de(),r=n.serverUrl,c=n.query,i=n.queryHistory,s=n.time.duration,l=n.queryControls.autocomplete,d=je(),j=Object(a.useState)(!0),b=Object(o.a)(j,2),p=b[0],f=b[1],x=Object(a.useRef)(null),v=Object(a.useRef)(c);Object(a.useEffect)((function(){v.current=c}),[c]);var m=function(){d({type:"SET_QUERY_HISTORY",payload:c.map((function(e,t){var n=i[t]||{values:[]},a=e===n.values[n.values.length-1];return{index:n.values.length-Number(a),values:!a&&e?[].concat(Object(Ue.a)(n.values),[e]):n.values}}))}),d({type:"SET_QUERY",payload:c}),d({type:"RUN_QUERY"})},S=function(e,t){var n=Object(Ue.a)(v.current);n[t]=e,d({type:"SET_QUERY",payload:n})},E=function(e,t){var n=i[t],a=n.index,r=n.values,c=a+e;c<0||c>=r.length||(S(r[c]||"",t),d({type:"SET_QUERY_HISTORY_BY_INDEX",payload:{value:{values:r,index:c},queryNumber:t}}))};return Object(u.jsx)(u.Fragment,{children:Object(u.jsxs)(Rt.a,{expanded:p,onChange:function(){return f((function(e){return!e}))},children:[Object(u.jsxs)(It.a,{expandIcon:Object(u.jsx)(g.a,{children:Object(u.jsx)(Vt.a,{})}),"aria-controls":"panel1a-content",id:"panel1a-header",sx:{alignItems:"flex-start",padding:"15px"},children:[Object(u.jsx)(O.a,{mr:2,children:Object(u.jsx)(h.a,{variant:"h6",component:"h2",children:"Query Configuration"})}),Object(u.jsx)(O.a,{flexGrow:1,onClick:function(e){return e.stopPropagation()},onFocusCapture:function(e){return e.stopPropagation()},children:Object(u.jsx)(tn.a,{disablePortal:!p,container:x.current,children:c.map((function(e,n){return Object(u.jsxs)(O.a,{display:"grid",gridTemplateColumns:"1fr auto",gap:"4px",width:"100%",mb:n===c.length-1?0:2,children:[Object(u.jsx)(Pt,{server:r,query:c[n],index:n,oneLiner:!p,autocomplete:l,queryHistory:i[n],error:t,setHistoryIndex:E,runQuery:m,setQuery:S}),0===n&&Object(u.jsx)(y.a,{title:"Execute Query",children:Object(u.jsx)(g.a,{onClick:m,children:Object(u.jsx)(en.a,{})})}),n>0&&Object(u.jsx)(y.a,{title:"Remove Query",children:Object(u.jsx)(g.a,{onClick:function(){return function(e){var t=Object(Ue.a)(v.current);t.splice(e,1),d({type:"SET_QUERY",payload:t})}(n)},children:Object(u.jsx)(Kt.a,{})})})]},n)}))})})]}),Object(u.jsx)(kt.a,{children:Object(u.jsxs)(Ut.a,{container:!0,columnSpacing:2,children:[Object(u.jsxs)(Ut.a,{item:!0,xs:6,minWidth:400,children:[Object(u.jsx)(Yn,{error:t}),Object(u.jsx)("div",{ref:x}),c.length<2&&Object(u.jsx)(O.a,{display:"inline-block",minHeight:"40px",mt:2,children:Object(u.jsxs)(bt.a,{onClick:function(){return d({type:"SET_QUERY",payload:[].concat(Object(Ue.a)(v.current),[""])})},variant:"outlined",children:[Object(u.jsx)(Zt.a,{sx:{fontSize:16,marginRight:"4px"}}),Object(u.jsx)("span",{style:{lineHeight:1,paddingTop:"1px"},children:"Query"})]})})]}),Object(u.jsx)(Ut.a,{item:!0,xs:!0,children:Object(u.jsx)(Gt,{setDuration:function(e){return d({type:"SET_DURATION",payload:e})},duration:s})}),Object(u.jsx)(Ut.a,{item:!0,xs:12,pt:1,children:Object(u.jsx)(Fn,{})})]})})]})})},zn=n(81),Gn=n.n(zn),Wn=n(166),Vn=n(167),Jn=qn(),Kn=Pn().serverURL,Xn=function(){var e=de(),t=e.query,n=e.displayType,r=e.serverUrl,c=e.time.period,i=e.queryControls.nocache,s=Un(),l=s.basicData,u=s.bearerData,d=s.authMethod,j=Pe().customStep,b=Object(a.useState)(!1),p=Object(o.a)(b,2),O=p[0],h=p[1],f=Object(a.useState)(),x=Object(o.a)(f,2),v=x[0],m=x[1],y=Object(a.useState)(),g=Object(o.a)(y,2),S=g[0],E=g[1],_=Object(a.useState)(),w=Object(o.a)(_,2),C=w[0],A=w[1],R=Object(a.useState)(),I=Object(o.a)(R,2),k=I[0],U=I[1];Object(a.useEffect)((function(){C&&(m(void 0),E(void 0))}),[C]);var M=Object(a.useMemo)((function(){if(!k)return!0;var e=(k.end-k.start)/3,t=e/(c.end-c.start)>=.7,n=c.end>k.end+e,a=c.start<k.start-e;return t||n||a}),[c]),H=function(){var e=Object(Wn.a)(Gn.a.mark((function e(){var t,a,r,i,o,s;return Gn.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(null===D||void 0===D?void 0:D.length){e.next=2;break}return e.abrupt("return");case 2:return h(!0),U(c),t=new Headers,"BASIC_AUTH"===d&&t.set("Authorization","Basic "+btoa("".concat((null===l||void 0===l?void 0:l.login)||"",":").concat((null===l||void 0===l?void 0:l.password)||""))),"BEARER_AUTH"===d&&t.set("Authorization",(null===u||void 0===u?void 0:u.token)||""),e.prev=7,e.delegateYield(Gn.a.mark((function e(){var c,l,u,d,j;return Gn.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,Promise.all(D.map((function(e){return fetch(e,{headers:t})})));case 2:c=e.sent,l=[],u=1,a=!1,r=!1,e.prev=7,o=Object(Vn.a)(c);case 9:return e.next=11,o.next();case 11:if(!(a=!(s=e.sent).done)){e.next=20;break}return d=s.value,e.next=15,d.json();case 15:j=e.sent,d.ok?(A(void 0),l.push.apply(l,Object(Ue.a)(j.data.result.map((function(e){return e.group=u,e})))),u++):A("".concat(j.errorType,"\r\n").concat(null===j||void 0===j?void 0:j.error));case 17:a=!1,e.next=9;break;case 20:e.next=26;break;case 22:e.prev=22,e.t0=e.catch(7),r=!0,i=e.t0;case 26:if(e.prev=26,e.prev=27,!a||null==o.return){e.next=31;break}return e.next=31,o.return();case 31:if(e.prev=31,!r){e.next=34;break}throw i;case 34:return e.finish(31);case 35:return e.finish(26);case 36:"chart"===n?m(l):E(l);case 37:case"end":return e.stop()}}),e,null,[[7,22,26,36],[27,,31,35]])}))(),"t0",9);case 9:e.next=14;break;case 11:e.prev=11,e.t1=e.catch(7),e.t1 instanceof Error&&A("".concat(e.t1.name,": ").concat(e.t1.message));case 14:h(!1);case 15:case"end":return e.stop()}}),e,null,[[7,11]])})));return function(){return e.apply(this,arguments)}}(),D=Object(a.useMemo)((function(){var e=Jn?Kn:r;if(c)if(e)if(t.every((function(e){return!e.trim()})))A($e.validQuery);else{if(function(e){var t;try{t=new URL(e)}catch(n){return!1}return"http:"===t.protocol||"https:"===t.protocol}(e)){var a=(c.end-c.start)/2,o=Object(T.a)(Object(T.a)({},c),{},{start:c.start-a,end:c.end+a});return j.enable&&(o.step=j.value),t.filter((function(e){return e.trim()})).map((function(t){return"chart"===n?function(e,t,n,a){return"".concat(e,"/api/v1/query_range?query=").concat(encodeURIComponent(t),"&start=").concat(n.start,"&end=").concat(n.end,"&step=").concat(n.step).concat(a?"&nocache=1":"")}(e,t,o,i):function(e,t,n){return"".concat(e,"/api/v1/query?query=").concat(encodeURIComponent(t),"&start=").concat(n.start,"&end=").concat(n.end,"&step=").concat(n.step)}(e,t,c)}))}A($e.validServer)}else A($e.emptyServer)}),[r,c,n,j]);return Object(a.useEffect)((function(){U(void 0)}),[t]),Object(a.useEffect)((function(){H()}),[r,n,j]),Object(a.useEffect)((function(){M&&H()}),[c]),{fetchUrl:D,isLoading:O,graphData:v,liveData:S,error:C}},Zn=function(e){var t=e.data,n=Object(a.useContext)(d).showInfoMessage,r=Object(a.useMemo)((function(){return JSON.stringify(t,null,2)}),[t]);return Object(u.jsxs)(O.a,{position:"relative",children:[Object(u.jsx)(O.a,{flexDirection:"column",justifyContent:"flex-end",display:"flex",style:{position:"fixed",right:"16px"},children:Object(u.jsx)(bt.a,{variant:"outlined",onClick:function(e){navigator.clipboard.writeText(r),n("Formatted JSON has been copied"),e.preventDefault()},children:"Copy JSON"})}),Object(u.jsx)("pre",{children:r})]})},$n=function(){var e=de(),t=e.displayType,n=e.time.period,a=Xn(),r=a.isLoading,c=a.liveData,i=a.graphData,o=a.error;return Object(u.jsxs)(u.Fragment,{children:[Object(u.jsx)(b.a,{position:"static",children:Object(u.jsxs)(p.a,{children:[Object(u.jsxs)(O.a,{display:"flex",children:[Object(u.jsxs)(h.a,{variant:"h5",children:[Object(u.jsx)("span",{style:{fontWeight:"bolder"},children:"VM"}),Object(u.jsx)("span",{style:{fontWeight:"lighter"},children:"UI"})]}),Object(u.jsx)("div",{style:{fontSize:"10px",marginTop:"-2px"},children:Object(u.jsx)("div",{children:"BETA"})})]}),Object(u.jsx)("div",{style:{fontSize:"10px",position:"absolute",top:"40px",opacity:".4"},children:Object(u.jsx)(f.a,{color:"inherit",href:"https://github.com/VictoriaMetrics/VictoriaMetrics/issues/new",target:"_blank",children:"Create an issue"})}),Object(u.jsx)(O.a,{ml:4,flexGrow:1,children:Object(u.jsx)(ye,{})}),Object(u.jsx)(ke,{})]})}),Object(u.jsxs)(O.a,{p:4,display:"grid",gridTemplateRows:"auto 1fr",gap:"20px",style:{minHeight:"calc(100vh - 64px)"},children:[Object(u.jsx)(O.a,{children:Object(u.jsx)(Qn,{error:o})}),Object(u.jsxs)(O.a,{height:"100%",children:[r&&Object(u.jsx)(x.a,{in:r,style:{transitionDelay:r?"300ms":"0ms"},children:Object(u.jsx)(O.a,{alignItems:"center",justifyContent:"center",flexDirection:"column",display:"flex",style:{width:"100%",maxWidth:"calc(100vw - 32px)",position:"absolute",height:"50%",background:"linear-gradient(rgba(255,255,255,.7), rgba(255,255,255,.7), rgba(255,255,255,0))"},children:Object(u.jsx)(v.a,{})})}),Object(u.jsxs)(O.a,{height:"100%",bgcolor:"#fff",children:[o&&Object(u.jsx)(l.a,{color:"error",severity:"error",style:{fontSize:"14px",whiteSpace:"pre-wrap"},children:o}),i&&n&&"chart"===t&&Object(u.jsx)(yt,{data:i}),c&&"code"===t&&Object(u.jsx)(Zn,{data:c}),c&&"table"===t&&Object(u.jsx)(At,{data:c})]})]})]})]})},ea=n(311),ta=n(354),na=n(173),aa=Object(na.a)({palette:{primary:{main:"#3F51B5"},secondary:{main:"#F50057"},error:{main:"#FF4141"}},components:{MuiFormHelperText:{styleOverrides:{root:{position:"absolute",top:"36px",left:"2px",margin:0}}},MuiInputLabel:{styleOverrides:{root:{fontSize:"12px",letterSpacing:"normal",lineHeight:"1"}}},MuiInputBase:{styleOverrides:{root:{"&.Mui-focused fieldset":{borderWidth:"1px !important"}}}},MuiSwitch:{defaultProps:{color:"secondary"}},MuiAccordion:{styleOverrides:{root:{boxShadow:"rgba(0, 0, 0, 0.16) 0px 1px 4px;"}}},MuiPaper:{styleOverrides:{elevation3:{boxShadow:"rgba(0, 0, 0, 0.2) 0px 3px 8px;"}}},MuiIconButton:{defaultProps:{size:"large"},styleOverrides:{sizeLarge:{borderRadius:"20%",height:"40px",width:"41px"},sizeMedium:{borderRadius:"20%"},sizeSmall:{borderRadius:"20%"}}}},typography:{fontSize:10}}),ra=n(310),ca=n(306),ia=n(168),oa=function(){return Object(u.jsxs)(u.Fragment,{children:[Object(u.jsx)(ra.a,{})," ",Object(u.jsxs)(ca.b,{dateAdapter:ia.a,children:[" ",Object(u.jsx)(ea.a,{injectFirst:!0,children:Object(u.jsxs)(ta.a,{theme:aa,children:["  ",Object(u.jsxs)(pe,{children:[" ",Object(u.jsxs)(Mn,{children:[" ",Object(u.jsxs)(Ye,{children:[" ",Object(u.jsxs)(j,{children:[" ",Object(u.jsx)($n,{})]})]})]})]})]})})]})]})},sa=function(e){e&&e instanceof Function&&n.e(3).then(n.bind(null,356)).then((function(t){var n=t.getCLS,a=t.getFID,r=t.getFCP,c=t.getLCP,i=t.getTTFB;n(e),a(e),r(e),c(e),i(e)}))};i.a.render(Object(u.jsx)(r.a.StrictMode,{children:Object(u.jsx)(oa,{})}),document.getElementById("root")),sa()}},[[234,1,2]]]);
\ No newline at end of file
diff --git a/app/vmui/packages/vmui/src/components/Home/Configurator/Query/ServerConfigurator.tsx b/app/vmui/packages/vmui/src/components/Home/Configurator/Query/ServerConfigurator.tsx
index aa9f4e832..e5a72920a 100644
--- a/app/vmui/packages/vmui/src/components/Home/Configurator/Query/ServerConfigurator.tsx
+++ b/app/vmui/packages/vmui/src/components/Home/Configurator/Query/ServerConfigurator.tsx
@@ -1,9 +1,10 @@
-import React, {FC, useState} from "react";
+import React, {FC, useEffect, useState} from "react";
 import {Box, TextField, Tooltip, IconButton} from "@mui/material";
 import SecurityIcon from "@mui/icons-material/Security";
 import {useAppDispatch, useAppState} from "../../../../state/common/StateContext";
 import {AuthDialog} from "../Auth/AuthDialog";
 import {ErrorTypes} from "../../../../types";
+import {getAppModeEnable, getAppModeParams} from "../../../../utils/app-mode";
 
 export interface ServerConfiguratorProps {
   error?: ErrorTypes | string;
@@ -11,6 +12,9 @@ export interface ServerConfiguratorProps {
 
 const ServerConfigurator: FC<ServerConfiguratorProps> = ({error}) => {
 
+  const appModeEnable = getAppModeEnable();
+  const {serverURL: appServerUrl} = getAppModeParams();
+
   const {serverUrl} = useAppState();
   const dispatch = useAppDispatch();
 
@@ -19,9 +23,13 @@ const ServerConfigurator: FC<ServerConfiguratorProps> = ({error}) => {
   };
   const [dialogOpen, setDialogOpen] = useState(false);
 
+  useEffect(() => {
+    if (appModeEnable) dispatch({type: "SET_SERVER", payload: appServerUrl});
+  }, [appServerUrl]);
+
   return <>
     <Box display="grid" gridTemplateColumns="1fr auto" gap="4px" alignItems="center" width="100%" mb={2} minHeight={50}>
-      <TextField variant="outlined" fullWidth label="Server URL" value={serverUrl}
+      <TextField variant="outlined" fullWidth label="Server URL" value={serverUrl || ""} disabled={appModeEnable}
         error={error === ErrorTypes.validServer || error === ErrorTypes.emptyServer}
         inputProps={{style: {fontFamily: "Monospace"}}}
         onChange={onSetServer}/>
diff --git a/app/vmui/packages/vmui/src/components/Home/Configurator/Query/useFetchQuery.ts b/app/vmui/packages/vmui/src/components/Home/Configurator/Query/useFetchQuery.ts
index acb897d8d..8a4fa990f 100644
--- a/app/vmui/packages/vmui/src/components/Home/Configurator/Query/useFetchQuery.ts
+++ b/app/vmui/packages/vmui/src/components/Home/Configurator/Query/useFetchQuery.ts
@@ -6,6 +6,10 @@ import {isValidHttpUrl} from "../../../../utils/url";
 import {useAuthState} from "../../../../state/auth/AuthStateContext";
 import {ErrorTypes, TimeParams} from "../../../../types";
 import {useGraphState} from "../../../../state/graph/GraphStateContext";
+import {getAppModeEnable, getAppModeParams} from "../../../../utils/app-mode";
+
+const appModeEnable = getAppModeEnable();
+const {serverURL: appServerUrl} = getAppModeParams();
 
 export const useFetchQuery = (): {
   fetchUrl?: string[],
@@ -80,18 +84,19 @@ export const useFetchQuery = (): {
   };
 
   const fetchUrl = useMemo(() => {
+    const server = appModeEnable ? appServerUrl : serverUrl;
     if (!period) return;
-    if (!serverUrl) {
+    if (!server) {
       setError(ErrorTypes.emptyServer);
     } else if (query.every(q => !q.trim())) {
       setError(ErrorTypes.validQuery);
-    } else if (isValidHttpUrl(serverUrl)) {
+    } else if (isValidHttpUrl(server)) {
       const duration = (period.end - period.start) / 2;
       const bufferPeriod = {...period, start: period.start - duration, end: period.end + duration};
       if (customStep.enable) bufferPeriod.step = customStep.value;
       return query.filter(q => q.trim()).map(q => displayType === "chart"
-        ? getQueryRangeUrl(serverUrl, q, bufferPeriod, nocache)
-        : getQueryUrl(serverUrl, q, period));
+        ? getQueryRangeUrl(server, q, bufferPeriod, nocache)
+        : getQueryUrl(server, q, period));
     } else {
       setError(ErrorTypes.validServer);
     }
diff --git a/app/vmui/packages/vmui/src/utils/app-mode.ts b/app/vmui/packages/vmui/src/utils/app-mode.ts
new file mode 100644
index 000000000..3dc88975f
--- /dev/null
+++ b/app/vmui/packages/vmui/src/utils/app-mode.ts
@@ -0,0 +1,12 @@
+export interface AppParams {
+  serverURL: string
+}
+
+const getAppModeParams = (): AppParams => {
+  const dataParams = document.getElementById("root")?.dataset.params || "{}";
+  return JSON.parse(dataParams);
+};
+
+const getAppModeEnable = (): boolean => !!Object.keys(getAppModeParams()).length;
+
+export {getAppModeEnable, getAppModeParams};
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index 8c654b399..d33e2bc80 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -6,19 +6,26 @@ sort: 15
 
 ## tip
 
+* FEATURE: [VictoriaMetrics enterprise](https://victoriametrics.com/enterprise.html): add multi-level downsampling support. See [these docs](https://docs.victoriametrics.com/#downsampling) and [this feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/36).
 * FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): add ability to analyze the correlation between two queries on a single graph. Just click `+Query` button, enter the second query in the newly appeared input field and press `Ctrl+Enter`. Results for both queries should be displayed simultaneously on the same graph. Every query has its own vertical scale, which is displayed on the left and the right side of the graph. Lines for the second query are dashed. See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/1916).
+* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): add ability to override the interval between returned datapoints. By default it is automatically calculated depending on the selected time range and horizontal resolution of the graph. Now it is possible to override it with custom values. This may be useful during data exploration and debugging.
 * FEATURE: accept optional `extra_filters[]=series_selector` query args at Prometheus query APIs additionally to `extra_label` query args. This allows enforcing additional filters for all the Prometheus query APIs by using [vmgateway](https://docs.victoriametrics.com/vmgateway.html) or [vmauth](https://docs.victoriametrics.com/vmauth.html). See [this feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1863).
 * FEATURE: [vmauth](https://docs.victoriametrics.com/vmauth.html): allow specifying `http` and `https` urls in `-auth.config` command-line flag. See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/1898). Thanks for @TFM93 .
 * FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent.html): allow specifying `http` and `https` urls in the following command-line flags: `-promscrape.config`, `-remoteWrite.relabelConfig` and `-remoteWrite.urlRelabelConfig`.
 * FEATURE: vminsert: allow specifying `http` and `https` urls in `-relabelConfig` command-line flag.
 * FEATURE: vminsert: add `-maxLabelValueLen` command-line flag for the ability to configure the maximum length of label value. See [this feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1908).
 * FEATURE: preserve the order of time series passed to [limit_offset](https://docs.victoriametrics.com/MetricsQL.html#limit_offset) function. This allows implementing series paging via `limit_offset(limit, offset, sort_by_label(...))`. See [this](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1920) and [this](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/951) issues.
-* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): add ability to override the interval between returned datapoints. By default it is automatically calculated depending on the selected time range and horizontal resolution of the graph. Now it is possible to override it with custom values. This may be useful during data exploration and debugging.
+* FEATURE: automaticall convert `(value1|...|valueN)` into `{value1,...,valueN}` inside `__graphite__` pseudo-label. This allows using [Grafana multi-value template variables](https://grafana.com/docs/grafana/latest/variables/formatting-multi-value-variables/) inside `__graphite__` pseudo-label. For example, `{__graphite__=~"foo.($bar)"}` is expanded to `{__graphite__=~"foo.{x,y}"}` if both `x` and `y` are selected for `$bar` template variable. See [these docs](https://docs.victoriametrics.com/#selecting-graphite-metrics) for details.
+* FEATURE: add [timestamp_with_name](https://docs.victoriametrics.com/MetricsQL.html#timestamp_with_name) function. It works the same as [timestamp](https://docs.victoriametrics.com/MetricsQL.html#timestamp), but leaves the original time series names, so it can be used in queries, which match multiple time series names: `timestamp_with_name({foo="bar"}[1h])`. See [this comment](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/949#issuecomment-995222388) for more context.
 
 * BUGFIX: fix `unaligned 64-bit atomic operation` panic on 32-bit architectures, which has been introduced in v1.70.0. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1944).
 * BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert.html): restore the ability to use `$labels.alertname` in labels templating. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1921).
 * BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): add missing `query` caption to the input field for the query. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1900).
 * BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): fix navigation over query history with `Ctrl+up/down` and fix zoom relatively to the cursor position. See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/1936).
+* BUGFIX: deduplicate samples more thoroughly if [deduplication](https://docs.victoriametrics.com/#deduplication) is enabled. Previously some duplicate samples may be left on disk for time series with high churn rate. This may result in bigger storage space requirements.
+* BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent.html): follow up to 5 redirects when `follow_redirects: true` is set for a particular scrape config. Previously only a single redirect was performed in this case. It is expected these redirects are performed to the original hostname. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1945).
+* BUGFIX: de-duplicate data exported via [/api/v1/export/csv](https://docs.victoriametrics.com/#how-to-export-csv-data) by default if [deduplication](https://docs.victoriametrics.com/#deduplication) is enabled. The de-duplication can be disabled by passing `reduce_mem_usage=1` query arg to `/api/v1/export/csv`. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1837).
+* BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert.html): properly store [historical data](https://docs.victoriametrics.com/vmalert.html#rules-backfilling) to old Prometheus versions. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1943).
 
 
 ## [v1.70.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.70.0)
diff --git a/docs/Cluster-VictoriaMetrics.md b/docs/Cluster-VictoriaMetrics.md
index 57465a748..dcc2b26be 100644
--- a/docs/Cluster-VictoriaMetrics.md
+++ b/docs/Cluster-VictoriaMetrics.md
@@ -315,7 +315,8 @@ It is recommended leaving the following amounts of spare resources:
 
 * 50% of free RAM across all the node types for reducing the probability of OOM (out of memory) crashes and slowdowns during temporary spikes in workload.
 * 50% of spare CPU across all the node types for reducing the probability of slowdowns during temporary spikes in workload.
-* At least 30% of free storage space at the directory pointed by `-storageDataPath` command-line flag at `vmstorage` nodes.
+* At least 30% of free storage space at the directory pointed by `-storageDataPath` command-line flag at `vmstorage` nodes. See also `-storage.minFreeDiskSpaceBytes` command-line flag [description for vmstorage](#list-of-command-line-flags-for-vmstorage).
+
 
 Some capacity planning tips for VictoriaMetrics cluster:
 
@@ -407,6 +408,11 @@ Restoring from backup:
 3. Start `vmstorage` node.
 
 
+## Downsampling
+
+Downsampling is available in [enterprise version of VictoriaMetrics](https://victoriametrics.com/enterprise.html). It is configured with `-downsampling.period` command-line flag. The same flag value must be passed to both `vmstorage` and `vmselect` nodes. See [these docs](https://docs.victoriametrics.com/#downsampling) for details.
+
+
 ## Profiling
 
 All the cluster components provide the following handlers for [profiling](https://blog.golang.org/profiling-go-programs):
@@ -484,6 +490,8 @@ Below is the output for `/path/to/vminsert -help`:
     	Whether to enable reading flags from environment variables additionally to command line. Command line flag values have priority over values from environment vars. Flags are read only from command line if this flag isn't set. See https://docs.victoriametrics.com/#environment-variables for more details
   -envflag.prefix string
     	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
   -fs.disableMmap
     	Whether to use pread() instead of mmap() for reading data files. By default mmap() is used for 64-bit arches and pread() is used for 32-bit arches, since they cannot read data files bigger than 2^32 bytes in memory. mmap() is usually faster for reading small data chunks than pread()
   -graphiteListenAddr string
@@ -596,12 +604,17 @@ Below is the output for `/path/to/vmselect -help`:
     	Path to directory for cache files. Cache isn't saved if empty
   -dedup.minScrapeInterval duration
     	Leave only the first sample in every time series per each discrete interval equal to -dedup.minScrapeInterval > 0. See https://docs.victoriametrics.com/#deduplication for details
+  -downsampling.period array
+    	Comma-separated downsampling periods in the format 'offset:period'. For example, '30d:10m' instructs to leave a single sample per 10 minutes for samples older than 30 days. See https://docs.victoriametrics.com/#downsampling for details
+    	Supports an array of values separated by comma or specified via multiple flags.
   -enableTCP6
     	Whether to enable IPv6 for listening and dialing. By default only IPv4 TCP and UDP is used
   -envflag.enable
     	Whether to enable reading flags from environment variables additionally to command line. Command line flag values have priority over values from environment vars. Flags are read only from command line if this flag isn't set. See https://docs.victoriametrics.com/#environment-variables for more details
   -envflag.prefix string
     	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
   -fs.disableMmap
     	Whether to use pread() instead of mmap() for reading data files. By default mmap() is used for 64-bit arches and pread() is used for 32-bit arches, since they cannot read data files bigger than 2^32 bytes in memory. mmap() is usually faster for reading small data chunks than pread()
   -graphiteTrimTimestamp duration
@@ -647,6 +660,10 @@ Below is the output for `/path/to/vmselect -help`:
     	Whether to deny partial responses if a part of -storageNode instances fail to perform queries; this trades availability over consistency; see also -search.maxQueryDuration
   -search.disableCache
     	Whether to disable response caching. This may be useful during data backfilling
+  -search.graphiteMaxPointsPerSeries int
+    	The maximum number of points per series Graphite render API can return (default 1000000)
+  -search.graphiteStorageStep duration
+    	The interval between datapoints stored in the database. It is used at Graphite Render API handler for normalizing the interval between datapoints in case it isn't normalized. It can be overriden by sending 'storage_step' query arg to /render API or by sending the desired interval via 'Storage-Step' http header during querying /render API (default 10s)
   -search.latencyOffset duration
     	The time when data points become visible in query results after the collection. Too small value can result in incomplete last points for query results (default 30s)
   -search.logSlowQueryDuration duration
@@ -715,12 +732,17 @@ Below is the output for `/path/to/vmstorage -help`:
     	Leave only the first sample in every time series per each discrete interval equal to -dedup.minScrapeInterval > 0. See https://docs.victoriametrics.com/#deduplication for details
   -denyQueriesOutsideRetention
     	Whether to deny queries outside of the configured -retentionPeriod. When set, then /api/v1/query_range would return '503 Service Unavailable' error for queries with 'from' value outside -retentionPeriod. This may be useful when multiple data sources with distinct retentions are hidden behind query-tee
+  -downsampling.period array
+    	Comma-separated downsampling periods in the format 'offset:period'. For example, '30d:10m' instructs to leave a single sample per 10 minutes for samples older than 30 days. See https://docs.victoriametrics.com/#downsampling for details
+    	Supports an array of values separated by comma or specified via multiple flags.
   -enableTCP6
     	Whether to enable IPv6 for listening and dialing. By default only IPv4 TCP and UDP is used
   -envflag.enable
     	Whether to enable reading flags from environment variables additionally to command line. Command line flag values have priority over values from environment vars. Flags are read only from command line if this flag isn't set. See https://docs.victoriametrics.com/#environment-variables for more details
   -envflag.prefix string
     	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
   -finalMergeDelay duration
     	The delay before starting final merge for per-month partition after no new data is ingested into it. Final merge may require additional disk IO and CPU resources. Final merge may increase query speed and reduce disk space usage in some cases. Zero value disables final merge
   -forceFlushAuthKey string
diff --git a/docs/MetricsQL.md b/docs/MetricsQL.md
index 6ad67f3a6..dc3912cb6 100644
--- a/docs/MetricsQL.md
+++ b/docs/MetricsQL.md
@@ -30,7 +30,7 @@ MetricsQL implements [PromQL](https://medium.com/@valyala/promql-tutorial-for-be
 
 This functionality can be evaluated at [an editable Grafana dashboard](https://play-grafana.victoriametrics.com/d/4ome8yJmz/node-exporter-on-victoriametrics-demo) or at your own [VictoriaMetrics instance](https://docs.victoriametrics.com/#how-to-start-victoriametrics).
 
-- Graphite-compatible filters can be passed via `{__graphite__="foo.*.bar"}` syntax. This is equivalent to `{__name__=~"foo[.][^.]*[.]bar"}`, but usually works faster and is easier to use when migrating from Graphite. VictoriaMetrics also can be used as Graphite datasource in Grafana. See [these docs](https://docs.victoriametrics.com/#graphite-api-usage) for details. See also [label_graphite_group](#label_graphite_group) function, which can be used for extracting the given groups from Graphite metric name.
+- Graphite-compatible filters can be passed via `{__graphite__="foo.*.bar"}` syntax. See [these docs](https://docs.victoriametrics.com/#selecting-graphite-metrics). VictoriaMetrics also can be used as Graphite datasource in Grafana. See [these docs](https://docs.victoriametrics.com/#graphite-api-usage) for details. See also [label_graphite_group](#label_graphite_group) function, which can be used for extracting the given groups from Graphite metric name.
 - Lookbehind window in square brackets may be omitted. VictoriaMetrics automatically selects the lookbehind window depending on the current step used for building the graph (e.g. `step` query arg passed to [/api/v1/query_range](https://prometheus.io/docs/prometheus/latest/querying/api/#range-queries)). For instance, the following query is valid in VictoriaMetrics: `rate(node_network_receive_bytes_total)`. It is equivalent to `rate(node_network_receive_bytes_total[$__interval])` when used in Grafana.
 - [Aggregate functions](#aggregate-functions) accept arbitrary number of args. For example, `avg(q1, q2, q3)` would return the average values for every point across time series returned by `q1`, `q2` and `q3`.
 - [offset](https://prometheus.io/docs/prometheus/latest/querying/basics/#offset-modifier), lookbehind window in square brackets and `step` value for [subquery](#subqueries) may refer to the current step aka `$__interval` value from Grafana with `[Ni]` syntax. For instance, `rate(metric[10i] offset 5i)` would return per-second rate over a range covering 10 previous steps with the offset of 5 steps.
@@ -316,7 +316,11 @@ See also [implicit query conversions](#implicit-query-conversions).
 
 #### timestamp
 
-`timestamp(series_selector[d])` returns the timestamp in seconds for the last raw sample on the given lookbehind window `d` per each time series returned from the given [series_selector](https://prometheus.io/docs/prometheus/latest/querying/basics/#time-series-selectors). Metric names are stripped from the resulting rollups. This function is supported by PromQL.
+`timestamp(series_selector[d])` returns the timestamp in seconds for the last raw sample on the given lookbehind window `d` per each time series returned from the given [series_selector](https://prometheus.io/docs/prometheus/latest/querying/basics/#time-series-selectors). Metric names are stripped from the resulting rollups. This function is supported by PromQL. See also [timestamp_with_name](#timestamp_with_name).
+
+#### timestamp_with_name
+
+`timestamp_with_name(series_selector[d])` returns the timestamp in seconds for the last raw sample on the given lookbehind window `d` per each time series returned from the given [series_selector](https://prometheus.io/docs/prometheus/latest/querying/basics/#time-series-selectors). Metric names are preserved in the resulting rollups. See also [timestamp](#timestamp).
 
 #### tfirst_over_time
 
@@ -914,11 +918,11 @@ See also [implicit query conversions](#implicit-query-conversions).
 
 ## Subqueries
 
-MetricsQL supports and extends PromQL subqueries. See [this article](https://valyala.medium.com/prometheus-subqueries-in-victoriametrics-9b1492b720b3) for details. Any nested [rollup functions](#rollup-functions) form a subquery. Nested rollup functions can be implicit thanks to the [implicit query conversions](#implicit-query-conversions). For example, `delta(sum(m))` is implicitly converted to `delta(sum(default_rollup(m[1i]))[1i:1i])`, so it becomes a subquery, since it contains [default_rollup](#default_rollup) nested into [delta](#delta).
+MetricsQL supports and extends PromQL subqueries. See [this article](https://valyala.medium.com/prometheus-subqueries-in-victoriametrics-9b1492b720b3) for details. Any [rollup function](#rollup-functions) for something other than [series selector](https://prometheus.io/docs/prometheus/latest/querying/basics/#time-series-selectors) form a subquery. Nested rollup functions can be implicit thanks to the [implicit query conversions](#implicit-query-conversions). For example, `delta(sum(m))` is implicitly converted to `delta(sum(default_rollup(m[1i]))[1i:1i])`, so it becomes a subquery, since it contains [default_rollup](#default_rollup) nested into [delta](#delta).
 
 VictoriaMetrics performs subqueries in the following way:
 
-* It calculates the inner rollup function using the `step` value from the outer rollup function. For example, if `max_over_time(rate(http_requests_total[5m])[1h:30s])` is executed, then the `rate(http_requests_total[5m])` is calculated with the `step` equal to `30s`. The resulting data points are algined by the `step`.
+* It calculates the inner rollup function using the `step` value from the outer rollup function. For example, for expression `max_over_time(rate(http_requests_total[5m])[1h:30s])` the inner function `rate(http_requests_total[5m])` is calculated with `step=30s`. The resulting data points are aligned by the `step`.
 * It calculates the outer rollup function over the results of the inner rollup function using the `step` value passed by Grafana to [/api/v1/query_range](https://prometheus.io/docs/prometheus/latest/querying/api/#range-queries).
 
 
diff --git a/docs/README.md b/docs/README.md
index 9fa9498cb..5a444567c 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -416,9 +416,15 @@ The `/api/v1/export` endpoint should return the following response:
 Data sent to VictoriaMetrics via `Graphite plaintext protocol` may be read via the following APIs:
 
 * [Graphite API](#graphite-api-usage)
-* [Prometheus querying API](#prometheus-querying-api-usage). VictoriaMetrics supports `__graphite__` pseudo-label for selecting time series with Graphite-compatible filters in [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html). For example, `{__graphite__="foo.*.bar"}` is equivalent to `{__name__=~"foo[.][^.]*[.]bar"}`, but it works faster and it is easier to use when migrating from Graphite to VictoriaMetrics. See [docs for Graphite paths and wildcards](https://graphite.readthedocs.io/en/latest/render_api.html#paths-and-wildcards). VictoriaMetrics also supports [label_graphite_group](https://docs.victoriametrics.com/MetricsQL.html#label_graphite_group) function for extracting the given groups from Graphite metric name.
+* [Prometheus querying API](#prometheus-querying-api-usage). See also [selecting Graphite metrics](#selecting-graphite-metrics).
 * [go-graphite/carbonapi](https://github.com/go-graphite/carbonapi/blob/main/cmd/carbonapi/carbonapi.example.victoriametrics.yaml)
 
+## Selecting Graphite metrics
+
+VictoriaMetrics supports `__graphite__` pseudo-label for selecting time series with Graphite-compatible filters in [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html). For example, `{__graphite__="foo.*.bar"}` is equivalent to `{__name__=~"foo[.][^.]*[.]bar"}`, but it works faster and it is easier to use when migrating from Graphite to VictoriaMetrics. See [docs for Graphite paths and wildcards](https://graphite.readthedocs.io/en/latest/render_api.html#paths-and-wildcards). VictoriaMetrics also supports [label_graphite_group](https://docs.victoriametrics.com/MetricsQL.html#label_graphite_group) function for extracting the given groups from Graphite metric name.
+
+The `__graphite__` pseudo-label supports e.g. alternate regexp filters such as `(value1|...|valueN)`. They are transparently converted to `{value1,...,valueN}` syntax [used in Graphite](https://graphite.readthedocs.io/en/latest/render_api.html#paths-and-wildcards). This allows using [multi-value template variables in Grafana](https://grafana.com/docs/grafana/latest/variables/formatting-multi-value-variables/) inside `__graphite__` pseudo-label. For example, Grafana expands `{__graphite__=~"foo.($bar).baz"}` into `{__graphite__=~"foo.(x|y).baz"}` if `$bar` template variable contains `x` and `y` values. In this case the query is automatically converted into `{__graphite__=~"foo.{x,y}.baz"}` before execution.
+
 ## How to send data from OpenTSDB-compatible agents
 
 VictoriaMetrics supports [telnet put protocol](http://opentsdb.net/docs/build/html/api_telnet/put.html)
@@ -559,8 +565,7 @@ VictoriaMetrics accepts optional query args: `extra_label=<label_name>=<label_va
 
 [Contact us](mailto:sales@victoriametrics.com) if you need assistance with such a proxy.
 
-VictoriaMetrics supports `__graphite__` pseudo-label for filtering time series with Graphite-compatible filters in [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html).
-For example, `{__graphite__="foo.*.bar"}` is equivalent to `{__name__=~"foo[.][^.]*[.]bar"}`, but it works faster and it is easier to use when migrating from Graphite to VictoriaMetrics. See [docs for Graphite paths and wildcards](https://graphite.readthedocs.io/en/latest/render_api.html#paths-and-wildcards). See also [label_graphite_group](https://docs.victoriametrics.com/MetricsQL.html#label_graphite_group) function.
+VictoriaMetrics supports `__graphite__` pseudo-label for filtering time series with Graphite-compatible filters in [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html). See [these docs](#selecting-graphite-metrics).
 
 
 ### Graphite Render API usage
@@ -832,7 +837,7 @@ unix timestamp in seconds or [RFC3339](https://www.ietf.org/rfc/rfc3339.txt) val
 
 The exported CSV data can be imported to VictoriaMetrics via [/api/v1/import/csv](#how-to-import-csv-data).
 
-The [deduplication](#deduplication) isn't applied for the data exported in CSV. It is expected that the de-duplication is performed during data import.
+The [deduplication](#deduplication) is applied for the data exported in CSV by default. It is possible to export raw data without de-duplication by passing `reduce_mem_usage=1` query arg to `/api/v1/export/csv`.
 
 
 ### How to export data in native format
@@ -1078,7 +1083,7 @@ It is recommended leaving the following amounts of spare resources:
 
 * 50% of free RAM for reducing the probability of OOM (out of memory) crashes and slowdowns during temporary spikes in workload.
 * 50% of spare CPU for reducing the probability of slowdowns during temporary spikes in workload.
-* At least 30% of free storage space at the directory pointed by `-storageDataPath` command-line flag.
+* At least 30% of free storage space at the directory pointed by `-storageDataPath` command-line flag. See also `-storage.minFreeDiskSpaceBytes` command-line flag description [here](#list-of-command-line-flags).
 
 
 ## High availability
@@ -1166,20 +1171,13 @@ See [these docs](https://docs.victoriametrics.com/guides/guide-vmcluster-multipl
 
 ## Downsampling
 
-There is no downsampling support at the moment, but:
+[VictoriaMetrics Enterprise](https://victoriametrics.com/enterprise.html) supports multi-level downsampling with `-downsampling.period` command-line flag. For example:
 
-* VictoriaMetrics is optimized for querying big amounts of raw data. See benchmark results for heavy queries
-  in [this article](https://medium.com/@valyala/measuring-vertical-scalability-for-time-series-databases-in-google-cloud-92550d78d8ae).
-* VictoriaMetrics has good compression for on-disk data. See [this article](https://medium.com/@valyala/victoriametrics-achieving-better-compression-for-time-series-data-than-gorilla-317bc1f95932)
-  for details.
-* The downsampling doesn't improve query performance on a long time range if the time range contains big number of time series due to [high churn rate](https://docs.victoriametrics.com/FAQ.html#what-is-high-churn-rate). The query performance depends on the number of unique time series on the selected time range, while downsampling doesn't reduce the number of unique time series in the database - it can reduce only the number of samples per each time series.
+* `-downsampling.period=30d:5m` instructs VictoriaMetrics to [deduplicate](#deduplication) samples older than 30 days with 5 minutes interval.
 
-These properties reduce the need of downsampling. We plan to implement downsampling in the future.
-See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/36) for details.
+* `-downsampling.period=30d:5m,180d:1h` instructs VictoriaMetrics to deduplicate samples older than 30 days with 5 minutes interval and to deduplicate samples older than 180 days with 1 hour interval.
 
-It is possible to (ab)use [-dedup.minScrapeInterval](#deduplication) for basic downsampling.
-For instance, if interval between the ingested data points is 15s, then `-dedup.minScrapeInterval=5m` will leave
-only a single data point out of 20 initial data points per each 5m interval.
+Downsampling is applied independently per each time series. It can reduce disk space usage and improve query performance if it is applied to time series with big number of samples per each series. The downsampling doesn't improve query performance if the database contains big number of time series with small number of samples per each series (aka [high churn rate](https://docs.victoriametrics.com/FAQ.html#what-is-high-churn-rate)), since downsamlping doesn't reduce the number of time series. So the majority of time is spent on searching for the matching time series.
 
 
 ## Multi-tenancy
@@ -1377,10 +1375,7 @@ See also more advanced [cardinality limiter in vmagent](https://docs.victoriamet
   This prevents from ingesting metrics with too many labels. It is recommended [monitoring](#monitoring) `vm_metrics_with_dropped_labels_total`
   metric in order to determine whether `-maxLabelsPerTimeseries` must be adjusted for your workload.
 
-* If you store Graphite metrics like `foo.bar.baz` in VictoriaMetrics, then use `{__graphite__="foo.*.baz"}` syntax for selecting such metrics.
-  This expression is equivalent to `{__name__=~"foo[.][^.]*[.]baz"}`, but it works faster and it is easier to use when migrating from Graphite.
-  See [docs for Graphite paths and wildcards](https://graphite.readthedocs.io/en/latest/render_api.html#paths-and-wildcards).
-  See also [label_graphite_group](https://docs.victoriametrics.com/MetricsQL.html#label_graphite_group) function, which allows extracting the given groups from Graphite metric names.
+* If you store Graphite metrics like `foo.bar.baz` in VictoriaMetrics, then `{__graphite__="foo.*.baz"}` filter can be used for selecting such metrics. See [these docs](#selecting-graphite-metrics) for details.
 
 * VictoriaMetrics ignores `NaN` values during data ingestion.
 
@@ -1446,6 +1441,18 @@ We also provide [vmbackupmanager](https://docs.victoriametrics.com/vmbackupmanag
 Enterprise binaries can be downloaded and evaluated for free from [the releases page](https://github.com/VictoriaMetrics/VictoriaMetrics/releases).
 
 
+## Benchmarks
+
+Note, that vendors (including VictoriaMetrics) are often biased when doing such tests. E.g. they try highlighting 
+the best parts of their product, while highlighting the worst parts of competing products. 
+So we encourage users and all independent third parties to conduct their becnhmarks for various products 
+they are evaluating in production and publish the results.
+
+As a reference, please see [benchmarks](https://docs.victoriametrics.com/Articles.html#benchmarks) conducted by
+VictoriaMetrics team. Please also see the [helm chart](https://github.com/VictoriaMetrics/benchmark) 
+for running ingestion benchmarks based on node_exporter metrics.
+
+
 ## Profiling
 
 VictoriaMetrics provides handlers for collecting the following [Go profiles](https://blog.golang.org/profiling-go-programs):
@@ -1573,11 +1580,14 @@ Pass `-help` to VictoriaMetrics in order to see the list of supported command-li
     	The maximum size in bytes of a single DataDog POST request to /api/v1/series
     	Supports the following optional suffixes for size values: KB, MB, GB, KiB, MiB, GiB (default 67108864)
   -dedup.minScrapeInterval duration
-    	Leave only the first sample in every time series per each discrete interval equal to -dedup.minScrapeInterval > 0. See https://docs.victoriametrics.com/#deduplication for details
+    	Leave only the first sample in every time series per each discrete interval equal to -dedup.minScrapeInterval > 0. See https://docs.victoriametrics.com/#deduplication and https://docs.victoriametrics.com/#downsampling
   -deleteAuthKey string
     	authKey for metrics' deletion via /api/v1/admin/tsdb/delete_series and /tags/delSeries
   -denyQueriesOutsideRetention
     	Whether to deny queries outside of the configured -retentionPeriod. When set, then /api/v1/query_range would return '503 Service Unavailable' error for queries with 'from' value outside -retentionPeriod. This may be useful when multiple data sources with distinct retentions are hidden behind query-tee
+  -downsampling.period array
+    	Comma-separated downsampling periods in the format 'offset:period'. For example, '30d:10m' instructs to leave a single sample per 10 minutes for samples older than 30 days. See https://docs.victoriametrics.com/#downsampling for details
+    	Supports an array of values separated by comma or specified via multiple flags.
   -dryRun
     	Whether to check only -promscrape.config and then exit. Unknown config entries are allowed in -promscrape.config by default. This can be changed with -promscrape.config.strictParse
   -enableTCP6
@@ -1586,6 +1596,8 @@ Pass `-help` to VictoriaMetrics in order to see the list of supported command-li
     	Whether to enable reading flags from environment variables additionally to command line. Command line flag values have priority over values from environment vars. Flags are read only from command line if this flag isn't set. See https://docs.victoriametrics.com/#environment-variables for more details
   -envflag.prefix string
     	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
   -finalMergeDelay duration
     	The delay before starting final merge for per-month partition after no new data is ingested into it. Final merge may require additional disk IO and CPU resources. Final merge may increase query speed and reduce disk space usage in some cases. Zero value disables final merge
   -forceFlushAuthKey string
@@ -1770,6 +1782,10 @@ Pass `-help` to VictoriaMetrics in order to see the list of supported command-li
     	Whether to disable automatic response cache reset if a sample with timestamp outside -search.cacheTimestampOffset is inserted into VictoriaMetrics
   -search.disableCache
     	Whether to disable response caching. This may be useful during data backfilling
+  -search.graphiteMaxPointsPerSeries int
+    	The maximum number of points per series Graphite render API can return (default 1000000)
+  -search.graphiteStorageStep duration
+    	The interval between datapoints stored in the database. It is used at Graphite Render API handler for normalizing the interval between datapoints in case it isn't normalized. It can be overriden by sending 'storage_step' query arg to /render API or by sending the desired interval via 'Storage-Step' http header during querying /render API (default 10s)
   -search.latencyOffset duration
     	The time when data points become visible in query results after the collection. Too small value can result in incomplete last points for query results (default 30s)
   -search.logSlowQueryDuration duration
diff --git a/docs/Single-server-VictoriaMetrics.md b/docs/Single-server-VictoriaMetrics.md
index e0ecbb375..148728d92 100644
--- a/docs/Single-server-VictoriaMetrics.md
+++ b/docs/Single-server-VictoriaMetrics.md
@@ -420,9 +420,15 @@ The `/api/v1/export` endpoint should return the following response:
 Data sent to VictoriaMetrics via `Graphite plaintext protocol` may be read via the following APIs:
 
 * [Graphite API](#graphite-api-usage)
-* [Prometheus querying API](#prometheus-querying-api-usage). VictoriaMetrics supports `__graphite__` pseudo-label for selecting time series with Graphite-compatible filters in [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html). For example, `{__graphite__="foo.*.bar"}` is equivalent to `{__name__=~"foo[.][^.]*[.]bar"}`, but it works faster and it is easier to use when migrating from Graphite to VictoriaMetrics. See [docs for Graphite paths and wildcards](https://graphite.readthedocs.io/en/latest/render_api.html#paths-and-wildcards). VictoriaMetrics also supports [label_graphite_group](https://docs.victoriametrics.com/MetricsQL.html#label_graphite_group) function for extracting the given groups from Graphite metric name.
+* [Prometheus querying API](#prometheus-querying-api-usage). See also [selecting Graphite metrics](#selecting-graphite-metrics).
 * [go-graphite/carbonapi](https://github.com/go-graphite/carbonapi/blob/main/cmd/carbonapi/carbonapi.example.victoriametrics.yaml)
 
+## Selecting Graphite metrics
+
+VictoriaMetrics supports `__graphite__` pseudo-label for selecting time series with Graphite-compatible filters in [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html). For example, `{__graphite__="foo.*.bar"}` is equivalent to `{__name__=~"foo[.][^.]*[.]bar"}`, but it works faster and it is easier to use when migrating from Graphite to VictoriaMetrics. See [docs for Graphite paths and wildcards](https://graphite.readthedocs.io/en/latest/render_api.html#paths-and-wildcards). VictoriaMetrics also supports [label_graphite_group](https://docs.victoriametrics.com/MetricsQL.html#label_graphite_group) function for extracting the given groups from Graphite metric name.
+
+The `__graphite__` pseudo-label supports e.g. alternate regexp filters such as `(value1|...|valueN)`. They are transparently converted to `{value1,...,valueN}` syntax [used in Graphite](https://graphite.readthedocs.io/en/latest/render_api.html#paths-and-wildcards). This allows using [multi-value template variables in Grafana](https://grafana.com/docs/grafana/latest/variables/formatting-multi-value-variables/) inside `__graphite__` pseudo-label. For example, Grafana expands `{__graphite__=~"foo.($bar).baz"}` into `{__graphite__=~"foo.(x|y).baz"}` if `$bar` template variable contains `x` and `y` values. In this case the query is automatically converted into `{__graphite__=~"foo.{x,y}.baz"}` before execution.
+
 ## How to send data from OpenTSDB-compatible agents
 
 VictoriaMetrics supports [telnet put protocol](http://opentsdb.net/docs/build/html/api_telnet/put.html)
@@ -563,8 +569,7 @@ VictoriaMetrics accepts optional query args: `extra_label=<label_name>=<label_va
 
 [Contact us](mailto:sales@victoriametrics.com) if you need assistance with such a proxy.
 
-VictoriaMetrics supports `__graphite__` pseudo-label for filtering time series with Graphite-compatible filters in [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html).
-For example, `{__graphite__="foo.*.bar"}` is equivalent to `{__name__=~"foo[.][^.]*[.]bar"}`, but it works faster and it is easier to use when migrating from Graphite to VictoriaMetrics. See [docs for Graphite paths and wildcards](https://graphite.readthedocs.io/en/latest/render_api.html#paths-and-wildcards). See also [label_graphite_group](https://docs.victoriametrics.com/MetricsQL.html#label_graphite_group) function.
+VictoriaMetrics supports `__graphite__` pseudo-label for filtering time series with Graphite-compatible filters in [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html). See [these docs](#selecting-graphite-metrics).
 
 
 ### Graphite Render API usage
@@ -836,7 +841,7 @@ unix timestamp in seconds or [RFC3339](https://www.ietf.org/rfc/rfc3339.txt) val
 
 The exported CSV data can be imported to VictoriaMetrics via [/api/v1/import/csv](#how-to-import-csv-data).
 
-The [deduplication](#deduplication) isn't applied for the data exported in CSV. It is expected that the de-duplication is performed during data import.
+The [deduplication](#deduplication) is applied for the data exported in CSV by default. It is possible to export raw data without de-duplication by passing `reduce_mem_usage=1` query arg to `/api/v1/export/csv`.
 
 
 ### How to export data in native format
@@ -1082,7 +1087,7 @@ It is recommended leaving the following amounts of spare resources:
 
 * 50% of free RAM for reducing the probability of OOM (out of memory) crashes and slowdowns during temporary spikes in workload.
 * 50% of spare CPU for reducing the probability of slowdowns during temporary spikes in workload.
-* At least 30% of free storage space at the directory pointed by `-storageDataPath` command-line flag.
+* At least 30% of free storage space at the directory pointed by `-storageDataPath` command-line flag. See also `-storage.minFreeDiskSpaceBytes` command-line flag description [here](#list-of-command-line-flags).
 
 
 ## High availability
@@ -1170,20 +1175,13 @@ See [these docs](https://docs.victoriametrics.com/guides/guide-vmcluster-multipl
 
 ## Downsampling
 
-There is no downsampling support at the moment, but:
+[VictoriaMetrics Enterprise](https://victoriametrics.com/enterprise.html) supports multi-level downsampling with `-downsampling.period` command-line flag. For example:
 
-* VictoriaMetrics is optimized for querying big amounts of raw data. See benchmark results for heavy queries
-  in [this article](https://medium.com/@valyala/measuring-vertical-scalability-for-time-series-databases-in-google-cloud-92550d78d8ae).
-* VictoriaMetrics has good compression for on-disk data. See [this article](https://medium.com/@valyala/victoriametrics-achieving-better-compression-for-time-series-data-than-gorilla-317bc1f95932)
-  for details.
-* The downsampling doesn't improve query performance on a long time range if the time range contains big number of time series due to [high churn rate](https://docs.victoriametrics.com/FAQ.html#what-is-high-churn-rate). The query performance depends on the number of unique time series on the selected time range, while downsampling doesn't reduce the number of unique time series in the database - it can reduce only the number of samples per each time series.
+* `-downsampling.period=30d:5m` instructs VictoriaMetrics to [deduplicate](#deduplication) samples older than 30 days with 5 minutes interval.
 
-These properties reduce the need of downsampling. We plan to implement downsampling in the future.
-See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/36) for details.
+* `-downsampling.period=30d:5m,180d:1h` instructs VictoriaMetrics to deduplicate samples older than 30 days with 5 minutes interval and to deduplicate samples older than 180 days with 1 hour interval.
 
-It is possible to (ab)use [-dedup.minScrapeInterval](#deduplication) for basic downsampling.
-For instance, if interval between the ingested data points is 15s, then `-dedup.minScrapeInterval=5m` will leave
-only a single data point out of 20 initial data points per each 5m interval.
+Downsampling is applied independently per each time series. It can reduce disk space usage and improve query performance if it is applied to time series with big number of samples per each series. The downsampling doesn't improve query performance if the database contains big number of time series with small number of samples per each series (aka [high churn rate](https://docs.victoriametrics.com/FAQ.html#what-is-high-churn-rate)), since downsamlping doesn't reduce the number of time series. So the majority of time is spent on searching for the matching time series.
 
 
 ## Multi-tenancy
@@ -1381,10 +1379,7 @@ See also more advanced [cardinality limiter in vmagent](https://docs.victoriamet
   This prevents from ingesting metrics with too many labels. It is recommended [monitoring](#monitoring) `vm_metrics_with_dropped_labels_total`
   metric in order to determine whether `-maxLabelsPerTimeseries` must be adjusted for your workload.
 
-* If you store Graphite metrics like `foo.bar.baz` in VictoriaMetrics, then use `{__graphite__="foo.*.baz"}` syntax for selecting such metrics.
-  This expression is equivalent to `{__name__=~"foo[.][^.]*[.]baz"}`, but it works faster and it is easier to use when migrating from Graphite.
-  See [docs for Graphite paths and wildcards](https://graphite.readthedocs.io/en/latest/render_api.html#paths-and-wildcards).
-  See also [label_graphite_group](https://docs.victoriametrics.com/MetricsQL.html#label_graphite_group) function, which allows extracting the given groups from Graphite metric names.
+* If you store Graphite metrics like `foo.bar.baz` in VictoriaMetrics, then `{__graphite__="foo.*.baz"}` filter can be used for selecting such metrics. See [these docs](#selecting-graphite-metrics) for details.
 
 * VictoriaMetrics ignores `NaN` values during data ingestion.
 
@@ -1450,6 +1445,18 @@ We also provide [vmbackupmanager](https://docs.victoriametrics.com/vmbackupmanag
 Enterprise binaries can be downloaded and evaluated for free from [the releases page](https://github.com/VictoriaMetrics/VictoriaMetrics/releases).
 
 
+## Benchmarks
+
+Note, that vendors (including VictoriaMetrics) are often biased when doing such tests. E.g. they try highlighting 
+the best parts of their product, while highlighting the worst parts of competing products. 
+So we encourage users and all independent third parties to conduct their becnhmarks for various products 
+they are evaluating in production and publish the results.
+
+As a reference, please see [benchmarks](https://docs.victoriametrics.com/Articles.html#benchmarks) conducted by
+VictoriaMetrics team. Please also see the [helm chart](https://github.com/VictoriaMetrics/benchmark) 
+for running ingestion benchmarks based on node_exporter metrics.
+
+
 ## Profiling
 
 VictoriaMetrics provides handlers for collecting the following [Go profiles](https://blog.golang.org/profiling-go-programs):
@@ -1577,11 +1584,14 @@ Pass `-help` to VictoriaMetrics in order to see the list of supported command-li
     	The maximum size in bytes of a single DataDog POST request to /api/v1/series
     	Supports the following optional suffixes for size values: KB, MB, GB, KiB, MiB, GiB (default 67108864)
   -dedup.minScrapeInterval duration
-    	Leave only the first sample in every time series per each discrete interval equal to -dedup.minScrapeInterval > 0. See https://docs.victoriametrics.com/#deduplication for details
+    	Leave only the first sample in every time series per each discrete interval equal to -dedup.minScrapeInterval > 0. See https://docs.victoriametrics.com/#deduplication and https://docs.victoriametrics.com/#downsampling
   -deleteAuthKey string
     	authKey for metrics' deletion via /api/v1/admin/tsdb/delete_series and /tags/delSeries
   -denyQueriesOutsideRetention
     	Whether to deny queries outside of the configured -retentionPeriod. When set, then /api/v1/query_range would return '503 Service Unavailable' error for queries with 'from' value outside -retentionPeriod. This may be useful when multiple data sources with distinct retentions are hidden behind query-tee
+  -downsampling.period array
+    	Comma-separated downsampling periods in the format 'offset:period'. For example, '30d:10m' instructs to leave a single sample per 10 minutes for samples older than 30 days. See https://docs.victoriametrics.com/#downsampling for details
+    	Supports an array of values separated by comma or specified via multiple flags.
   -dryRun
     	Whether to check only -promscrape.config and then exit. Unknown config entries are allowed in -promscrape.config by default. This can be changed with -promscrape.config.strictParse
   -enableTCP6
@@ -1590,6 +1600,8 @@ Pass `-help` to VictoriaMetrics in order to see the list of supported command-li
     	Whether to enable reading flags from environment variables additionally to command line. Command line flag values have priority over values from environment vars. Flags are read only from command line if this flag isn't set. See https://docs.victoriametrics.com/#environment-variables for more details
   -envflag.prefix string
     	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
   -finalMergeDelay duration
     	The delay before starting final merge for per-month partition after no new data is ingested into it. Final merge may require additional disk IO and CPU resources. Final merge may increase query speed and reduce disk space usage in some cases. Zero value disables final merge
   -forceFlushAuthKey string
@@ -1774,6 +1786,10 @@ Pass `-help` to VictoriaMetrics in order to see the list of supported command-li
     	Whether to disable automatic response cache reset if a sample with timestamp outside -search.cacheTimestampOffset is inserted into VictoriaMetrics
   -search.disableCache
     	Whether to disable response caching. This may be useful during data backfilling
+  -search.graphiteMaxPointsPerSeries int
+    	The maximum number of points per series Graphite render API can return (default 1000000)
+  -search.graphiteStorageStep duration
+    	The interval between datapoints stored in the database. It is used at Graphite Render API handler for normalizing the interval between datapoints in case it isn't normalized. It can be overriden by sending 'storage_step' query arg to /render API or by sending the desired interval via 'Storage-Step' http header during querying /render API (default 10s)
   -search.latencyOffset duration
     	The time when data points become visible in query results after the collection. Too small value can result in incomplete last points for query results (default 30s)
   -search.logSlowQueryDuration duration
diff --git a/go.mod b/go.mod
index 4332258fe..148205faf 100644
--- a/go.mod
+++ b/go.mod
@@ -9,7 +9,7 @@ require (
 	// like https://github.com/valyala/fasthttp/commit/996610f021ff45fdc98c2ce7884d5fa4e7f9199b
 	github.com/VictoriaMetrics/fasthttp v1.1.0
 	github.com/VictoriaMetrics/metrics v1.18.1
-	github.com/VictoriaMetrics/metricsql v0.32.0
+	github.com/VictoriaMetrics/metricsql v0.33.0
 	github.com/VividCortex/ewma v1.2.0 // indirect
 	github.com/aws/aws-sdk-go v1.42.22
 	github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect
diff --git a/go.sum b/go.sum
index c6e1c36ca..fdb41d91c 100644
--- a/go.sum
+++ b/go.sum
@@ -110,8 +110,8 @@ github.com/VictoriaMetrics/fasthttp v1.1.0/go.mod h1:/7DMcogqd+aaD3G3Hg5kFgoFwlR
 github.com/VictoriaMetrics/metrics v1.12.2/go.mod h1:Z1tSfPfngDn12bTfZSCqArT3OPY3u88J12hSoOhuiRE=
 github.com/VictoriaMetrics/metrics v1.18.1 h1:OZ0+kTTto8oPfHnVAnTOoyl0XlRhRkoQrD2n2cOuRw0=
 github.com/VictoriaMetrics/metrics v1.18.1/go.mod h1:ArjwVz7WpgpegX/JpB0zpNF2h2232kErkEnzH1sxMmA=
-github.com/VictoriaMetrics/metricsql v0.32.0 h1:yTZFB1FvbOsD5ahl6mxKYprHpZ248nVk3s8Kl7UBg5c=
-github.com/VictoriaMetrics/metricsql v0.32.0/go.mod h1:ylO7YITho/Iw6P71oEaGyHbO94bGoGtzWfLGqFhMIg8=
+github.com/VictoriaMetrics/metricsql v0.33.0 h1:UBj7+Tf4dhD47tIxMYfAiy/4GXJN6xPYTweCZ+sRqw0=
+github.com/VictoriaMetrics/metricsql v0.33.0/go.mod h1:ylO7YITho/Iw6P71oEaGyHbO94bGoGtzWfLGqFhMIg8=
 github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
 github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
 github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4=
diff --git a/lib/promscrape/client.go b/lib/promscrape/client.go
index 2447a92e5..0826d20f1 100644
--- a/lib/promscrape/client.go
+++ b/lib/promscrape/client.go
@@ -236,19 +236,27 @@ func (c *client) ReadData(dst []byte) ([]byte, error) {
 	}
 	err := doRequestWithPossibleRetry(c.hc, req, resp, deadline)
 	statusCode := resp.StatusCode()
-	if err == nil && (statusCode == fasthttp.StatusMovedPermanently || statusCode == fasthttp.StatusFound) {
+	redirectsCount := 0
+	for err == nil && (statusCode == fasthttp.StatusMovedPermanently || statusCode == fasthttp.StatusFound) {
+		if redirectsCount > 5 {
+			err = fmt.Errorf("too many redirects")
+			break
+		}
 		if c.denyRedirects {
 			err = fmt.Errorf("cannot follow redirects if `follow_redirects: false` is set")
-		} else {
-			// Allow a single redirect.
-			// It is expected that the redirect is made on the same host.
-			// Otherwise it won't work.
-			if location := resp.Header.Peek("Location"); len(location) > 0 {
-				req.URI().UpdateBytes(location)
-				err = c.hc.DoDeadline(req, resp, deadline)
-				statusCode = resp.StatusCode()
-			}
+			break
+		}
+		// It is expected that the redirect is made on the same host.
+		// Otherwise it won't work.
+		location := resp.Header.Peek("Location")
+		if len(location) == 0 {
+			err = fmt.Errorf("missing Location header")
+			break
 		}
+		req.URI().UpdateBytes(location)
+		err = doRequestWithPossibleRetry(c.hc, req, resp, deadline)
+		statusCode = resp.StatusCode()
+		redirectsCount++
 	}
 	if swapResponseBodies {
 		dst = resp.SwapBody(dst)
diff --git a/lib/storage/block.go b/lib/storage/block.go
index c446c370e..edc7507e6 100644
--- a/lib/storage/block.go
+++ b/lib/storage/block.go
@@ -148,13 +148,26 @@ func (b *Block) tooBig() bool {
 }
 
 func (b *Block) deduplicateSamplesDuringMerge() {
-	if len(b.values) == 0 {
-		// Nothing to dedup or the data is already marshaled.
+	if !isDedupEnabled() {
+		// Deduplication is disabled
 		return
 	}
+	// Unmarshal block if it isn't unmarshaled yet in order to apply the de-duplication to unmarshaled samples.
+	if err := b.UnmarshalData(); err != nil {
+		logger.Panicf("FATAL: cannot unmarshal block: %s", err)
+	}
 	srcTimestamps := b.timestamps[b.nextIdx:]
+	if len(srcTimestamps) < 2 {
+		// Nothing to dedup.
+		return
+	}
+	dedupInterval := GetDedupInterval()
+	if dedupInterval <= 0 {
+		// Deduplication is disabled.
+		return
+	}
 	srcValues := b.values[b.nextIdx:]
-	timestamps, values := deduplicateSamplesDuringMerge(srcTimestamps, srcValues)
+	timestamps, values := deduplicateSamplesDuringMerge(srcTimestamps, srcValues, dedupInterval)
 	dedups := len(srcTimestamps) - len(timestamps)
 	atomic.AddUint64(&dedupsDuringMerge, uint64(dedups))
 	b.timestamps = b.timestamps[:b.nextIdx+len(timestamps)]
diff --git a/lib/storage/block_stream_writer.go b/lib/storage/block_stream_writer.go
index 5421a6656..c46f12fe2 100644
--- a/lib/storage/block_stream_writer.go
+++ b/lib/storage/block_stream_writer.go
@@ -184,11 +184,9 @@ func (bsw *blockStreamWriter) MustClose() {
 }
 
 // WriteExternalBlock writes b to bsw and updates ph and rowsMerged.
-func (bsw *blockStreamWriter) WriteExternalBlock(b *Block, ph *partHeader, rowsMerged *uint64, needDedup bool) {
+func (bsw *blockStreamWriter) WriteExternalBlock(b *Block, ph *partHeader, rowsMerged *uint64) {
 	atomic.AddUint64(rowsMerged, uint64(b.rowsCount()))
-	if needDedup {
-		b.deduplicateSamplesDuringMerge()
-	}
+	b.deduplicateSamplesDuringMerge()
 	headerData, timestampsData, valuesData := b.MarshalData(bsw.timestampsBlockOffset, bsw.valuesBlockOffset)
 	usePrevTimestamps := len(bsw.prevTimestampsData) > 0 && bytes.Equal(timestampsData, bsw.prevTimestampsData)
 	if usePrevTimestamps {
diff --git a/lib/storage/dedup.go b/lib/storage/dedup.go
index 6179ed030..c92cc6221 100644
--- a/lib/storage/dedup.go
+++ b/lib/storage/dedup.go
@@ -4,31 +4,37 @@ import (
 	"time"
 )
 
-// SetMinScrapeIntervalForDeduplication sets the minimum interval for data points during de-duplication.
+// SetDedupInterval sets the deduplication interval, which is applied to raw samples during data ingestion and querying.
 //
-// De-duplication is disabled if interval is 0.
+// De-duplication is disabled if dedupInterval is 0.
 //
 // This function must be called before initializing the storage.
-func SetMinScrapeIntervalForDeduplication(interval time.Duration) {
-	minScrapeInterval = interval.Milliseconds()
+func SetDedupInterval(dedupInterval time.Duration) {
+	globalDedupInterval = dedupInterval.Milliseconds()
 }
 
-var minScrapeInterval = int64(0)
+// GetDedupInterval returns the dedup interval in milliseconds, which has been set via SetDedupInterval.
+func GetDedupInterval() int64 {
+	return globalDedupInterval
+}
 
-// DeduplicateSamples removes samples from src* if they are closer to each other than minScrapeInterval.
-func DeduplicateSamples(srcTimestamps []int64, srcValues []float64) ([]int64, []float64) {
-	if minScrapeInterval <= 0 {
-		return srcTimestamps, srcValues
-	}
-	if !needsDedup(srcTimestamps, minScrapeInterval) {
+var globalDedupInterval int64
+
+func isDedupEnabled() bool {
+	return globalDedupInterval > 0
+}
+
+// DeduplicateSamples removes samples from src* if they are closer to each other than dedupInterval in millseconds.
+func DeduplicateSamples(srcTimestamps []int64, srcValues []float64, dedupInterval int64) ([]int64, []float64) {
+	if !needsDedup(srcTimestamps, dedupInterval) {
 		// Fast path - nothing to deduplicate
 		return srcTimestamps, srcValues
 	}
-	return deduplicateInternal(minScrapeInterval, srcTimestamps, srcValues)
+	return deduplicateInternal(srcTimestamps, srcValues, dedupInterval)
 }
 
-func deduplicateInternal(interval int64, srcTimestamps []int64, srcValues []float64) ([]int64, []float64) {
-	tsNext := (srcTimestamps[0] - srcTimestamps[0]%interval) + interval
+func deduplicateInternal(srcTimestamps []int64, srcValues []float64, dedupInterval int64) ([]int64, []float64) {
+	tsNext := (srcTimestamps[0] - srcTimestamps[0]%dedupInterval) + dedupInterval
 	dstTimestamps := srcTimestamps[:1]
 	dstValues := srcValues[:1]
 	for i := 1; i < len(srcTimestamps); i++ {
@@ -40,28 +46,25 @@ func deduplicateInternal(interval int64, srcTimestamps []int64, srcValues []floa
 		dstValues = append(dstValues, srcValues[i])
 
 		// Update tsNext
-		tsNext += interval
+		tsNext += dedupInterval
 		if ts >= tsNext {
 			// Slow path for updating ts.
-			tsNext = (ts - ts%interval) + interval
+			tsNext = (ts - ts%dedupInterval) + dedupInterval
 		}
 	}
 	return dstTimestamps, dstValues
 }
 
-func deduplicateSamplesDuringMerge(srcTimestamps, srcValues []int64) ([]int64, []int64) {
-	if minScrapeInterval <= 0 {
-		return srcTimestamps, srcValues
-	}
-	if !needsDedup(srcTimestamps, minScrapeInterval) {
+func deduplicateSamplesDuringMerge(srcTimestamps, srcValues []int64, dedupInterval int64) ([]int64, []int64) {
+	if !needsDedup(srcTimestamps, dedupInterval) {
 		// Fast path - nothing to deduplicate
 		return srcTimestamps, srcValues
 	}
-	return deduplicateDuringMergeInternal(minScrapeInterval, srcTimestamps, srcValues)
+	return deduplicateDuringMergeInternal(srcTimestamps, srcValues, dedupInterval)
 }
 
-func deduplicateDuringMergeInternal(interval int64, srcTimestamps, srcValues []int64) ([]int64, []int64) {
-	tsNext := (srcTimestamps[0] - srcTimestamps[0]%interval) + interval
+func deduplicateDuringMergeInternal(srcTimestamps, srcValues []int64, dedupInterval int64) ([]int64, []int64) {
+	tsNext := (srcTimestamps[0] - srcTimestamps[0]%dedupInterval) + dedupInterval
 	dstTimestamps := srcTimestamps[:1]
 	dstValues := srcValues[:1]
 	for i := 1; i < len(srcTimestamps); i++ {
@@ -73,27 +76,27 @@ func deduplicateDuringMergeInternal(interval int64, srcTimestamps, srcValues []i
 		dstValues = append(dstValues, srcValues[i])
 
 		// Update tsNext
-		tsNext += interval
+		tsNext += dedupInterval
 		if ts >= tsNext {
 			// Slow path for updating ts.
-			tsNext = (ts - ts%interval) + interval
+			tsNext = (ts - ts%dedupInterval) + dedupInterval
 		}
 	}
 	return dstTimestamps, dstValues
 }
 
-func needsDedup(timestamps []int64, interval int64) bool {
-	if len(timestamps) == 0 || interval <= 0 {
+func needsDedup(timestamps []int64, dedupInterval int64) bool {
+	if len(timestamps) == 0 || dedupInterval <= 0 {
 		return false
 	}
-	tsNext := (timestamps[0] - timestamps[0]%interval) + interval
+	tsNext := (timestamps[0] - timestamps[0]%dedupInterval) + dedupInterval
 	for _, ts := range timestamps[1:] {
 		if ts < tsNext {
 			return true
 		}
-		tsNext += interval
+		tsNext += dedupInterval
 		if ts >= tsNext {
-			tsNext = (ts - ts%interval) + interval
+			tsNext = (ts - ts%dedupInterval) + dedupInterval
 		}
 	}
 	return false
diff --git a/lib/storage/merge.go b/lib/storage/merge.go
index e5e7f221d..4ef383797 100644
--- a/lib/storage/merge.go
+++ b/lib/storage/merge.go
@@ -76,14 +76,14 @@ func mergeBlockStreamsInternal(ph *partHeader, bsw *blockStreamWriter, bsm *bloc
 			if bsm.Block.bh.TSID.Less(&pendingBlock.bh.TSID) {
 				logger.Panicf("BUG: the next TSID=%+v is smaller than the current TSID=%+v", &bsm.Block.bh.TSID, &pendingBlock.bh.TSID)
 			}
-			bsw.WriteExternalBlock(pendingBlock, ph, rowsMerged, true)
+			bsw.WriteExternalBlock(pendingBlock, ph, rowsMerged)
 			pendingBlock.CopyFrom(bsm.Block)
 			continue
 		}
 		if pendingBlock.tooBig() && pendingBlock.bh.MaxTimestamp <= bsm.Block.bh.MinTimestamp {
 			// Fast path - pendingBlock is too big and it doesn't overlap with bsm.Block.
 			// Write the pendingBlock and then deal with bsm.Block.
-			bsw.WriteExternalBlock(pendingBlock, ph, rowsMerged, true)
+			bsw.WriteExternalBlock(pendingBlock, ph, rowsMerged)
 			pendingBlock.CopyFrom(bsm.Block)
 			continue
 		}
@@ -119,13 +119,13 @@ func mergeBlockStreamsInternal(ph *partHeader, bsw *blockStreamWriter, bsm *bloc
 		tmpBlock.timestamps = tmpBlock.timestamps[:maxRowsPerBlock]
 		tmpBlock.values = tmpBlock.values[:maxRowsPerBlock]
 		tmpBlock.fixupTimestamps()
-		bsw.WriteExternalBlock(tmpBlock, ph, rowsMerged, true)
+		bsw.WriteExternalBlock(tmpBlock, ph, rowsMerged)
 	}
 	if err := bsm.Error(); err != nil {
 		return fmt.Errorf("cannot read block to be merged: %w", err)
 	}
 	if !pendingBlockIsEmpty {
-		bsw.WriteExternalBlock(pendingBlock, ph, rowsMerged, true)
+		bsw.WriteExternalBlock(pendingBlock, ph, rowsMerged)
 	}
 	return nil
 }
diff --git a/lib/storage/part_header.go b/lib/storage/part_header.go
index 54bbb760b..ec874a23d 100644
--- a/lib/storage/part_header.go
+++ b/lib/storage/part_header.go
@@ -1,11 +1,17 @@
 package storage
 
 import (
+	"errors"
 	"fmt"
+	"io/ioutil"
+	"os"
 	"path/filepath"
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/fs"
+	"github.com/VictoriaMetrics/metricsql"
 )
 
 // partHeader represents part header.
@@ -21,6 +27,9 @@ type partHeader struct {
 
 	// MaxTimestamp is the maximum timestamp in the part.
 	MaxTimestamp int64
+
+	// MinDedupInterval is minimal dedup interval in milliseconds across all the blocks in the part.
+	MinDedupInterval int64
 }
 
 // String returns string representation of ph.
@@ -104,6 +113,10 @@ func (ph *partHeader) ParseFromPath(path string) error {
 		return fmt.Errorf("blocksCount cannot be bigger than rowsCount; got blocksCount=%d, rowsCount=%d", ph.BlocksCount, ph.RowsCount)
 	}
 
+	if err := ph.readMinDedupInterval(path); err != nil {
+		return fmt.Errorf("cannot read min dedup interval: %w", err)
+	}
+
 	return nil
 }
 
@@ -113,4 +126,34 @@ func (ph *partHeader) Reset() {
 	ph.BlocksCount = 0
 	ph.MinTimestamp = (1 << 63) - 1
 	ph.MaxTimestamp = -1 << 63
+	ph.MinDedupInterval = 0
+}
+
+func (ph *partHeader) readMinDedupInterval(partPath string) error {
+	filePath := partPath + "/min_dedup_interval"
+	data, err := ioutil.ReadFile(filePath)
+	if err != nil {
+		if errors.Is(err, os.ErrNotExist) {
+			// The minimum dedup interval may not exist for old parts.
+			ph.MinDedupInterval = 0
+			return nil
+		}
+		return fmt.Errorf("cannot read %q: %w", filePath, err)
+	}
+	dedupInterval, err := metricsql.DurationValue(string(data), 0)
+	if err != nil {
+		return fmt.Errorf("cannot parse minimum dedup interval %q at %q: %w", data, filePath, err)
+	}
+	ph.MinDedupInterval = dedupInterval
+	return nil
+}
+
+func (ph *partHeader) writeMinDedupInterval(partPath string) error {
+	filePath := partPath + "/min_dedup_interval"
+	dedupInterval := time.Duration(ph.MinDedupInterval) * time.Millisecond
+	data := dedupInterval.String()
+	if err := fs.WriteFileAtomically(filePath, []byte(data)); err != nil {
+		return fmt.Errorf("cannot create %q: %w", filePath, err)
+	}
+	return nil
 }
diff --git a/lib/storage/partition.go b/lib/storage/partition.go
index ac6f7af98..93fc92ac8 100644
--- a/lib/storage/partition.go
+++ b/lib/storage/partition.go
@@ -835,7 +835,17 @@ func (pt *partition) ForceMergeAllParts() error {
 		// Nothing to merge.
 		return nil
 	}
-	// If len(pws) == 1, then the merge must run anyway, so deleted time series could be removed from the part.
+
+	// Check whether there is enough disk space for merging pws.
+	newPartSize := getPartsSize(pws)
+	maxOutBytes := fs.MustGetFreeSpace(pt.bigPartsPath)
+	if newPartSize > maxOutBytes {
+		freeSpaceNeededBytes := newPartSize - maxOutBytes
+		logger.Warnf("cannot initiate force merge for the partition %s; additional space needed: %d bytes", pt.name, freeSpaceNeededBytes)
+		return nil
+	}
+
+	// If len(pws) == 1, then the merge must run anyway. This allows removing the deleted series and performing de-duplication if needed.
 	if err := pt.mergePartsOptimal(pws, pt.stopCh); err != nil {
 		return fmt.Errorf("cannot force merge %d parts from partition %q: %w", len(pws), pt.name, err)
 	}
@@ -1056,6 +1066,44 @@ func atomicSetBool(p *uint64, b bool) {
 	atomic.StoreUint64(p, v)
 }
 
+func (pt *partition) runFinalDedup() error {
+	requiredDedupInterval, actualDedupInterval := pt.getRequiredDedupInterval()
+	if requiredDedupInterval <= actualDedupInterval {
+		// Deduplication isn't needed.
+		return nil
+	}
+	t := time.Now()
+	logger.Infof("starting final dedup for partition %s using requiredDedupInterval=%d ms, since the partition has smaller actualDedupInterval=%d ms",
+		pt.bigPartsPath, requiredDedupInterval, actualDedupInterval)
+	if err := pt.ForceMergeAllParts(); err != nil {
+		return fmt.Errorf("cannot perform final dedup for partition %s: %w", pt.bigPartsPath, err)
+	}
+	logger.Infof("final dedup for partition %s has been finished in %.3f seconds", pt.bigPartsPath, time.Since(t).Seconds())
+	return nil
+}
+
+func (pt *partition) getRequiredDedupInterval() (int64, int64) {
+	pws := pt.GetParts(nil)
+	defer pt.PutParts(pws)
+	dedupInterval := GetDedupInterval()
+	minDedupInterval := getMinDedupInterval(pws)
+	return dedupInterval, minDedupInterval
+}
+
+func getMinDedupInterval(pws []*partWrapper) int64 {
+	if len(pws) == 0 {
+		return 0
+	}
+	dMin := pws[0].p.ph.MinDedupInterval
+	for _, pw := range pws[1:] {
+		d := pw.p.ph.MinDedupInterval
+		if d < dMin {
+			dMin = d
+		}
+	}
+	return dMin
+}
+
 // mergeParts merges pws.
 //
 // Merging is immediately stopped if stopCh is closed.
@@ -1146,6 +1194,11 @@ func (pt *partition) mergeParts(pws []*partWrapper, stopCh <-chan struct{}) erro
 	}
 	bsrs = nil
 
+	ph.MinDedupInterval = GetDedupInterval()
+	if err := ph.writeMinDedupInterval(tmpPartPath); err != nil {
+		return fmt.Errorf("cannot store min dedup interval for part %q: %w", tmpPartPath, err)
+	}
+
 	// Create a transaction for atomic deleting old parts and moving
 	// new part to its destination place.
 	var bb bytesutil.ByteBuffer
diff --git a/lib/storage/raw_row.go b/lib/storage/raw_row.go
index e3dcdfc9f..b1d978d33 100644
--- a/lib/storage/raw_row.go
+++ b/lib/storage/raw_row.go
@@ -115,7 +115,7 @@ func (rrm *rawRowsMarshaler) marshalToInmemoryPart(mp *inmemoryPart, rows []rawR
 
 		rrm.auxValues, scale = decimal.AppendFloatToDecimal(rrm.auxValues[:0], rrm.auxFloatValues)
 		tmpBlock.Init(tsid, rrm.auxTimestamps, rrm.auxValues, scale, precisionBits)
-		rrm.bsw.WriteExternalBlock(tmpBlock, ph, &rowsMerged, false)
+		rrm.bsw.WriteExternalBlock(tmpBlock, ph, &rowsMerged)
 
 		tsid = &r.TSID
 		precisionBits = r.PrecisionBits
@@ -125,7 +125,7 @@ func (rrm *rawRowsMarshaler) marshalToInmemoryPart(mp *inmemoryPart, rows []rawR
 
 	rrm.auxValues, scale = decimal.AppendFloatToDecimal(rrm.auxValues[:0], rrm.auxFloatValues)
 	tmpBlock.Init(tsid, rrm.auxTimestamps, rrm.auxValues, scale, precisionBits)
-	rrm.bsw.WriteExternalBlock(tmpBlock, ph, &rowsMerged, false)
+	rrm.bsw.WriteExternalBlock(tmpBlock, ph, &rowsMerged)
 	if rowsMerged != uint64(len(rows)) {
 		logger.Panicf("BUG: unexpected rowsMerged; got %d; want %d", rowsMerged, len(rows))
 	}
diff --git a/lib/storage/storage.go b/lib/storage/storage.go
index 208fb2679..e10df1a80 100644
--- a/lib/storage/storage.go
+++ b/lib/storage/storage.go
@@ -1228,9 +1228,52 @@ func (s *Storage) SearchTagValueSuffixes(tr TimeRange, tagKey, tagValuePrefix []
 
 // SearchGraphitePaths returns all the matching paths for the given graphite query on the given tr.
 func (s *Storage) SearchGraphitePaths(tr TimeRange, query []byte, maxPaths int, deadline uint64) ([]string, error) {
+	query = replaceAlternateRegexpsWithGraphiteWildcards(query)
 	return s.searchGraphitePaths(tr, nil, query, maxPaths, deadline)
 }
 
+// replaceAlternateRegexpsWithGraphiteWildcards replaces (foo|..|bar) with {foo,...,bar} in b and returns the new value.
+func replaceAlternateRegexpsWithGraphiteWildcards(b []byte) []byte {
+	var dst []byte
+	for {
+		n := bytes.IndexByte(b, '(')
+		if n < 0 {
+			if len(dst) == 0 {
+				// Fast path - b doesn't contain the openining brace.
+				return b
+			}
+			dst = append(dst, b...)
+			return dst
+		}
+		dst = append(dst, b[:n]...)
+		b = b[n+1:]
+		n = bytes.IndexByte(b, ')')
+		if n < 0 {
+			dst = append(dst, '(')
+			dst = append(dst, b...)
+			return dst
+		}
+		x := b[:n]
+		b = b[n+1:]
+		if string(x) == ".*" {
+			dst = append(dst, '*')
+			continue
+		}
+		dst = append(dst, '{')
+		for len(x) > 0 {
+			n = bytes.IndexByte(x, '|')
+			if n < 0 {
+				dst = append(dst, x...)
+				break
+			}
+			dst = append(dst, x[:n]...)
+			x = x[n+1:]
+			dst = append(dst, ',')
+		}
+		dst = append(dst, '}')
+	}
+}
+
 func (s *Storage) searchGraphitePaths(tr TimeRange, qHead, qTail []byte, maxPaths int, deadline uint64) ([]string, error) {
 	n := bytes.IndexAny(qTail, "*[{")
 	if n < 0 {
diff --git a/lib/storage/table.go b/lib/storage/table.go
index 5049a18e0..c85bbbfb0 100644
--- a/lib/storage/table.go
+++ b/lib/storage/table.go
@@ -31,7 +31,8 @@ type table struct {
 
 	stop chan struct{}
 
-	retentionWatcherWG sync.WaitGroup
+	retentionWatcherWG  sync.WaitGroup
+	finalDedupWatcherWG sync.WaitGroup
 }
 
 // partitionWrapper provides refcounting mechanism for the partition.
@@ -135,6 +136,7 @@ func openTable(path string, getDeletedMetricIDs func() *uint64set.Set, retention
 		tb.addPartitionNolock(pt)
 	}
 	tb.startRetentionWatcher()
+	tb.startFinalDedupWatcher()
 	return tb, nil
 }
 
@@ -193,6 +195,7 @@ func (tb *table) addPartitionNolock(pt *partition) {
 func (tb *table) MustClose() {
 	close(tb.stop)
 	tb.retentionWatcherWG.Wait()
+	tb.finalDedupWatcherWG.Wait()
 
 	tb.ptwsLock.Lock()
 	ptws := tb.ptws
@@ -435,6 +438,47 @@ func (tb *table) retentionWatcher() {
 	}
 }
 
+func (tb *table) startFinalDedupWatcher() {
+	tb.finalDedupWatcherWG.Add(1)
+	go func() {
+		tb.finalDedupWatcher()
+		tb.finalDedupWatcherWG.Done()
+	}()
+}
+
+func (tb *table) finalDedupWatcher() {
+	if !isDedupEnabled() {
+		// Deduplication is disabled.
+		return
+	}
+	f := func() {
+		ptws := tb.GetPartitions(nil)
+		defer tb.PutPartitions(ptws)
+		timestamp := timestampFromTime(time.Now())
+		currentPartitionName := timestampToPartitionName(timestamp)
+		for _, ptw := range ptws {
+			if ptw.pt.name == currentPartitionName {
+				// Do not run final dedup for the current month.
+				continue
+			}
+			if err := ptw.pt.runFinalDedup(); err != nil {
+				logger.Errorf("cannot run final dedup for partition %s: %s", ptw.pt.name, err)
+				continue
+			}
+		}
+	}
+	t := time.NewTicker(time.Hour)
+	defer t.Stop()
+	for {
+		select {
+		case <-tb.stop:
+			return
+		case <-t.C:
+			f()
+		}
+	}
+}
+
 // GetPartitions appends tb's partitions snapshot to dst and returns the result.
 //
 // The returned partitions must be passed to PutPartitions
diff --git a/vendor/github.com/VictoriaMetrics/metricsql/rollup.go b/vendor/github.com/VictoriaMetrics/metricsql/rollup.go
index 7bd5a2a68..4887cf2db 100644
--- a/vendor/github.com/VictoriaMetrics/metricsql/rollup.go
+++ b/vendor/github.com/VictoriaMetrics/metricsql/rollup.go
@@ -68,11 +68,12 @@ var rollupFuncs = map[string]bool{
 	// `timestamp` function must return timestamp for the last datapoint on the current window
 	// in order to properly handle offset and timestamps unaligned to the current step.
 	// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/415 for details.
-	"timestamp":        true,
-	"tlast_over_time":  true,
-	"tmax_over_time":   true,
-	"tmin_over_time":   true,
-	"zscore_over_time": true,
+	"timestamp":           true,
+	"timestamp_with_name": true,
+	"tlast_over_time":     true,
+	"tmax_over_time":      true,
+	"tmin_over_time":      true,
+	"zscore_over_time":    true,
 }
 
 // IsRollupFunc returns whether funcName is known rollup function.
diff --git a/vendor/modules.txt b/vendor/modules.txt
index ba4e6b2f3..68812d3f9 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -22,7 +22,7 @@ github.com/VictoriaMetrics/fasthttp/stackless
 # github.com/VictoriaMetrics/metrics v1.18.1
 ## explicit
 github.com/VictoriaMetrics/metrics
-# github.com/VictoriaMetrics/metricsql v0.32.0
+# github.com/VictoriaMetrics/metricsql v0.33.0
 ## explicit
 github.com/VictoriaMetrics/metricsql
 github.com/VictoriaMetrics/metricsql/binaryop


Test patch:
diff --git a/app/vmalert/datasource/vm_test.go b/app/vmalert/datasource/vm_test.go
index 068cb6277..81e12b2f6 100644
--- a/app/vmalert/datasource/vm_test.go
+++ b/app/vmalert/datasource/vm_test.go
@@ -436,7 +436,20 @@ func TestRequestParams(t *testing.T) {
 				queryStep: time.Minute,
 			},
 			func(t *testing.T, r *http.Request) {
-				exp := fmt.Sprintf("query=%s&step=%v&time=%d", query, time.Minute, timestamp.Unix())
+				exp := fmt.Sprintf("query=%s&step=%ds&time=%d", query, int(time.Minute.Seconds()), timestamp.Unix())
+				checkEqualString(t, exp, r.URL.RawQuery)
+			},
+		},
+		{
+			"step to seconds",
+			false,
+			&VMStorage{
+				evaluationInterval: 3 * time.Hour,
+			},
+			func(t *testing.T, r *http.Request) {
+				evalInterval := 3 * time.Hour
+				tt := timestamp.Truncate(evalInterval)
+				exp := fmt.Sprintf("query=%s&step=%ds&time=%d", query, int(evalInterval.Seconds()), tt.Unix())
 				checkEqualString(t, exp, r.URL.RawQuery)
 			},
 		},
diff --git a/app/vmselect/promql/exec_test.go b/app/vmselect/promql/exec_test.go
index cfd76878a..b69cfbd87 100644
--- a/app/vmselect/promql/exec_test.go
+++ b/app/vmselect/promql/exec_test.go
@@ -593,6 +593,29 @@ func TestExecSuccess(t *testing.T) {
 		resultExpected := []netstorage.Result{r}
 		f(q, resultExpected)
 	})
+	t.Run("timestamp(alias(time()>=1600))", func(t *testing.T) {
+		t.Parallel()
+		q := `timestamp(alias(time()>=1600,"foo"))`
+		r := netstorage.Result{
+			MetricName: metricNameExpected,
+			Values:     []float64{nan, nan, nan, 1600, 1800, 2000},
+			Timestamps: timestampsExpected,
+		}
+		resultExpected := []netstorage.Result{r}
+		f(q, resultExpected)
+	})
+	t.Run("timestamp_with_name(alias(time()>=1600))", func(t *testing.T) {
+		t.Parallel()
+		q := `timestamp_with_name(alias(time()>=1600,"foo"))`
+		r := netstorage.Result{
+			MetricName: metricNameExpected,
+			Values:     []float64{nan, nan, nan, 1600, 1800, 2000},
+			Timestamps: timestampsExpected,
+		}
+		r.MetricName.MetricGroup = []byte("foo")
+		resultExpected := []netstorage.Result{r}
+		f(q, resultExpected)
+	})
 	t.Run("time()/100", func(t *testing.T) {
 		t.Parallel()
 		q := `time()/100`
@@ -7382,6 +7405,7 @@ func TestExecError(t *testing.T) {
 	f(`sort_by_label()`)
 	f(`sort_by_label_desc()`)
 	f(`timestamp()`)
+	f(`timestamp_with_name()`)
 	f(`vector()`)
 	f(`histogram_quantile()`)
 	f(`histogram_quantiles()`)
diff --git a/app/vmselect/promql/rollup_test.go b/app/vmselect/promql/rollup_test.go
index e90ebd0eb..e0348dfd7 100644
--- a/app/vmselect/promql/rollup_test.go
+++ b/app/vmselect/promql/rollup_test.go
@@ -524,6 +524,7 @@ func TestRollupNewRollupFuncSuccess(t *testing.T) {
 	f("descent_over_time", 231)
 	f("zscore_over_time", -0.4254336383156416)
 	f("timestamp", 0.13)
+	f("timestamp_with_name", 0.13)
 	f("mode_over_time", 34)
 	f("rate_over_sum", 4520)
 }
diff --git a/lib/storage/block_stream_writer_timing_test.go b/lib/storage/block_stream_writer_timing_test.go
index a8b2c0d06..8e51d06a2 100644
--- a/lib/storage/block_stream_writer_timing_test.go
+++ b/lib/storage/block_stream_writer_timing_test.go
@@ -49,7 +49,7 @@ func benchmarkBlockStreamWriter(b *testing.B, ebs []Block, rowsCount int, writeR
 
 			bsw.InitFromInmemoryPart(&mp)
 			for i := range ebsCopy {
-				bsw.WriteExternalBlock(&ebsCopy[i], &ph, &rowsMerged, false)
+				bsw.WriteExternalBlock(&ebsCopy[i], &ph, &rowsMerged)
 			}
 			bsw.MustClose()
 			mp.Reset()
diff --git a/lib/storage/dedup_test.go b/lib/storage/dedup_test.go
index a3f0d88bb..b206adaa2 100644
--- a/lib/storage/dedup_test.go
+++ b/lib/storage/dedup_test.go
@@ -30,18 +30,17 @@ func TestNeedsDedup(t *testing.T) {
 
 func TestDeduplicateSamples(t *testing.T) {
 	// Disable deduplication before exit, since the rest of tests expect disabled dedup.
-	defer SetMinScrapeIntervalForDeduplication(0)
 
 	f := func(scrapeInterval time.Duration, timestamps, timestampsExpected []int64) {
 		t.Helper()
-		SetMinScrapeIntervalForDeduplication(scrapeInterval)
 		timestampsCopy := make([]int64, len(timestamps))
 		values := make([]float64, len(timestamps))
 		for i, ts := range timestamps {
 			timestampsCopy[i] = ts
 			values[i] = float64(i)
 		}
-		timestampsCopy, values = DeduplicateSamples(timestampsCopy, values)
+		dedupInterval := scrapeInterval.Milliseconds()
+		timestampsCopy, values = DeduplicateSamples(timestampsCopy, values, dedupInterval)
 		if !reflect.DeepEqual(timestampsCopy, timestampsExpected) {
 			t.Fatalf("invalid DeduplicateSamples(%v) result;\ngot\n%v\nwant\n%v", timestamps, timestampsCopy, timestampsExpected)
 		}
@@ -69,9 +68,9 @@ func TestDeduplicateSamples(t *testing.T) {
 			t.Fatalf("superfluous timestamps found starting from index %d: %v", j, timestampsCopy[j:])
 		}
 
-		// Verify that the second call to DeduplicatSamples doesn't modify samples.
+		// Verify that the second call to DeduplicateSamples doesn't modify samples.
 		valuesCopy := append([]float64{}, values...)
-		timestampsCopy, valuesCopy = DeduplicateSamples(timestampsCopy, valuesCopy)
+		timestampsCopy, valuesCopy = DeduplicateSamples(timestampsCopy, valuesCopy, dedupInterval)
 		if !reflect.DeepEqual(timestampsCopy, timestampsExpected) {
 			t.Fatalf("invalid DeduplicateSamples(%v) timestamps for the second call;\ngot\n%v\nwant\n%v", timestamps, timestampsCopy, timestampsExpected)
 		}
@@ -90,18 +89,17 @@ func TestDeduplicateSamples(t *testing.T) {
 
 func TestDeduplicateSamplesDuringMerge(t *testing.T) {
 	// Disable deduplication before exit, since the rest of tests expect disabled dedup.
-	defer SetMinScrapeIntervalForDeduplication(0)
 
 	f := func(scrapeInterval time.Duration, timestamps, timestampsExpected []int64) {
 		t.Helper()
-		SetMinScrapeIntervalForDeduplication(scrapeInterval)
 		timestampsCopy := make([]int64, len(timestamps))
 		values := make([]int64, len(timestamps))
 		for i, ts := range timestamps {
 			timestampsCopy[i] = ts
 			values[i] = int64(i)
 		}
-		timestampsCopy, values = deduplicateSamplesDuringMerge(timestampsCopy, values)
+		dedupInterval := scrapeInterval.Milliseconds()
+		timestampsCopy, values = deduplicateSamplesDuringMerge(timestampsCopy, values, dedupInterval)
 		if !reflect.DeepEqual(timestampsCopy, timestampsExpected) {
 			t.Fatalf("invalid deduplicateSamplesDuringMerge(%v) result;\ngot\n%v\nwant\n%v", timestamps, timestampsCopy, timestampsExpected)
 		}
@@ -129,9 +127,9 @@ func TestDeduplicateSamplesDuringMerge(t *testing.T) {
 			t.Fatalf("superfluous timestamps found starting from index %d: %v", j, timestampsCopy[j:])
 		}
 
-		// Verify that the second call to DeduplicatSamples doesn't modify samples.
+		// Verify that the second call to DeduplicateSamples doesn't modify samples.
 		valuesCopy := append([]int64{}, values...)
-		timestampsCopy, valuesCopy = deduplicateSamplesDuringMerge(timestampsCopy, valuesCopy)
+		timestampsCopy, valuesCopy = deduplicateSamplesDuringMerge(timestampsCopy, valuesCopy, dedupInterval)
 		if !reflect.DeepEqual(timestampsCopy, timestampsExpected) {
 			t.Fatalf("invalid deduplicateSamplesDuringMerge(%v) timestamps for the second call;\ngot\n%v\nwant\n%v", timestamps, timestampsCopy, timestampsExpected)
 		}
diff --git a/lib/storage/dedup_timing_test.go b/lib/storage/dedup_timing_test.go
index 9be079403..6bdd4fc32 100644
--- a/lib/storage/dedup_timing_test.go
+++ b/lib/storage/dedup_timing_test.go
@@ -15,8 +15,7 @@ func BenchmarkDeduplicateSamples(b *testing.B) {
 	}
 	for _, minScrapeInterval := range []time.Duration{time.Second, 2 * time.Second, 5 * time.Second, 10 * time.Second} {
 		b.Run(fmt.Sprintf("minScrapeInterval=%s", minScrapeInterval), func(b *testing.B) {
-			SetMinScrapeIntervalForDeduplication(minScrapeInterval)
-			defer SetMinScrapeIntervalForDeduplication(0)
+			dedupInterval := minScrapeInterval.Milliseconds()
 			b.ReportAllocs()
 			b.SetBytes(blockSize)
 			b.RunParallel(func(pb *testing.PB) {
@@ -25,7 +24,7 @@ func BenchmarkDeduplicateSamples(b *testing.B) {
 				for pb.Next() {
 					timestampsCopy := append(timestampsCopy[:0], timestamps...)
 					valuesCopy := append(valuesCopy[:0], values...)
-					ts, vs := DeduplicateSamples(timestampsCopy, valuesCopy)
+					ts, vs := DeduplicateSamples(timestampsCopy, valuesCopy, dedupInterval)
 					if len(ts) == 0 || len(vs) == 0 {
 						panic(fmt.Errorf("expecting non-empty results; got\nts=%v\nvs=%v", ts, vs))
 					}
diff --git a/lib/storage/storage_test.go b/lib/storage/storage_test.go
index 975ebe7bc..c58788a83 100644
--- a/lib/storage/storage_test.go
+++ b/lib/storage/storage_test.go
@@ -14,6 +14,24 @@ import (
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/uint64set"
 )
 
+func TestReplaceAlternateRegexpsWithGraphiteWildcards(t *testing.T) {
+	f := func(q, resultExpected string) {
+		t.Helper()
+		result := replaceAlternateRegexpsWithGraphiteWildcards([]byte(q))
+		if string(result) != resultExpected {
+			t.Fatalf("unexpected result for %s\ngot\n%s\nwant\n%s", q, result, resultExpected)
+		}
+	}
+	f("", "")
+	f("foo", "foo")
+	f("foo(bar", "foo(bar")
+	f("foo.(bar|baz", "foo.(bar|baz")
+	f("foo.(bar).x", "foo.{bar}.x")
+	f("foo.(bar|baz).*.{x,y}", "foo.{bar,baz}.*.{x,y}")
+	f("foo.(bar|baz).*.{x,y}(z|aa)", "foo.{bar,baz}.*.{x,y}{z,aa}")
+	f("foo(.*)", "foo*")
+}
+
 func TestGetRegexpForGraphiteNodeQuery(t *testing.T) {
 	f := func(q, expectedRegexp string) {
 		t.Helper()