mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-01 14:47:38 +00:00
Merge branch 'public-single-node' into pmm-6401-read-prometheus-data-files
This commit is contained in:
commit
21140318cc
172 changed files with 4996 additions and 3003 deletions
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
|
@ -15,6 +15,8 @@ jobs:
|
|||
steps:
|
||||
- name: Code checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.workflow_run.head_branch }}
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v3
|
||||
|
|
|
@ -1085,7 +1085,9 @@ The [deduplication](#deduplication) isn't applied for the data exported in nativ
|
|||
|
||||
## How to import time series data
|
||||
|
||||
Time series data can be imported into VictoriaMetrics via any supported data ingestion protocol:
|
||||
VictoriaMetrics can discover and scrape metrics from Prometheus-compatible targets (aka "pull" protocol) -
|
||||
see [these docs](#how-to-scrape-prometheus-exporters-such-as-node-exporter).
|
||||
Additionally, VictoriaMetrics can accept metrics via the following popular data ingestion protocols (aka "push" protocols):
|
||||
|
||||
* [Prometheus remote_write API](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write). See [these docs](#prometheus-setup) for details.
|
||||
* DataDog `submit metrics` API. See [these docs](#how-to-send-data-from-datadog-agent) for details.
|
||||
|
|
|
@ -129,7 +129,7 @@ func setUp() {
|
|||
storagePath = filepath.Join(os.TempDir(), testStorageSuffix)
|
||||
processFlags()
|
||||
logger.Init()
|
||||
vmstorage.InitWithoutMetrics(promql.ResetRollupResultCacheIfNeeded)
|
||||
vmstorage.Init(promql.ResetRollupResultCacheIfNeeded)
|
||||
vmselect.Init()
|
||||
vminsert.Init()
|
||||
go httpserver.Serve(*httpListenAddr, requestHandler)
|
||||
|
@ -189,10 +189,8 @@ func tearDown() {
|
|||
|
||||
func TestWriteRead(t *testing.T) {
|
||||
t.Run("write", testWrite)
|
||||
vmstorage.Storage.DebugFlush()
|
||||
time.Sleep(1 * time.Second)
|
||||
vmstorage.Stop()
|
||||
// open storage after stop in write
|
||||
vmstorage.InitWithoutMetrics(promql.ResetRollupResultCacheIfNeeded)
|
||||
t.Run("read", testRead)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
package prometheusimport
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmagent/common"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmagent/remotewrite"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/auth"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
|
||||
parserCommon "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/common"
|
||||
parser "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/prometheus"
|
||||
|
@ -33,14 +33,9 @@ func InsertHandler(at *auth.Token, req *http.Request) error {
|
|||
isGzipped := req.Header.Get("Content-Encoding") == "gzip"
|
||||
return parser.ParseStream(req.Body, defaultTimestamp, isGzipped, func(rows []parser.Row) error {
|
||||
return insertRows(at, rows, extraLabels)
|
||||
}, nil)
|
||||
}
|
||||
|
||||
// InsertHandlerForReader processes metrics from given reader with optional gzip format
|
||||
func InsertHandlerForReader(r io.Reader, isGzipped bool) error {
|
||||
return parser.ParseStream(r, 0, isGzipped, func(rows []parser.Row) error {
|
||||
return insertRows(nil, rows, nil)
|
||||
}, nil)
|
||||
}, func(s string) {
|
||||
httpserver.LogError(req, s)
|
||||
})
|
||||
}
|
||||
|
||||
func insertRows(at *auth.Token, rows []parser.Row, extraLabels []prompbmarshal.Label) error {
|
||||
|
|
56
app/vmagent/prometheusimport/request_handler_test.go
Normal file
56
app/vmagent/prometheusimport/request_handler_test.go
Normal file
|
@ -0,0 +1,56 @@
|
|||
package prometheusimport
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmagent/remotewrite"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/common"
|
||||
)
|
||||
|
||||
var (
|
||||
srv *httptest.Server
|
||||
testOutput *bytes.Buffer
|
||||
)
|
||||
|
||||
func TestInsertHandler(t *testing.T) {
|
||||
setUp()
|
||||
defer tearDown()
|
||||
req := httptest.NewRequest("POST", "/insert/0/api/v1/import/prometheus", bytes.NewBufferString(`{"foo":"bar"}
|
||||
go_memstats_alloc_bytes_total 1`))
|
||||
if err := InsertHandler(nil, req); err != nil {
|
||||
t.Errorf("unxepected error %s", err)
|
||||
}
|
||||
expectedMsg := "cannot unmarshal Prometheus line"
|
||||
if !strings.Contains(testOutput.String(), expectedMsg) {
|
||||
t.Errorf("output %q should contain %q", testOutput.String(), expectedMsg)
|
||||
}
|
||||
}
|
||||
|
||||
func setUp() {
|
||||
srv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(204)
|
||||
}))
|
||||
flag.Parse()
|
||||
remoteWriteFlag := "remoteWrite.url"
|
||||
if err := flag.Lookup(remoteWriteFlag).Value.Set(srv.URL); err != nil {
|
||||
log.Fatalf("unable to set %q with value %q, err: %v", remoteWriteFlag, srv.URL, err)
|
||||
}
|
||||
logger.Init()
|
||||
common.StartUnmarshalWorkers()
|
||||
remotewrite.Init()
|
||||
testOutput = &bytes.Buffer{}
|
||||
logger.SetOutputForTests(testOutput)
|
||||
}
|
||||
|
||||
func tearDown() {
|
||||
common.StopUnmarshalWorkers()
|
||||
srv.Close()
|
||||
logger.ResetOutputForTest()
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package promremotewrite
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmagent/common"
|
||||
|
@ -33,13 +32,6 @@ func InsertHandler(at *auth.Token, req *http.Request) error {
|
|||
})
|
||||
}
|
||||
|
||||
// InsertHandlerForReader processes metrics from given reader
|
||||
func InsertHandlerForReader(at *auth.Token, r io.Reader) error {
|
||||
return parser.ParseStream(r, func(tss []prompb.TimeSeries) error {
|
||||
return insertRows(at, tss, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func insertRows(at *auth.Token, timeseries []prompb.TimeSeries, extraLabels []prompbmarshal.Label) error {
|
||||
ctx := common.GetPushCtx()
|
||||
defer common.PutPushCtx(ctx)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package vmimport
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmagent/common"
|
||||
|
@ -36,13 +35,6 @@ func InsertHandler(at *auth.Token, req *http.Request) error {
|
|||
})
|
||||
}
|
||||
|
||||
// InsertHandlerForReader processes metrics from given reader
|
||||
func InsertHandlerForReader(r io.Reader, isGzipped bool) error {
|
||||
return parser.ParseStream(r, isGzipped, func(rows []parser.Row) error {
|
||||
return insertRows(nil, rows, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func insertRows(at *auth.Token, rows []parser.Row, extraLabels []prompbmarshal.Label) error {
|
||||
ctx := common.GetPushCtx()
|
||||
defer common.PutPushCtx(ctx)
|
||||
|
|
|
@ -64,17 +64,18 @@ func TestManagerUpdateConcurrent(t *testing.T) {
|
|||
wg := sync.WaitGroup{}
|
||||
wg.Add(workers)
|
||||
for i := 0; i < workers; i++ {
|
||||
go func() {
|
||||
go func(n int) {
|
||||
defer wg.Done()
|
||||
r := rand.New(rand.NewSource(int64(n)))
|
||||
for i := 0; i < iterations; i++ {
|
||||
rnd := rand.Intn(len(paths))
|
||||
rnd := r.Intn(len(paths))
|
||||
cfg, err := config.Parse([]string{paths[rnd]}, notifier.ValidateTemplates, true)
|
||||
if err != nil { // update can fail and this is expected
|
||||
continue
|
||||
}
|
||||
_ = m.update(context.Background(), cfg, false)
|
||||
}
|
||||
}()
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
|
|
@ -162,14 +162,15 @@ consul_sd_configs:
|
|||
wg := sync.WaitGroup{}
|
||||
wg.Add(workers)
|
||||
for i := 0; i < workers; i++ {
|
||||
go func() {
|
||||
go func(n int) {
|
||||
defer wg.Done()
|
||||
r := rand.New(rand.NewSource(int64(n)))
|
||||
for i := 0; i < iterations; i++ {
|
||||
rnd := rand.Intn(len(paths))
|
||||
rnd := r.Intn(len(paths))
|
||||
_ = cw.reload(paths[rnd]) // update can fail and this is expected
|
||||
_ = cw.notifiers()
|
||||
}
|
||||
}()
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
|
|
@ -27,12 +27,13 @@ func TestClient_Push(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("failed to create client: %s", err)
|
||||
}
|
||||
r := rand.New(rand.NewSource(1))
|
||||
const rowsN = 1e4
|
||||
var sent int
|
||||
for i := 0; i < rowsN; i++ {
|
||||
s := prompbmarshal.TimeSeries{
|
||||
Samples: []prompbmarshal.Sample{{
|
||||
Value: rand.Float64(),
|
||||
Value: r.Float64(),
|
||||
Timestamp: time.Now().Unix(),
|
||||
}},
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vminsert/common"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vminsert/relabel"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
|
||||
parserCommon "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/common"
|
||||
parser "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/prometheus"
|
||||
|
@ -29,7 +30,9 @@ func InsertHandler(req *http.Request) error {
|
|||
isGzipped := req.Header.Get("Content-Encoding") == "gzip"
|
||||
return parser.ParseStream(req.Body, defaultTimestamp, isGzipped, func(rows []parser.Row) error {
|
||||
return insertRows(rows, extraLabels)
|
||||
}, nil)
|
||||
}, func(s string) {
|
||||
httpserver.LogError(req, s)
|
||||
})
|
||||
}
|
||||
|
||||
func insertRows(rows []parser.Row, extraLabels []prompbmarshal.Label) error {
|
||||
|
|
|
@ -35,9 +35,10 @@ var (
|
|||
)
|
||||
|
||||
var benchValues = func() []float64 {
|
||||
r := rand.New(rand.NewSource(1))
|
||||
values := make([]float64, 1000)
|
||||
for i := range values {
|
||||
values[i] = rand.Float64() * 100
|
||||
values[i] = r.Float64() * 100
|
||||
}
|
||||
return values
|
||||
}()
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
{
|
||||
"files": {
|
||||
"main.css": "./static/css/main.e8e53cbf.css",
|
||||
"main.js": "./static/js/main.58fe7908.js",
|
||||
"main.css": "./static/css/main.9ca6b743.css",
|
||||
"main.js": "./static/js/main.8969be5f.js",
|
||||
"static/js/27.c1ccfd29.chunk.js": "./static/js/27.c1ccfd29.chunk.js",
|
||||
"static/media/Lato-Regular.ttf": "./static/media/Lato-Regular.d714fec1633b69a9c2e9.ttf",
|
||||
"static/media/Lato-Bold.ttf": "./static/media/Lato-Bold.32360ba4b57802daa4d6.ttf",
|
||||
"index.html": "./index.html"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/css/main.e8e53cbf.css",
|
||||
"static/js/main.58fe7908.js"
|
||||
"static/css/main.9ca6b743.css",
|
||||
"static/js/main.8969be5f.js"
|
||||
]
|
||||
}
|
|
@ -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="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono&family=Lato:wght@300;400;700&display=swap" rel="stylesheet"><script src="./dashboards/index.js" type="module"></script><script defer="defer" src="./static/js/main.58fe7908.js"></script><link href="./static/css/main.e8e53cbf.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="UI for VictoriaMetrics"/><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><script src="./dashboards/index.js" type="module"></script><meta name="twitter:card" content="summary_large_image"><meta name="twitter:image" content="./preview.jpg"><meta name="twitter:title" content="UI for VictoriaMetrics"><meta name="twitter:description" content="Explore and troubleshoot your VictoriaMetrics data"><meta name="twitter:site" content="@VictoriaMetrics"><meta property="og:title" content="Metric explorer for VictoriaMetrics"><meta property="og:description" content="Explore and troubleshoot your VictoriaMetrics data"><meta property="og:image" content="./preview.jpg"><meta property="og:type" content="website"><script defer="defer" src="./static/js/main.8969be5f.js"></script><link href="./static/css/main.9ca6b743.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
BIN
app/vmselect/vmui/preview.jpg
Normal file
BIN
app/vmselect/vmui/preview.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 67 KiB |
1
app/vmselect/vmui/static/css/main.9ca6b743.css
Normal file
1
app/vmselect/vmui/static/css/main.9ca6b743.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
app/vmselect/vmui/static/js/main.8969be5f.js
Normal file
2
app/vmselect/vmui/static/js/main.8969be5f.js
Normal file
File diff suppressed because one or more lines are too long
|
@ -7,7 +7,7 @@
|
|||
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
|
||||
|
||||
/**
|
||||
* @remix-run/router v1.0.5
|
||||
* @remix-run/router v1.3.0
|
||||
*
|
||||
* Copyright (c) Remix Software Inc.
|
||||
*
|
||||
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* React Router DOM v6.4.5
|
||||
* React Router DOM v6.7.0
|
||||
*
|
||||
* Copyright (c) Remix Software Inc.
|
||||
*
|
||||
|
@ -29,7 +29,7 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* React Router v6.4.5
|
||||
* React Router v6.7.0
|
||||
*
|
||||
* Copyright (c) Remix Software Inc.
|
||||
*
|
Binary file not shown.
Binary file not shown.
|
@ -85,14 +85,6 @@ func CheckTimeRange(tr storage.TimeRange) error {
|
|||
|
||||
// Init initializes vmstorage.
|
||||
func Init(resetCacheIfNeeded func(mrs []storage.MetricRow)) {
|
||||
InitWithoutMetrics(resetCacheIfNeeded)
|
||||
registerStorageMetrics(Storage)
|
||||
}
|
||||
|
||||
// InitWithoutMetrics must be called instead of Init inside tests.
|
||||
//
|
||||
// This allows multiple Init / Stop cycles.
|
||||
func InitWithoutMetrics(resetCacheIfNeeded func(mrs []storage.MetricRow)) {
|
||||
if err := encoding.CheckPrecisionBits(uint8(*precisionBits)); err != nil {
|
||||
logger.Fatalf("invalid `-precisionBits`: %s", err)
|
||||
}
|
||||
|
@ -131,6 +123,7 @@ func InitWithoutMetrics(resetCacheIfNeeded func(mrs []storage.MetricRow)) {
|
|||
sizeBytes := tm.SmallSizeBytes + tm.BigSizeBytes
|
||||
logger.Infof("successfully opened storage %q in %.3f seconds; partsCount: %d; blocksCount: %d; rowsCount: %d; sizeBytes: %d",
|
||||
*DataPath, time.Since(startTime).Seconds(), partsCount, blocksCount, rowsCount, sizeBytes)
|
||||
registerStorageMetrics(Storage)
|
||||
|
||||
promdb.Init(retentionPeriod.Msecs)
|
||||
}
|
||||
|
|
1246
app/vmui/packages/vmui/package-lock.json
generated
1246
app/vmui/packages/vmui/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -7,7 +7,7 @@
|
|||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="VM-UI is a metric explorer for Victoria Metrics"
|
||||
content="UI for VictoriaMetrics"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/apple-touch-icon.png" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="%PUBLIC_URL%/favicon-32x32.png">
|
||||
|
@ -26,10 +26,18 @@
|
|||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>VM UI</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono&family=Lato:wght@300;400;700&display=swap" rel="stylesheet">
|
||||
<script src="%PUBLIC_URL%/dashboards/index.js" type="module"></script>
|
||||
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:image" content="%PUBLIC_URL%/preview.jpg">
|
||||
<meta name="twitter:title" content="UI for VictoriaMetrics">
|
||||
<meta name="twitter:description" content="Explore and troubleshoot your VictoriaMetrics data">
|
||||
<meta name="twitter:site" content="@VictoriaMetrics">
|
||||
|
||||
<meta property="og:title" content="Metric explorer for VictoriaMetrics">
|
||||
<meta property="og:description" content="Explore and troubleshoot your VictoriaMetrics data">
|
||||
<meta property="og:image" content="%PUBLIC_URL%/preview.jpg">
|
||||
<meta property="og:type" content="website">
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
|
|
BIN
app/vmui/packages/vmui/public/preview.jpg
Normal file
BIN
app/vmui/packages/vmui/public/preview.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 67 KiB |
|
@ -17,15 +17,11 @@ const App: FC = () => {
|
|||
|
||||
const [loadingTheme, setLoadingTheme] = useState(true);
|
||||
|
||||
if (loadingTheme) return (
|
||||
<>
|
||||
<Spinner/>
|
||||
<ThemeProvider setLoadingTheme={setLoadingTheme}/>;
|
||||
</>
|
||||
);
|
||||
|
||||
return <>
|
||||
<HashRouter>
|
||||
{loadingTheme && <Spinner/>}
|
||||
<ThemeProvider setLoadingTheme={setLoadingTheme}/>
|
||||
|
||||
<HashRouter key={`${loadingTheme}`}>
|
||||
<AppContextProvider>
|
||||
<Routes>
|
||||
<Route
|
||||
|
|
BIN
app/vmui/packages/vmui/src/assets/fonts/Lato/Lato-Bold.ttf
Normal file
BIN
app/vmui/packages/vmui/src/assets/fonts/Lato/Lato-Bold.ttf
Normal file
Binary file not shown.
BIN
app/vmui/packages/vmui/src/assets/fonts/Lato/Lato-Regular.ttf
Normal file
BIN
app/vmui/packages/vmui/src/assets/fonts/Lato/Lato-Regular.ttf
Normal file
Binary file not shown.
|
@ -3,11 +3,13 @@ import uPlot, { Options as uPlotOptions } from "uplot";
|
|||
import useResize from "../../../hooks/useResize";
|
||||
import { BarChartProps } from "./types";
|
||||
import "./style.scss";
|
||||
import { useAppState } from "../../../state/common/StateContext";
|
||||
|
||||
const BarChart: FC<BarChartProps> = ({
|
||||
data,
|
||||
container,
|
||||
configs }) => {
|
||||
const { darkTheme } = useAppState();
|
||||
|
||||
const uPlotRef = useRef<HTMLDivElement>(null);
|
||||
const [uPlotInst, setUPlotInst] = useState<uPlot>();
|
||||
|
@ -28,7 +30,7 @@ const BarChart: FC<BarChartProps> = ({
|
|||
const u = new uPlot(options, data, uPlotRef.current);
|
||||
setUPlotInst(u);
|
||||
return u.destroy;
|
||||
}, [uPlotRef.current, layoutSize]);
|
||||
}, [uPlotRef.current, layoutSize, darkTheme]);
|
||||
|
||||
useEffect(() => updateChart(), [data]);
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@ $chart-tooltip-y: -1 * ($padding-small + $chart-tooltip-half-icon);
|
|||
pointer-events: none;
|
||||
|
||||
&_sticky {
|
||||
background-color: $color-dove-gray;
|
||||
pointer-events: auto;
|
||||
z-index: 99;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import "./style.scss";
|
|||
import classNames from "classnames";
|
||||
import ChartTooltip, { ChartTooltipProps } from "../ChartTooltip/ChartTooltip";
|
||||
import dayjs from "dayjs";
|
||||
import { useAppState } from "../../../state/common/StateContext";
|
||||
|
||||
export interface LineChartProps {
|
||||
metrics: MetricResult[];
|
||||
|
@ -47,6 +48,8 @@ const LineChart: FC<LineChartProps> = ({
|
|||
container,
|
||||
height
|
||||
}) => {
|
||||
const { darkTheme } = useAppState();
|
||||
|
||||
const uPlotRef = useRef<HTMLDivElement>(null);
|
||||
const [isPanning, setPanning] = useState(false);
|
||||
const [xRange, setXRange] = useState({ min: period.start, max: period.end });
|
||||
|
@ -222,7 +225,7 @@ const LineChart: FC<LineChartProps> = ({
|
|||
setUPlotInst(u);
|
||||
setXRange({ min: period.start, max: period.end });
|
||||
return u.destroy;
|
||||
}, [uPlotRef.current, series, layoutSize, height]);
|
||||
}, [uPlotRef.current, series, layoutSize, height, darkTheme]);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("keydown", handleKeyDown);
|
||||
|
|
|
@ -13,6 +13,7 @@ import { getAppModeEnable } from "../../../utils/app-mode";
|
|||
import classNames from "classnames";
|
||||
import Timezones from "./Timezones/Timezones";
|
||||
import { useTimeDispatch, useTimeState } from "../../../state/time/TimeStateContext";
|
||||
import ThemeControl from "../ThemeControl/ThemeControl";
|
||||
|
||||
const title = "Settings";
|
||||
|
||||
|
@ -82,6 +83,9 @@ const GlobalSettings: FC = () => {
|
|||
onChange={setTimezone}
|
||||
/>
|
||||
</div>
|
||||
<div className="vm-server-configurator__input">
|
||||
<ThemeControl/>
|
||||
</div>
|
||||
<div className="vm-server-configurator__footer">
|
||||
<Button
|
||||
variant="outlined"
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba($color-black, 0.06);
|
||||
background-color: $color-hover-black;
|
||||
padding: calc($padding-small/2);
|
||||
border-radius: $border-radius-small;
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ const GraphSettings: FC<GraphSettingsProps> = ({ yaxis, setYaxisLimits, toggleEn
|
|||
</h3>
|
||||
<Button
|
||||
size="small"
|
||||
variant="text"
|
||||
startIcon={<CloseIcon/>}
|
||||
onClick={handleClose}
|
||||
/>
|
||||
|
|
|
@ -158,7 +158,7 @@ const StepConfigurator: FC = () => {
|
|||
className="vm-link vm-link_colored"
|
||||
href="https://docs.victoriametrics.com/keyConcepts.html#range-query"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
rel="help noreferrer"
|
||||
>
|
||||
Read more about Range query
|
||||
</a>
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
padding: 0.2em 0.4em;
|
||||
margin: 0 0.2em;
|
||||
font-size: 85%;
|
||||
background-color: rgba($color-black, 0.05);
|
||||
background-color: $color-hover-black;
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
import React from "react";
|
||||
import "./style.scss";
|
||||
import classNames from "classnames";
|
||||
import { useAppDispatch, useAppState } from "../../../state/common/StateContext";
|
||||
|
||||
const options = [
|
||||
{ title: "Light", value: false },
|
||||
{ title: "Dark", value: true }
|
||||
];
|
||||
|
||||
const ThemeControl = () => {
|
||||
const { darkTheme } = useAppState();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const createHandlerClickItem = (value: boolean) => () => {
|
||||
dispatch({ type: "SET_DARK_THEME", payload: value });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="vm-theme-control">
|
||||
<div className="vm-server-configurator__title">
|
||||
Theme preferences
|
||||
</div>
|
||||
<div className="vm-theme-control-options">
|
||||
<div
|
||||
className="vm-theme-control-options__highlight"
|
||||
style={{ left: darkTheme ? "50%" : 0 }}
|
||||
/>
|
||||
{options.map(item => (
|
||||
<div
|
||||
className={classNames({
|
||||
"vm-theme-control-options__item": true,
|
||||
"vm-theme-control-options__item_active": item.value === darkTheme
|
||||
})}
|
||||
onClick={createHandlerClickItem(item.value)}
|
||||
key={item.title}
|
||||
>{item.title}</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ThemeControl;
|
|
@ -0,0 +1,44 @@
|
|||
@use "src/styles/variables" as *;
|
||||
|
||||
.vm-theme-control {
|
||||
&-options {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
border: $border-divider;
|
||||
border-radius: $border-radius-medium;
|
||||
overflow: hidden;
|
||||
|
||||
&__item {
|
||||
position: relative;
|
||||
padding: $padding-small $padding-global;
|
||||
border-right: $border-divider;
|
||||
color: $color-text;
|
||||
cursor: pointer;
|
||||
z-index: 2;
|
||||
transition: color 200ms ease-out;
|
||||
user-select: none;
|
||||
|
||||
&:last-child {
|
||||
border: none;
|
||||
}
|
||||
|
||||
&_active {
|
||||
color: $color-primary-text;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
box-shadow: $box-shadow-popper;
|
||||
}
|
||||
}
|
||||
|
||||
&__highlight {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: $color-primary;
|
||||
height: 100%;
|
||||
width: 50%;
|
||||
transition: left 150ms ease-in;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,11 +13,14 @@ import useResize from "../../../../hooks/useResize";
|
|||
import DatePicker from "../../../Main/DatePicker/DatePicker";
|
||||
import "./style.scss";
|
||||
import useClickOutside from "../../../../hooks/useClickOutside";
|
||||
import classNames from "classnames";
|
||||
import { useAppState } from "../../../../state/common/StateContext";
|
||||
|
||||
export const TimeSelector: FC = () => {
|
||||
const { darkTheme } = useAppState();
|
||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||
const documentSize = useResize(document.body);
|
||||
const displayFullDate = useMemo(() => documentSize.width > 1120, [documentSize]);
|
||||
const displayFullDate = useMemo(() => documentSize.width > 1280, [documentSize]);
|
||||
|
||||
const [until, setUntil] = useState<string>();
|
||||
const [from, setFrom] = useState<string>();
|
||||
|
@ -120,7 +123,7 @@ export const TimeSelector: FC = () => {
|
|||
|
||||
return <>
|
||||
<div ref={buttonRef}>
|
||||
<Tooltip title="Time range controls">
|
||||
<Tooltip title={displayFullDate ? "Time range controls" : dateTitle}>
|
||||
<Button
|
||||
className={appModeEnable ? "" : "vm-header-button"}
|
||||
variant="contained"
|
||||
|
@ -144,7 +147,12 @@ export const TimeSelector: FC = () => {
|
|||
ref={wrapperRef}
|
||||
>
|
||||
<div className="vm-time-selector-left">
|
||||
<div className="vm-time-selector-left-inputs">
|
||||
<div
|
||||
className={classNames({
|
||||
"vm-time-selector-left-inputs": true,
|
||||
"vm-time-selector-left-inputs_dark": darkTheme
|
||||
})}
|
||||
>
|
||||
<div
|
||||
className="vm-time-selector-left-inputs__date"
|
||||
ref={fromRef}
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
align-items: flex-start;
|
||||
justify-content: stretch;
|
||||
|
||||
&_dark &__date {
|
||||
border-color: $color-text-disabled;
|
||||
}
|
||||
|
||||
&__date {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 14px;
|
||||
|
@ -70,7 +74,7 @@
|
|||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba($color-black, 0.06);
|
||||
background-color: $color-hover-black;
|
||||
padding: calc($padding-small/2);
|
||||
border-radius: $border-radius-small;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
code {
|
||||
padding: 0.2em 0.4em;
|
||||
font-size: 85%;
|
||||
background-color: rgba($color-black, 0.05);
|
||||
background-color: $color-hover-black;
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React, { FC } from "preact/compat";
|
||||
import dayjs from "dayjs";
|
||||
import "./style.scss";
|
||||
import { LogoIcon } from "../../Main/Icons";
|
||||
import { IssueIcon, LogoIcon, WikiIcon } from "../../Main/Icons";
|
||||
|
||||
const Footer: FC = () => {
|
||||
const copyrightYears = `2019-${dayjs().format("YYYY")}`;
|
||||
|
@ -11,18 +11,28 @@ const Footer: FC = () => {
|
|||
className="vm-link vm-footer__website"
|
||||
target="_blank"
|
||||
href="https://victoriametrics.com/"
|
||||
rel="noreferrer"
|
||||
rel="me noreferrer"
|
||||
>
|
||||
<LogoIcon/>
|
||||
victoriametrics.com
|
||||
</a>
|
||||
<a
|
||||
className="vm-link"
|
||||
className="vm-link vm-footer__link"
|
||||
target="_blank"
|
||||
href="https://docs.victoriametrics.com/#vmui"
|
||||
rel="help noreferrer"
|
||||
>
|
||||
<WikiIcon/>
|
||||
Documentation
|
||||
</a>
|
||||
<a
|
||||
className="vm-link vm-footer__link"
|
||||
target="_blank"
|
||||
href="https://github.com/VictoriaMetrics/VictoriaMetrics/issues/new/choose"
|
||||
rel="noreferrer"
|
||||
>
|
||||
create an issue
|
||||
<IssueIcon/>
|
||||
Create an issue
|
||||
</a>
|
||||
<div className="vm-footer__copyright">
|
||||
© {copyrightYears} VictoriaMetrics
|
||||
|
|
|
@ -5,10 +5,12 @@
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: $padding-medium;
|
||||
gap: $padding-large;
|
||||
gap: $padding-medium;
|
||||
border-top: $border-divider;
|
||||
color: $color-text-secondary;
|
||||
background: $color-background-body;
|
||||
|
||||
&__link,
|
||||
&__website {
|
||||
display: grid;
|
||||
grid-template-columns: 12px auto;
|
||||
|
@ -17,6 +19,14 @@
|
|||
gap: 6px;
|
||||
}
|
||||
|
||||
&__website {
|
||||
margin-right: $padding-global;
|
||||
}
|
||||
|
||||
&__link {
|
||||
grid-template-columns: 14px auto;
|
||||
}
|
||||
|
||||
&__copyright {
|
||||
text-align: right;
|
||||
flex-grow: 1;
|
||||
|
|
|
@ -1,86 +1,58 @@
|
|||
import React, { FC, useMemo, useState } from "preact/compat";
|
||||
import React, { FC, useMemo } from "preact/compat";
|
||||
import { ExecutionControls } from "../../Configurators/TimeRangeSettings/ExecutionControls/ExecutionControls";
|
||||
import { setQueryStringWithoutPageReload } from "../../../utils/query-string";
|
||||
import { TimeSelector } from "../../Configurators/TimeRangeSettings/TimeSelector/TimeSelector";
|
||||
import GlobalSettings from "../../Configurators/GlobalSettings/GlobalSettings";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import router, { RouterOptions, routerOptions } from "../../../router";
|
||||
import { useEffect } from "react";
|
||||
import ShortcutKeys from "../../Main/ShortcutKeys/ShortcutKeys";
|
||||
import { getAppModeEnable, getAppModeParams } from "../../../utils/app-mode";
|
||||
import CardinalityDatePicker from "../../Configurators/CardinalityDatePicker/CardinalityDatePicker";
|
||||
import { LogoFullIcon } from "../../Main/Icons";
|
||||
import { getCssVariable } from "../../../utils/theme";
|
||||
import Tabs from "../../Main/Tabs/Tabs";
|
||||
import "./style.scss";
|
||||
import classNames from "classnames";
|
||||
import { useDashboardsState } from "../../../state/dashboards/DashboardsStateContext";
|
||||
import StepConfigurator from "../../Configurators/StepConfigurator/StepConfigurator";
|
||||
import { useAppState } from "../../../state/common/StateContext";
|
||||
import HeaderNav from "./HeaderNav/HeaderNav";
|
||||
|
||||
const Header: FC = () => {
|
||||
const primaryColor = getCssVariable("color-primary");
|
||||
const { darkTheme } = useAppState();
|
||||
const appModeEnable = getAppModeEnable();
|
||||
const { dashboardsSettings } = useDashboardsState();
|
||||
|
||||
const { headerStyles: {
|
||||
background = appModeEnable ? "#FFF" : primaryColor,
|
||||
color = appModeEnable ? primaryColor : "#FFF",
|
||||
} = {} } = getAppModeParams();
|
||||
const primaryColor = useMemo(() => {
|
||||
const variable = darkTheme ? "color-background-block" : "color-primary";
|
||||
return getCssVariable(variable);
|
||||
}, [darkTheme]);
|
||||
|
||||
const { background, color } = useMemo(() => {
|
||||
const { headerStyles: {
|
||||
background = appModeEnable ? "#FFF" : primaryColor,
|
||||
color = appModeEnable ? primaryColor : "#FFF",
|
||||
} = {} } = getAppModeParams();
|
||||
|
||||
return { background, color };
|
||||
}, [primaryColor]);
|
||||
|
||||
const navigate = useNavigate();
|
||||
const { search, pathname } = useLocation();
|
||||
const routes = useMemo(() => ([
|
||||
{
|
||||
label: routerOptions[router.home].title,
|
||||
value: router.home,
|
||||
},
|
||||
{
|
||||
label: routerOptions[router.metrics].title,
|
||||
value: router.metrics,
|
||||
},
|
||||
{
|
||||
label: routerOptions[router.cardinality].title,
|
||||
value: router.cardinality,
|
||||
},
|
||||
{
|
||||
label: routerOptions[router.topQueries].title,
|
||||
value: router.topQueries,
|
||||
},
|
||||
{
|
||||
label: routerOptions[router.trace].title,
|
||||
value: router.trace,
|
||||
},
|
||||
{
|
||||
label: routerOptions[router.dashboards].title,
|
||||
value: router.dashboards,
|
||||
hide: appModeEnable || !dashboardsSettings.length
|
||||
}
|
||||
]), [appModeEnable, dashboardsSettings]);
|
||||
|
||||
const [activeMenu, setActiveMenu] = useState(pathname);
|
||||
|
||||
const headerSetup = useMemo(() => {
|
||||
return ((routerOptions[pathname] || {}) as RouterOptions).header || {};
|
||||
}, [pathname]);
|
||||
|
||||
const onClickLogo = () => {
|
||||
navigateHandler(router.home);
|
||||
navigate({ pathname: router.home, search: search });
|
||||
setQueryStringWithoutPageReload({});
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
const navigateHandler = (pathname: string) => {
|
||||
navigate({ pathname, search: search });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setActiveMenu(pathname);
|
||||
}, [pathname]);
|
||||
|
||||
return <header
|
||||
className={classNames({
|
||||
"vm-header": true,
|
||||
"vm-header_app": appModeEnable
|
||||
"vm-header_app": appModeEnable,
|
||||
"vm-header_dark": darkTheme
|
||||
})}
|
||||
style={{ background, color }}
|
||||
>
|
||||
|
@ -93,14 +65,10 @@ const Header: FC = () => {
|
|||
<LogoFullIcon/>
|
||||
</div>
|
||||
)}
|
||||
<div className="vm-header-nav">
|
||||
<Tabs
|
||||
isNavLink
|
||||
activeItem={activeMenu}
|
||||
items={routes.filter(r => !r.hide)}
|
||||
color={color}
|
||||
/>
|
||||
</div>
|
||||
<HeaderNav
|
||||
color={color}
|
||||
background={background}
|
||||
/>
|
||||
<div className="vm-header__settings">
|
||||
{headerSetup?.stepControl && <StepConfigurator/>}
|
||||
{headerSetup?.timeSelector && <TimeSelector/>}
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
import React, { FC, useMemo, useState } from "preact/compat";
|
||||
import router, { routerOptions } from "../../../../router";
|
||||
import { getAppModeEnable } from "../../../../utils/app-mode";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { useDashboardsState } from "../../../../state/dashboards/DashboardsStateContext";
|
||||
import { useEffect } from "react";
|
||||
import "./style.scss";
|
||||
import NavItem from "./NavItem";
|
||||
import NavSubItem from "./NavSubItem";
|
||||
|
||||
interface HeaderNavProps {
|
||||
color: string
|
||||
background: string
|
||||
}
|
||||
|
||||
const HeaderNav: FC<HeaderNavProps> = ({ color, background }) => {
|
||||
const appModeEnable = getAppModeEnable();
|
||||
const { dashboardsSettings } = useDashboardsState();
|
||||
const { pathname } = useLocation();
|
||||
|
||||
const [activeMenu, setActiveMenu] = useState(pathname);
|
||||
|
||||
const menu = useMemo(() => ([
|
||||
{
|
||||
label: routerOptions[router.home].title,
|
||||
value: router.home,
|
||||
},
|
||||
{
|
||||
label: "Explore",
|
||||
submenu: [
|
||||
{
|
||||
label: routerOptions[router.metrics].title,
|
||||
value: router.metrics,
|
||||
},
|
||||
{
|
||||
label: routerOptions[router.cardinality].title,
|
||||
value: router.cardinality,
|
||||
},
|
||||
{
|
||||
label: routerOptions[router.topQueries].title,
|
||||
value: router.topQueries,
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: routerOptions[router.trace].title,
|
||||
value: router.trace,
|
||||
},
|
||||
{
|
||||
label: routerOptions[router.dashboards].title,
|
||||
value: router.dashboards,
|
||||
hide: appModeEnable || !dashboardsSettings.length,
|
||||
}
|
||||
].filter(r => !r.hide)), [appModeEnable, dashboardsSettings]);
|
||||
|
||||
useEffect(() => {
|
||||
setActiveMenu(pathname);
|
||||
}, [pathname]);
|
||||
|
||||
|
||||
return (
|
||||
<nav className="vm-header-nav">
|
||||
{menu.map(m => (
|
||||
m.submenu
|
||||
? (
|
||||
<NavSubItem
|
||||
key={m.label}
|
||||
activeMenu={activeMenu}
|
||||
label={m.label || ""}
|
||||
submenu={m.submenu}
|
||||
color={color}
|
||||
background={background}
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<NavItem
|
||||
key={m.value}
|
||||
activeMenu={activeMenu}
|
||||
value={m.value}
|
||||
label={m.label || ""}
|
||||
color={color}
|
||||
/>
|
||||
)
|
||||
))}
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
export default HeaderNav;
|
|
@ -0,0 +1,30 @@
|
|||
import React, { FC } from "preact/compat";
|
||||
import { NavLink } from "react-router-dom";
|
||||
import classNames from "classnames";
|
||||
|
||||
interface NavItemProps {
|
||||
activeMenu: string,
|
||||
label: string,
|
||||
value: string,
|
||||
color?: string
|
||||
}
|
||||
|
||||
const NavItem: FC<NavItemProps> = ({
|
||||
activeMenu,
|
||||
label,
|
||||
value,
|
||||
color
|
||||
}) => (
|
||||
<NavLink
|
||||
className={classNames({
|
||||
"vm-header-nav-item": true,
|
||||
"vm-header-nav-item_active": activeMenu === value // || m.submenu?.find(m => m.value === activeMenu)
|
||||
})}
|
||||
style={{ color }}
|
||||
to={value}
|
||||
>
|
||||
{label}
|
||||
</NavLink>
|
||||
);
|
||||
|
||||
export default NavItem;
|
|
@ -0,0 +1,96 @@
|
|||
import React, { FC, useRef, useState } from "preact/compat";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import classNames from "classnames";
|
||||
import { ArrowDropDownIcon } from "../../../Main/Icons";
|
||||
import Popper from "../../../Main/Popper/Popper";
|
||||
import NavItem from "./NavItem";
|
||||
import { useEffect } from "react";
|
||||
|
||||
interface NavItemProps {
|
||||
activeMenu: string,
|
||||
label: string,
|
||||
submenu: {label: string | undefined, value: string}[],
|
||||
color?: string
|
||||
background?: string
|
||||
}
|
||||
|
||||
const NavSubItem: FC<NavItemProps> = ({
|
||||
activeMenu,
|
||||
label,
|
||||
color,
|
||||
background,
|
||||
submenu
|
||||
}) => {
|
||||
const { pathname } = useLocation();
|
||||
|
||||
const [openSubmenu, setOpenSubmenu] = useState(false);
|
||||
const [menuTimeout, setMenuTimeout] = useState<NodeJS.Timeout | null>(null);
|
||||
const buttonRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const handleOpenSubmenu = () => {
|
||||
setOpenSubmenu(true);
|
||||
if (menuTimeout) clearTimeout(menuTimeout);
|
||||
};
|
||||
|
||||
const handleCloseSubmenu = () => {
|
||||
setOpenSubmenu(false);
|
||||
};
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
if (menuTimeout) clearTimeout(menuTimeout);
|
||||
const timeout = setTimeout(handleCloseSubmenu, 300);
|
||||
setMenuTimeout(timeout);
|
||||
};
|
||||
|
||||
const handleMouseEnterPopup = () => {
|
||||
if (menuTimeout) clearTimeout(menuTimeout);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
handleCloseSubmenu();
|
||||
}, [pathname]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames({
|
||||
"vm-header-nav-item": true,
|
||||
"vm-header-nav-item_sub": true,
|
||||
"vm-header-nav-item_open": openSubmenu,
|
||||
"vm-header-nav-item_active": submenu.find(m => m.value === activeMenu)
|
||||
})}
|
||||
style={{ color }}
|
||||
onMouseEnter={handleOpenSubmenu}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
ref={buttonRef}
|
||||
>
|
||||
{label}
|
||||
<ArrowDropDownIcon/>
|
||||
|
||||
<Popper
|
||||
open={openSubmenu}
|
||||
placement="bottom-left"
|
||||
offset={{ top: 12, left: 0 }}
|
||||
onClose={handleCloseSubmenu}
|
||||
buttonRef={buttonRef}
|
||||
>
|
||||
<div
|
||||
className="vm-header-nav-item-submenu"
|
||||
style={{ background }}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
onMouseEnter={handleMouseEnterPopup}
|
||||
>
|
||||
{submenu.map(sm => (
|
||||
<NavItem
|
||||
key={sm.value}
|
||||
activeMenu={activeMenu}
|
||||
value={sm.value}
|
||||
label={sm.label || ""}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</Popper>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default NavSubItem;
|
|
@ -0,0 +1,63 @@
|
|||
@use "src/styles/variables" as *;
|
||||
|
||||
.vm-header-nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: $padding-global;
|
||||
font-size: $font-size-small;
|
||||
font-weight: bold;
|
||||
|
||||
&-item {
|
||||
position: relative;
|
||||
padding: $padding-global $padding-small;
|
||||
opacity: 0.5;
|
||||
cursor: pointer;
|
||||
transition: opacity 200ms ease-in;
|
||||
text-transform: uppercase;
|
||||
|
||||
&_sub {
|
||||
display: grid;
|
||||
grid-template-columns: auto 14px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&_active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
svg {
|
||||
transform: rotate(0deg);
|
||||
transition: transform 200ms ease-in;
|
||||
}
|
||||
|
||||
&_open {
|
||||
svg {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
&-submenu {
|
||||
display: grid;
|
||||
white-space: nowrap;
|
||||
padding: $padding-small;
|
||||
color: $color-white;
|
||||
border-radius: 2px;
|
||||
opacity: 1;
|
||||
transform-origin: top center;
|
||||
font-size: $font-size-small;
|
||||
font-weight: bold;
|
||||
|
||||
&-item {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,17 +6,18 @@
|
|||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: $padding-small $padding-medium;
|
||||
gap: $padding-large;
|
||||
gap: 0 $padding-large;
|
||||
z-index: 99;
|
||||
|
||||
&_app {
|
||||
padding: $padding-small 0;
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
gap: $padding-global;
|
||||
|
||||
.vm-tabs {
|
||||
gap: 0;
|
||||
&_dark {
|
||||
.vm-header-button,
|
||||
button:before,
|
||||
button {
|
||||
background-color: $color-background-block;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,7 +46,7 @@
|
|||
|
||||
&-nav {
|
||||
font-size: $font-size-small;
|
||||
font-weight: 600;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&__settings {
|
||||
|
|
|
@ -14,7 +14,7 @@ const Layout: FC = () => {
|
|||
|
||||
const { pathname } = useLocation();
|
||||
useEffect(() => {
|
||||
const defaultTitle = "VM UI";
|
||||
const defaultTitle = "vmui";
|
||||
const routeTitle = routerOptions[pathname]?.title;
|
||||
document.title = routeTitle ? `${routeTitle} - ${defaultTitle}` : defaultTitle;
|
||||
}, [pathname]);
|
||||
|
|
|
@ -3,6 +3,7 @@ import { ReactNode } from "react";
|
|||
import classNames from "classnames";
|
||||
import { ErrorIcon, InfoIcon, SuccessIcon, WarningIcon } from "../Icons";
|
||||
import "./style.scss";
|
||||
import { useAppState } from "../../../state/common/StateContext";
|
||||
|
||||
interface AlertProps {
|
||||
variant?: "success" | "error" | "info" | "warning"
|
||||
|
@ -19,12 +20,14 @@ const icons = {
|
|||
const Alert: FC<AlertProps> = ({
|
||||
variant,
|
||||
children }) => {
|
||||
const { darkTheme } = useAppState();
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames({
|
||||
"vm-alert": true,
|
||||
[`vm-alert_${variant}`]: variant
|
||||
[`vm-alert_${variant}`]: variant,
|
||||
"vm-alert_dark": darkTheme
|
||||
})}
|
||||
>
|
||||
<div className="vm-alert__icon">{icons[variant || "info"]}</div>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
border-radius: $border-radius-medium;
|
||||
box-shadow: $box-shadow;
|
||||
font-size: $font-size-medium;
|
||||
font-weight: 500;
|
||||
font-weight: normal;
|
||||
color: $color-text;
|
||||
line-height: 20px;
|
||||
|
||||
|
@ -75,4 +75,14 @@
|
|||
background-color: $color-warning;
|
||||
}
|
||||
}
|
||||
|
||||
&_dark {
|
||||
&:after {
|
||||
opacity: 0.1;
|
||||
}
|
||||
}
|
||||
|
||||
&_dark &__content {
|
||||
filter: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ $button-radius: 6px;
|
|||
padding: 6px 14px;
|
||||
font-size: $font-size-small;
|
||||
line-height: 15px;
|
||||
font-weight: 500;
|
||||
font-weight: normal;
|
||||
min-height: 31px;
|
||||
border-radius: $button-radius;
|
||||
color: $color-white;
|
||||
|
@ -21,7 +21,7 @@ $button-radius: 6px;
|
|||
white-space: nowrap;
|
||||
|
||||
&:hover:after {
|
||||
background-color: rgba($color-black, 0.05);
|
||||
background-color: $color-hover-black;
|
||||
}
|
||||
|
||||
&:before,
|
||||
|
|
|
@ -104,7 +104,7 @@
|
|||
transition: color 200ms ease, background-color 300ms ease-in-out;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba($color-black, 0.05);
|
||||
background-color: $color-hover-black;
|
||||
}
|
||||
|
||||
&_empty {
|
||||
|
@ -144,7 +144,7 @@
|
|||
transition: color 200ms ease, background-color 300ms ease-in-out;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba($color-black, 0.05);
|
||||
background-color: $color-hover-black;
|
||||
}
|
||||
|
||||
&_selected {
|
||||
|
@ -270,6 +270,10 @@
|
|||
justify-content: space-between;
|
||||
margin-top: $padding-global;
|
||||
|
||||
&_dark &__input {
|
||||
border-color: $color-text-disabled;
|
||||
}
|
||||
|
||||
span {
|
||||
margin: 0 $padding-small;
|
||||
}
|
||||
|
@ -277,11 +281,13 @@
|
|||
&__input {
|
||||
width: 64px;
|
||||
height: 32px;
|
||||
border: 1px solid $color-alto;
|
||||
border: $border-divider;
|
||||
border-radius: $border-radius-small;
|
||||
font-size: $font-size-medium;
|
||||
padding: 2px $padding-small;
|
||||
text-align: center;
|
||||
background-color: transparent;
|
||||
color: $color-text;
|
||||
|
||||
&:focus {
|
||||
border-color: $color-primary;
|
||||
|
|
|
@ -2,6 +2,7 @@ import React, { FC, useEffect, useMemo, useRef, useState } from "preact/compat";
|
|||
import { Dayjs } from "dayjs";
|
||||
import { FormEvent, FocusEvent } from "react";
|
||||
import classNames from "classnames";
|
||||
import { useAppState } from "../../../../state/common/StateContext";
|
||||
|
||||
interface CalendarTimepickerProps {
|
||||
selectDate: Dayjs
|
||||
|
@ -13,6 +14,7 @@ enum TimeUnits { hour, minutes, seconds }
|
|||
|
||||
|
||||
const TimePicker: FC<CalendarTimepickerProps>= ({ selectDate, onChangeTime, onClose }) => {
|
||||
const { darkTheme } = useAppState();
|
||||
|
||||
const [activeField, setActiveField] = useState<TimeUnits>(TimeUnits.hour);
|
||||
const [hours, setHours] = useState(selectDate.format("HH"));
|
||||
|
@ -154,7 +156,12 @@ const TimePicker: FC<CalendarTimepickerProps>= ({ selectDate, onChangeTime, onCl
|
|||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="vm-calendar-time-picker-fields">
|
||||
<div
|
||||
className={classNames({
|
||||
"vm-calendar-time-picker-fields": true,
|
||||
"vm-calendar-time-picker-fields_dark": darkTheme
|
||||
})}
|
||||
>
|
||||
<input
|
||||
className="vm-calendar-time-picker-fields__input"
|
||||
value={hours}
|
||||
|
|
|
@ -344,3 +344,48 @@ export const TimelineIcon = () => (
|
|||
></path>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const WikiIcon = () => (
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M21 5C19.89 4.65 18.67 4.5 17.5 4.5C15.55 4.5 13.45 4.9 12 6C10.55 4.9 8.45 4.5 6.5 4.5C5.33 4.5 4.11 4.65 3 5C2.25 5.25 1.6 5.55 1 6V20.6C1 20.85 1.25 21.1 1.5 21.1C1.6 21.1 1.65 21.1 1.75 21.05C3.15 20.3 4.85 20 6.5 20C8.2 20 10.65 20.65 12 21.5C13.35 20.65 15.8 20 17.5 20C19.15 20 20.85 20.3 22.25 21.05C22.35 21.1 22.4 21.1 22.5 21.1C22.75 21.1 23 20.85 23 20.6V6C22.4 5.55 21.75 5.25 21 5ZM21 18.5C19.9 18.15 18.7 18 17.5 18C15.8 18 13.35 18.65 12 19.5C10.65 18.65 8.2 18 6.5 18C5.3 18 4.1 18.15 3 18.5V7C4.1 6.65 5.3 6.5 6.5 6.5C8.2 6.5 10.65 7.15 12 8C13.35 7.15 15.8 6.5 17.5 6.5C18.7 6.5 19.9 6.65 21 7V18.5Z"
|
||||
/>
|
||||
<path
|
||||
d="M17.5 10.5C18.38 10.5 19.23 10.59 20 10.76V9.24C19.21 9.09 18.36 9 17.5 9C15.8 9 14.26 9.29 13 9.83V11.49C14.13 10.85 15.7 10.5 17.5 10.5ZM13 12.49V14.15C14.13 13.51 15.7 13.16 17.5 13.16C18.38 13.16 19.23 13.25 20 13.42V11.9C19.21 11.75 18.36 11.66 17.5 11.66C15.8 11.66 14.26 11.96 13 12.49ZM17.5 14.33C15.8 14.33 14.26 14.62 13 15.16V16.82C14.13 16.18 15.7 15.83 17.5 15.83C18.38 15.83 19.23 15.92 20 16.09V14.57C19.21 14.41 18.36 14.33 17.5 14.33Z"
|
||||
/>
|
||||
<path
|
||||
d="M6.5 10.5C5.62 10.5 4.77 10.59 4 10.76V9.24C4.79 9.09 5.64 9 6.5 9C8.2 9 9.74 9.29 11 9.83V11.49C9.87 10.85 8.3 10.5 6.5 10.5ZM11 12.49V14.15C9.87 13.51 8.3 13.16 6.5 13.16C5.62 13.16 4.77 13.25 4 13.42V11.9C4.79 11.75 5.64 11.66 6.5 11.66C8.2 11.66 9.74 11.96 11 12.49ZM6.5 14.33C8.2 14.33 9.74 14.62 11 15.16V16.82C9.87 16.18 8.3 15.83 6.5 15.83C5.62 15.83 4.77 15.92 4 16.09V14.57C4.79 14.41 5.64 14.33 6.5 14.33Z"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
);
|
||||
|
||||
export const IssueIcon = () => (
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
d="M12 2C6.49 2 2 6.49 2 12s4.49 10 10 10 10-4.49 10-10S17.51 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm3-8c0 1.66-1.34 3-3 3s-3-1.34-3-3 1.34-3 3-3 3 1.34 3 3z"
|
||||
></path>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const QuestionIcon = () => (
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M12 2C6.48 2 2 6.48 2 12C2 17.52 6.48 22 12 22C17.52 22 22 17.52 22 12C22 6.48 17.52 2 12 2ZM12 6C9.79 6 8 7.79 8 10H10C10 8.9 10.9 8 12 8C13.1 8 14 8.9 14 10C14 10.8792 13.4202 11.3236 12.7704 11.8217C11.9421 12.4566 11 13.1787 11 15H13C13 13.9046 13.711 13.2833 14.4408 12.6455C15.21 11.9733 16 11.2829 16 10C16 7.79 14.21 6 12 6ZM13 16V18H11V16H13Z"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
);
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
&-track {
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
background-color: rgba($color-black, 0.05);
|
||||
background-color: $color-hover-black;
|
||||
border-radius: $border-radius-small;
|
||||
|
||||
&__thumb {
|
||||
|
|
|
@ -8,7 +8,7 @@ $padding-modal: 22px;
|
|||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 100;
|
||||
z-index: 999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
@ -16,9 +16,11 @@ $padding-modal: 22px;
|
|||
|
||||
&-content {
|
||||
padding: $padding-modal;
|
||||
background: $color-white;
|
||||
background: $color-background-block;
|
||||
box-shadow: 0 0 24px rgba($color-black, 0.07);
|
||||
border-radius: $border-radius-small;
|
||||
max-height: 90vh;
|
||||
overflow: auto;
|
||||
|
||||
&-header {
|
||||
display: grid;
|
||||
|
|
|
@ -3,6 +3,7 @@ import classNames from "classnames";
|
|||
import { ArrowDropDownIcon, CloseIcon } from "../Icons";
|
||||
import { FormEvent, MouseEvent } from "react";
|
||||
import Autocomplete from "../Autocomplete/Autocomplete";
|
||||
import { useAppState } from "../../../state/common/StateContext";
|
||||
import "./style.scss";
|
||||
|
||||
interface SelectProps {
|
||||
|
@ -26,6 +27,7 @@ const Select: FC<SelectProps> = ({
|
|||
autofocus,
|
||||
onChange
|
||||
}) => {
|
||||
const { darkTheme } = useAppState();
|
||||
|
||||
const [search, setSearch] = useState("");
|
||||
const autocompleteAnchorEl = useRef<HTMLDivElement>(null);
|
||||
|
@ -106,7 +108,12 @@ const Select: FC<SelectProps> = ({
|
|||
}, []);
|
||||
|
||||
return (
|
||||
<div className="vm-select">
|
||||
<div
|
||||
className={classNames({
|
||||
"vm-select": true,
|
||||
"vm-select_dark": darkTheme
|
||||
})}
|
||||
>
|
||||
<div
|
||||
className="vm-select-input"
|
||||
onClick={handleToggleList}
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba($color-black, 0.06);
|
||||
background-color: $color-hover-black;
|
||||
padding: 2px 2px 2px 6px;
|
||||
border-radius: $border-radius-small;
|
||||
font-size: $font-size;
|
||||
|
@ -60,6 +60,8 @@
|
|||
z-index: 2;
|
||||
min-width: 100px;
|
||||
flex-grow: 1;
|
||||
background-color: transparent;
|
||||
color: $color-text;
|
||||
|
||||
&:placeholder-shown {
|
||||
width: auto;
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
line-height: 2;
|
||||
color: $color-text;
|
||||
text-align: center;
|
||||
background-color: $color-white;
|
||||
background-color: $color-background-body;
|
||||
background-repeat: repeat-x;
|
||||
border: $border-divider;
|
||||
border-radius: 4px;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import React, { CSSProperties, FC } from "preact/compat";
|
||||
import "./style.scss";
|
||||
import classNames from "classnames";
|
||||
import { getFromStorage } from "../../../utils/storage";
|
||||
|
||||
interface SpinnerProps {
|
||||
containerStyles?: CSSProperties;
|
||||
|
@ -8,7 +10,10 @@ interface SpinnerProps {
|
|||
|
||||
const Spinner: FC<SpinnerProps> = ({ containerStyles = {}, message }) => (
|
||||
<div
|
||||
className="vm-spinner"
|
||||
className={classNames({
|
||||
"vm-spinner": true,
|
||||
"vm-spinner_dark": getFromStorage("DARK_THEME")
|
||||
})}
|
||||
style={containerStyles && {}}
|
||||
>
|
||||
<div className="half-circle-spinner">
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
z-index: 99;
|
||||
animation: vm-fade 2s cubic-bezier(0.280, 0.840, 0.420, 1.1);
|
||||
|
||||
&_dark {
|
||||
background-color: rgba($color-black, 0.2);
|
||||
}
|
||||
|
||||
&__message {
|
||||
margin-top: $padding-medium;
|
||||
white-space: pre-line;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React, { FC, KeyboardEvent, useEffect, useRef, HTMLInputTypeAttribute, ReactNode } from "react";
|
||||
import classNames from "classnames";
|
||||
import { useMemo } from "preact/compat";
|
||||
import { useAppState } from "../../../state/common/StateContext";
|
||||
import "./style.scss";
|
||||
|
||||
interface TextFieldProps {
|
||||
|
@ -38,6 +39,7 @@ const TextField: FC<TextFieldProps> = ({
|
|||
onFocus,
|
||||
onBlur
|
||||
}) => {
|
||||
const { darkTheme } = useAppState();
|
||||
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
@ -81,6 +83,7 @@ const TextField: FC<TextFieldProps> = ({
|
|||
className={classNames({
|
||||
"vm-text-field": true,
|
||||
"vm-text-field_textarea": type === "textarea",
|
||||
"vm-text-field_dark": darkTheme
|
||||
})}
|
||||
data-replicated-value={value}
|
||||
>
|
||||
|
|
|
@ -67,6 +67,8 @@
|
|||
min-height: 34px;
|
||||
resize: none;
|
||||
overflow: hidden;
|
||||
background-color: transparent;
|
||||
color: $color-text;
|
||||
|
||||
&:focus {
|
||||
border: 1px solid $color-primary;
|
||||
|
|
|
@ -2,6 +2,8 @@ import { FC, useEffect } from "preact/compat";
|
|||
import { getContrastColor } from "../../../utils/color";
|
||||
import { getCssVariable, setCssVariable } from "../../../utils/theme";
|
||||
import { AppParams, getAppModeParams } from "../../../utils/app-mode";
|
||||
import { getFromStorage } from "../../../utils/storage";
|
||||
import { darkPalette, lightPalette } from "../../../constants/palette";
|
||||
|
||||
interface StyleVariablesProps {
|
||||
setLoadingTheme: (val: boolean) => void
|
||||
|
@ -27,13 +29,6 @@ export const ThemeProvider: FC<StyleVariablesProps> = ({ setLoadingTheme }) => {
|
|||
setCssVariable("scrollbar-height", `${innerHeight - clientHeight}px`);
|
||||
};
|
||||
|
||||
const setAppModePalette = () => {
|
||||
colorVariables.forEach(variable => {
|
||||
const colorFromAppMode = palette[variable as keyof AppParams["palette"]];
|
||||
if (colorFromAppMode) setCssVariable(`color-${variable}`, colorFromAppMode);
|
||||
});
|
||||
};
|
||||
|
||||
const setContrastText = () => {
|
||||
colorVariables.forEach(variable => {
|
||||
const color = getCssVariable(`color-${variable}`);
|
||||
|
@ -42,11 +37,34 @@ export const ThemeProvider: FC<StyleVariablesProps> = ({ setLoadingTheme }) => {
|
|||
});
|
||||
};
|
||||
|
||||
const setAppModePalette = () => {
|
||||
colorVariables.forEach(variable => {
|
||||
const colorFromAppMode = palette[variable as keyof AppParams["palette"]];
|
||||
if (colorFromAppMode) setCssVariable(`color-${variable}`, colorFromAppMode);
|
||||
});
|
||||
|
||||
setContrastText();
|
||||
};
|
||||
|
||||
const setTheme = () => {
|
||||
const darkTheme = getFromStorage("DARK_THEME");
|
||||
const palette = darkTheme ? darkPalette : lightPalette;
|
||||
Object.entries(palette).forEach(([variable, value]) => {
|
||||
setCssVariable(variable, value);
|
||||
});
|
||||
setContrastText();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setAppModePalette();
|
||||
setScrollbarSize();
|
||||
setContrastText();
|
||||
setTheme();
|
||||
setLoadingTheme(false);
|
||||
|
||||
window.addEventListener("storage", setTheme);
|
||||
return () => {
|
||||
window.removeEventListener("storage", setTheme);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
|
|
|
@ -4,6 +4,7 @@ import Trace from "../Trace";
|
|||
import { ArrowDownIcon } from "../../Main/Icons";
|
||||
import "./style.scss";
|
||||
import classNames from "classnames";
|
||||
import { useAppState } from "../../../state/common/StateContext";
|
||||
|
||||
interface RecursiveProps {
|
||||
trace: Trace;
|
||||
|
@ -15,6 +16,7 @@ interface OpenLevels {
|
|||
}
|
||||
|
||||
const NestedNav: FC<RecursiveProps> = ({ trace, totalMsec }) => {
|
||||
const { darkTheme } = useAppState();
|
||||
const [openLevels, setOpenLevels] = useState({} as OpenLevels);
|
||||
|
||||
const handleListClick = (level: number) => () => {
|
||||
|
@ -26,7 +28,12 @@ const NestedNav: FC<RecursiveProps> = ({ trace, totalMsec }) => {
|
|||
const progress = trace.duration / totalMsec * 100;
|
||||
|
||||
return (
|
||||
<div className="vm-nested-nav">
|
||||
<div
|
||||
className={classNames({
|
||||
"vm-nested-nav": true,
|
||||
"vm-nested-nav_dark": darkTheme,
|
||||
})}
|
||||
>
|
||||
<div
|
||||
className="vm-nested-nav-header"
|
||||
onClick={handleListClick(trace.idValue)}
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
border-radius: $border-radius-small;
|
||||
background-color: rgba($color-tropical-blue, 0.4);
|
||||
|
||||
&_dark {
|
||||
background-color: rgba($color-black, 0.1);
|
||||
}
|
||||
|
||||
&-header {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
|
@ -15,7 +19,7 @@
|
|||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba($color-black, 0.06);
|
||||
background-color: $color-hover-black;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
|
|
|
@ -14,5 +14,6 @@
|
|||
transform: translateY(-32px);
|
||||
font-size: $font-size;
|
||||
line-height: 1.4;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
}
|
||||
|
|
37
app/vmui/packages/vmui/src/constants/palette.ts
Normal file
37
app/vmui/packages/vmui/src/constants/palette.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
export const darkPalette = {
|
||||
"color-primary": "#589DF6",
|
||||
"color-secondary": "#316eca",
|
||||
"color-error": "#e5534b",
|
||||
"color-warning": "#c69026",
|
||||
"color-info": "#539bf5",
|
||||
"color-success": "#57ab5a",
|
||||
"color-background-body": "#22272e",
|
||||
"color-background-block": "#2d333b",
|
||||
"color-background-tooltip": "rgba(22, 22, 22, 0.6)",
|
||||
"color-text": "#cdd9e5",
|
||||
"color-text-secondary": "#768390",
|
||||
"color-text-disabled": "#636e7b",
|
||||
"box-shadow": "rgba(0, 0, 0, 0.16) 1px 2px 6px",
|
||||
"box-shadow-popper": "rgba(0, 0, 0, 0.2) 0px 2px 8px 0px",
|
||||
"border-divider": "1px solid rgba(99, 110, 123, 0.5)",
|
||||
"color-hover-black": "rgba(0, 0, 0, 0.12)"
|
||||
};
|
||||
|
||||
export const lightPalette = {
|
||||
"color-primary": "#3F51B5",
|
||||
"color-secondary": "#E91E63",
|
||||
"color-error": "#FD080E",
|
||||
"color-warning": "#FF8308",
|
||||
"color-info": "#03A9F4",
|
||||
"color-success": "#4CAF50",
|
||||
"color-background-body": "#FEFEFF",
|
||||
"color-background-block": "#FFFFFF",
|
||||
"color-background-tooltip": "rgba(97,97,97, 0.92)",
|
||||
"color-text": "#110f0f",
|
||||
"color-text-secondary": "#706F6F",
|
||||
"color-text-disabled": "#A09F9F",
|
||||
"box-shadow": "rgba(0, 0, 0, 0.08) 1px 2px 6px",
|
||||
"box-shadow-popper": "rgba(0, 0, 0, 0.1) 0px 2px 8px 0px",
|
||||
"border-divider": "1px solid rgba(0, 0, 0, 0.15)",
|
||||
"color-hover-black": "rgba(0, 0, 0, 0.06)"
|
||||
};
|
430
app/vmui/packages/vmui/src/constants/timezones.ts
Normal file
430
app/vmui/packages/vmui/src/constants/timezones.ts
Normal file
|
@ -0,0 +1,430 @@
|
|||
export default [
|
||||
"Africa/Abidjan",
|
||||
"Africa/Accra",
|
||||
"Africa/Addis_Ababa",
|
||||
"Africa/Algiers",
|
||||
"Africa/Asmera",
|
||||
"Africa/Bamako",
|
||||
"Africa/Bangui",
|
||||
"Africa/Banjul",
|
||||
"Africa/Bissau",
|
||||
"Africa/Blantyre",
|
||||
"Africa/Brazzaville",
|
||||
"Africa/Bujumbura",
|
||||
"Africa/Cairo",
|
||||
"Africa/Casablanca",
|
||||
"Africa/Ceuta",
|
||||
"Africa/Conakry",
|
||||
"Africa/Dakar",
|
||||
"Africa/Dar_es_Salaam",
|
||||
"Africa/Djibouti",
|
||||
"Africa/Douala",
|
||||
"Africa/El_Aaiun",
|
||||
"Africa/Freetown",
|
||||
"Africa/Gaborone",
|
||||
"Africa/Harare",
|
||||
"Africa/Johannesburg",
|
||||
"Africa/Juba",
|
||||
"Africa/Kampala",
|
||||
"Africa/Khartoum",
|
||||
"Africa/Kigali",
|
||||
"Africa/Kinshasa",
|
||||
"Africa/Lagos",
|
||||
"Africa/Libreville",
|
||||
"Africa/Lome",
|
||||
"Africa/Luanda",
|
||||
"Africa/Lubumbashi",
|
||||
"Africa/Lusaka",
|
||||
"Africa/Malabo",
|
||||
"Africa/Maputo",
|
||||
"Africa/Maseru",
|
||||
"Africa/Mbabane",
|
||||
"Africa/Mogadishu",
|
||||
"Africa/Monrovia",
|
||||
"Africa/Nairobi",
|
||||
"Africa/Ndjamena",
|
||||
"Africa/Niamey",
|
||||
"Africa/Nouakchott",
|
||||
"Africa/Ouagadougou",
|
||||
"Africa/Porto-Novo",
|
||||
"Africa/Sao_Tome",
|
||||
"Africa/Tripoli",
|
||||
"Africa/Tunis",
|
||||
"Africa/Windhoek",
|
||||
"America/Adak",
|
||||
"America/Anchorage",
|
||||
"America/Anguilla",
|
||||
"America/Antigua",
|
||||
"America/Araguaina",
|
||||
"America/Argentina/La_Rioja",
|
||||
"America/Argentina/Rio_Gallegos",
|
||||
"America/Argentina/Salta",
|
||||
"America/Argentina/San_Juan",
|
||||
"America/Argentina/San_Luis",
|
||||
"America/Argentina/Tucuman",
|
||||
"America/Argentina/Ushuaia",
|
||||
"America/Aruba",
|
||||
"America/Asuncion",
|
||||
"America/Bahia",
|
||||
"America/Bahia_Banderas",
|
||||
"America/Barbados",
|
||||
"America/Belem",
|
||||
"America/Belize",
|
||||
"America/Blanc-Sablon",
|
||||
"America/Boa_Vista",
|
||||
"America/Bogota",
|
||||
"America/Boise",
|
||||
"America/Buenos_Aires",
|
||||
"America/Cambridge_Bay",
|
||||
"America/Campo_Grande",
|
||||
"America/Cancun",
|
||||
"America/Caracas",
|
||||
"America/Catamarca",
|
||||
"America/Cayenne",
|
||||
"America/Cayman",
|
||||
"America/Chicago",
|
||||
"America/Chihuahua",
|
||||
"America/Coral_Harbour",
|
||||
"America/Cordoba",
|
||||
"America/Costa_Rica",
|
||||
"America/Creston",
|
||||
"America/Cuiaba",
|
||||
"America/Curacao",
|
||||
"America/Danmarkshavn",
|
||||
"America/Dawson",
|
||||
"America/Dawson_Creek",
|
||||
"America/Denver",
|
||||
"America/Detroit",
|
||||
"America/Dominica",
|
||||
"America/Edmonton",
|
||||
"America/Eirunepe",
|
||||
"America/El_Salvador",
|
||||
"America/Fort_Nelson",
|
||||
"America/Fortaleza",
|
||||
"America/Glace_Bay",
|
||||
"America/Godthab",
|
||||
"America/Goose_Bay",
|
||||
"America/Grand_Turk",
|
||||
"America/Grenada",
|
||||
"America/Guadeloupe",
|
||||
"America/Guatemala",
|
||||
"America/Guayaquil",
|
||||
"America/Guyana",
|
||||
"America/Halifax",
|
||||
"America/Havana",
|
||||
"America/Hermosillo",
|
||||
"America/Indiana/Knox",
|
||||
"America/Indiana/Marengo",
|
||||
"America/Indiana/Petersburg",
|
||||
"America/Indiana/Tell_City",
|
||||
"America/Indiana/Vevay",
|
||||
"America/Indiana/Vincennes",
|
||||
"America/Indiana/Winamac",
|
||||
"America/Indianapolis",
|
||||
"America/Inuvik",
|
||||
"America/Iqaluit",
|
||||
"America/Jamaica",
|
||||
"America/Jujuy",
|
||||
"America/Juneau",
|
||||
"America/Kentucky/Monticello",
|
||||
"America/Kralendijk",
|
||||
"America/La_Paz",
|
||||
"America/Lima",
|
||||
"America/Los_Angeles",
|
||||
"America/Louisville",
|
||||
"America/Lower_Princes",
|
||||
"America/Maceio",
|
||||
"America/Managua",
|
||||
"America/Manaus",
|
||||
"America/Marigot",
|
||||
"America/Martinique",
|
||||
"America/Matamoros",
|
||||
"America/Mazatlan",
|
||||
"America/Mendoza",
|
||||
"America/Menominee",
|
||||
"America/Merida",
|
||||
"America/Metlakatla",
|
||||
"America/Mexico_City",
|
||||
"America/Miquelon",
|
||||
"America/Moncton",
|
||||
"America/Monterrey",
|
||||
"America/Montevideo",
|
||||
"America/Montreal",
|
||||
"America/Montserrat",
|
||||
"America/Nassau",
|
||||
"America/New_York",
|
||||
"America/Nipigon",
|
||||
"America/Nome",
|
||||
"America/Noronha",
|
||||
"America/North_Dakota/Beulah",
|
||||
"America/North_Dakota/Center",
|
||||
"America/North_Dakota/New_Salem",
|
||||
"America/Ojinaga",
|
||||
"America/Panama",
|
||||
"America/Pangnirtung",
|
||||
"America/Paramaribo",
|
||||
"America/Phoenix",
|
||||
"America/Port-au-Prince",
|
||||
"America/Port_of_Spain",
|
||||
"America/Porto_Velho",
|
||||
"America/Puerto_Rico",
|
||||
"America/Punta_Arenas",
|
||||
"America/Rainy_River",
|
||||
"America/Rankin_Inlet",
|
||||
"America/Recife",
|
||||
"America/Regina",
|
||||
"America/Resolute",
|
||||
"America/Rio_Branco",
|
||||
"America/Santa_Isabel",
|
||||
"America/Santarem",
|
||||
"America/Santiago",
|
||||
"America/Santo_Domingo",
|
||||
"America/Sao_Paulo",
|
||||
"America/Scoresbysund",
|
||||
"America/Sitka",
|
||||
"America/St_Barthelemy",
|
||||
"America/St_Johns",
|
||||
"America/St_Kitts",
|
||||
"America/St_Lucia",
|
||||
"America/St_Thomas",
|
||||
"America/St_Vincent",
|
||||
"America/Swift_Current",
|
||||
"America/Tegucigalpa",
|
||||
"America/Thule",
|
||||
"America/Thunder_Bay",
|
||||
"America/Tijuana",
|
||||
"America/Toronto",
|
||||
"America/Tortola",
|
||||
"America/Vancouver",
|
||||
"America/Whitehorse",
|
||||
"America/Winnipeg",
|
||||
"America/Yakutat",
|
||||
"America/Yellowknife",
|
||||
"Antarctica/Casey",
|
||||
"Antarctica/Davis",
|
||||
"Antarctica/DumontDUrville",
|
||||
"Antarctica/Macquarie",
|
||||
"Antarctica/Mawson",
|
||||
"Antarctica/McMurdo",
|
||||
"Antarctica/Palmer",
|
||||
"Antarctica/Rothera",
|
||||
"Antarctica/Syowa",
|
||||
"Antarctica/Troll",
|
||||
"Antarctica/Vostok",
|
||||
"Arctic/Longyearbyen",
|
||||
"Asia/Aden",
|
||||
"Asia/Almaty",
|
||||
"Asia/Amman",
|
||||
"Asia/Anadyr",
|
||||
"Asia/Aqtau",
|
||||
"Asia/Aqtobe",
|
||||
"Asia/Ashgabat",
|
||||
"Asia/Atyrau",
|
||||
"Asia/Baghdad",
|
||||
"Asia/Bahrain",
|
||||
"Asia/Baku",
|
||||
"Asia/Bangkok",
|
||||
"Asia/Barnaul",
|
||||
"Asia/Beirut",
|
||||
"Asia/Bishkek",
|
||||
"Asia/Brunei",
|
||||
"Asia/Calcutta",
|
||||
"Asia/Chita",
|
||||
"Asia/Choibalsan",
|
||||
"Asia/Colombo",
|
||||
"Asia/Damascus",
|
||||
"Asia/Dhaka",
|
||||
"Asia/Dili",
|
||||
"Asia/Dubai",
|
||||
"Asia/Dushanbe",
|
||||
"Asia/Famagusta",
|
||||
"Asia/Gaza",
|
||||
"Asia/Hebron",
|
||||
"Asia/Hong_Kong",
|
||||
"Asia/Hovd",
|
||||
"Asia/Irkutsk",
|
||||
"Asia/Jakarta",
|
||||
"Asia/Jayapura",
|
||||
"Asia/Jerusalem",
|
||||
"Asia/Kabul",
|
||||
"Asia/Kamchatka",
|
||||
"Asia/Karachi",
|
||||
"Asia/Katmandu",
|
||||
"Asia/Khandyga",
|
||||
"Asia/Krasnoyarsk",
|
||||
"Asia/Kuala_Lumpur",
|
||||
"Asia/Kuching",
|
||||
"Asia/Kuwait",
|
||||
"Asia/Macau",
|
||||
"Asia/Magadan",
|
||||
"Asia/Makassar",
|
||||
"Asia/Manila",
|
||||
"Asia/Muscat",
|
||||
"Asia/Nicosia",
|
||||
"Asia/Novokuznetsk",
|
||||
"Asia/Novosibirsk",
|
||||
"Asia/Omsk",
|
||||
"Asia/Oral",
|
||||
"Asia/Phnom_Penh",
|
||||
"Asia/Pontianak",
|
||||
"Asia/Pyongyang",
|
||||
"Asia/Qatar",
|
||||
"Asia/Qostanay",
|
||||
"Asia/Qyzylorda",
|
||||
"Asia/Rangoon",
|
||||
"Asia/Riyadh",
|
||||
"Asia/Saigon",
|
||||
"Asia/Sakhalin",
|
||||
"Asia/Samarkand",
|
||||
"Asia/Seoul",
|
||||
"Asia/Shanghai",
|
||||
"Asia/Singapore",
|
||||
"Asia/Srednekolymsk",
|
||||
"Asia/Taipei",
|
||||
"Asia/Tashkent",
|
||||
"Asia/Tbilisi",
|
||||
"Asia/Tehran",
|
||||
"Asia/Thimphu",
|
||||
"Asia/Tokyo",
|
||||
"Asia/Tomsk",
|
||||
"Asia/Ulaanbaatar",
|
||||
"Asia/Urumqi",
|
||||
"Asia/Ust-Nera",
|
||||
"Asia/Vientiane",
|
||||
"Asia/Vladivostok",
|
||||
"Asia/Yakutsk",
|
||||
"Asia/Yekaterinburg",
|
||||
"Asia/Yerevan",
|
||||
"Atlantic/Azores",
|
||||
"Atlantic/Bermuda",
|
||||
"Atlantic/Canary",
|
||||
"Atlantic/Cape_Verde",
|
||||
"Atlantic/Faeroe",
|
||||
"Atlantic/Madeira",
|
||||
"Atlantic/Reykjavik",
|
||||
"Atlantic/South_Georgia",
|
||||
"Atlantic/St_Helena",
|
||||
"Atlantic/Stanley",
|
||||
"Australia/Adelaide",
|
||||
"Australia/Brisbane",
|
||||
"Australia/Broken_Hill",
|
||||
"Australia/Currie",
|
||||
"Australia/Darwin",
|
||||
"Australia/Eucla",
|
||||
"Australia/Hobart",
|
||||
"Australia/Lindeman",
|
||||
"Australia/Lord_Howe",
|
||||
"Australia/Melbourne",
|
||||
"Australia/Perth",
|
||||
"Australia/Sydney",
|
||||
"Europe/Amsterdam",
|
||||
"Europe/Andorra",
|
||||
"Europe/Astrakhan",
|
||||
"Europe/Athens",
|
||||
"Europe/Belgrade",
|
||||
"Europe/Berlin",
|
||||
"Europe/Bratislava",
|
||||
"Europe/Brussels",
|
||||
"Europe/Bucharest",
|
||||
"Europe/Budapest",
|
||||
"Europe/Busingen",
|
||||
"Europe/Chisinau",
|
||||
"Europe/Copenhagen",
|
||||
"Europe/Dublin",
|
||||
"Europe/Gibraltar",
|
||||
"Europe/Guernsey",
|
||||
"Europe/Helsinki",
|
||||
"Europe/Isle_of_Man",
|
||||
"Europe/Istanbul",
|
||||
"Europe/Jersey",
|
||||
"Europe/Kaliningrad",
|
||||
"Europe/Kiev",
|
||||
"Europe/Kirov",
|
||||
"Europe/Lisbon",
|
||||
"Europe/Ljubljana",
|
||||
"Europe/London",
|
||||
"Europe/Luxembourg",
|
||||
"Europe/Madrid",
|
||||
"Europe/Malta",
|
||||
"Europe/Mariehamn",
|
||||
"Europe/Minsk",
|
||||
"Europe/Monaco",
|
||||
"Europe/Moscow",
|
||||
"Europe/Oslo",
|
||||
"Europe/Paris",
|
||||
"Europe/Podgorica",
|
||||
"Europe/Prague",
|
||||
"Europe/Riga",
|
||||
"Europe/Rome",
|
||||
"Europe/Samara",
|
||||
"Europe/San_Marino",
|
||||
"Europe/Sarajevo",
|
||||
"Europe/Saratov",
|
||||
"Europe/Simferopol",
|
||||
"Europe/Skopje",
|
||||
"Europe/Sofia",
|
||||
"Europe/Stockholm",
|
||||
"Europe/Tallinn",
|
||||
"Europe/Tirane",
|
||||
"Europe/Ulyanovsk",
|
||||
"Europe/Uzhgorod",
|
||||
"Europe/Vaduz",
|
||||
"Europe/Vatican",
|
||||
"Europe/Vienna",
|
||||
"Europe/Vilnius",
|
||||
"Europe/Volgograd",
|
||||
"Europe/Warsaw",
|
||||
"Europe/Zagreb",
|
||||
"Europe/Zaporozhye",
|
||||
"Europe/Zurich",
|
||||
"Indian/Antananarivo",
|
||||
"Indian/Chagos",
|
||||
"Indian/Christmas",
|
||||
"Indian/Cocos",
|
||||
"Indian/Comoro",
|
||||
"Indian/Kerguelen",
|
||||
"Indian/Mahe",
|
||||
"Indian/Maldives",
|
||||
"Indian/Mauritius",
|
||||
"Indian/Mayotte",
|
||||
"Indian/Reunion",
|
||||
"Pacific/Apia",
|
||||
"Pacific/Auckland",
|
||||
"Pacific/Bougainville",
|
||||
"Pacific/Chatham",
|
||||
"Pacific/Easter",
|
||||
"Pacific/Efate",
|
||||
"Pacific/Enderbury",
|
||||
"Pacific/Fakaofo",
|
||||
"Pacific/Fiji",
|
||||
"Pacific/Funafuti",
|
||||
"Pacific/Galapagos",
|
||||
"Pacific/Gambier",
|
||||
"Pacific/Guadalcanal",
|
||||
"Pacific/Guam",
|
||||
"Pacific/Honolulu",
|
||||
"Pacific/Johnston",
|
||||
"Pacific/Kiritimati",
|
||||
"Pacific/Kosrae",
|
||||
"Pacific/Kwajalein",
|
||||
"Pacific/Majuro",
|
||||
"Pacific/Marquesas",
|
||||
"Pacific/Midway",
|
||||
"Pacific/Nauru",
|
||||
"Pacific/Niue",
|
||||
"Pacific/Norfolk",
|
||||
"Pacific/Noumea",
|
||||
"Pacific/Pago_Pago",
|
||||
"Pacific/Palau",
|
||||
"Pacific/Pitcairn",
|
||||
"Pacific/Ponape",
|
||||
"Pacific/Port_Moresby",
|
||||
"Pacific/Rarotonga",
|
||||
"Pacific/Saipan",
|
||||
"Pacific/Tahiti",
|
||||
"Pacific/Tarawa",
|
||||
"Pacific/Tongatapu",
|
||||
"Pacific/Truk",
|
||||
"Pacific/Wake",
|
||||
"Pacific/Wallis"
|
||||
];
|
|
@ -4,11 +4,12 @@ import { useFetchQueryOptions } from "../../../hooks/useFetchQueryOptions";
|
|||
import { ErrorTypes } from "../../../types";
|
||||
import { useQueryDispatch, useQueryState } from "../../../state/query/QueryStateContext";
|
||||
import Switch from "../../../components/Main/Switch/Switch";
|
||||
import { PlayIcon } from "../../../components/Main/Icons";
|
||||
import { PlayIcon, QuestionIcon } from "../../../components/Main/Icons";
|
||||
import Button from "../../../components/Main/Button/Button";
|
||||
import TextField from "../../../components/Main/TextField/TextField";
|
||||
import "./style.scss";
|
||||
import { useMemo } from "preact/compat";
|
||||
import Tooltip from "../../../components/Main/Tooltip/Tooltip";
|
||||
|
||||
export interface CardinalityConfiguratorProps {
|
||||
onSetHistory: (step: number) => void;
|
||||
|
@ -92,13 +93,13 @@ const CardinalityConfigurator: FC<CardinalityConfiguratorProps> = ({
|
|||
onChange={onFocusLabelChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="vm-cardinality-configurator-controls__item">
|
||||
<Switch
|
||||
label={"Autocomplete"}
|
||||
value={autocomplete}
|
||||
onChange={onChangeAutocomplete}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="vm-cardinality-configurator-bottom__autocomplete">
|
||||
<Switch
|
||||
label={"Autocomplete"}
|
||||
value={autocomplete}
|
||||
onChange={onChangeAutocomplete}
|
||||
/>
|
||||
</div>
|
||||
<div className="vm-cardinality-configurator-bottom">
|
||||
<div className="vm-cardinality-configurator-bottom__info">
|
||||
|
@ -106,6 +107,19 @@ const CardinalityConfigurator: FC<CardinalityConfiguratorProps> = ({
|
|||
at <b>{date}</b>{match && <span> for series selector <b>{match}</b></span>}.
|
||||
Show top {topN} entries per table.
|
||||
</div>
|
||||
<a
|
||||
className="vm-cardinality-configurator-bottom__docs"
|
||||
href="https://victoriametrics.com/blog/cardinality-explorer/"
|
||||
target="_blank"
|
||||
rel="help noreferrer"
|
||||
>
|
||||
<Tooltip title="Example of using">
|
||||
<Button
|
||||
variant="text"
|
||||
startIcon={<QuestionIcon/>}
|
||||
/>
|
||||
</Tooltip>
|
||||
</a>
|
||||
<Button
|
||||
startIcon={<PlayIcon/>}
|
||||
onClick={onRunQuery}
|
||||
|
|
|
@ -18,12 +18,18 @@
|
|||
|
||||
&-bottom {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
grid-template-columns: 1fr auto auto;
|
||||
align-items: flex-end;
|
||||
gap: $padding-medium;
|
||||
gap: $padding-small;
|
||||
|
||||
&__info {
|
||||
font-size: $font-size;
|
||||
}
|
||||
|
||||
&__docs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,6 +89,7 @@ const TableSettings: FC<TableSettingsProps> = ({ data, defaultColumns = [], onCh
|
|||
onClick={handleClose}
|
||||
startIcon={<CloseIcon/>}
|
||||
size="small"
|
||||
variant="text"
|
||||
/>
|
||||
</div>
|
||||
<div className="vm-table-settings-popper-list">
|
||||
|
|
|
@ -2,20 +2,25 @@
|
|||
|
||||
.vm-json-form {
|
||||
display: grid;
|
||||
grid-template-rows: auto calc(90vh - 78px - ($padding-medium*3)) auto;
|
||||
grid-template-rows: auto calc(70vh - 78px - ($padding-medium*3)) auto;
|
||||
gap: $padding-global;
|
||||
width: 70vw;
|
||||
max-width: 1000px;
|
||||
max-height: 900px;
|
||||
overflow: hidden;
|
||||
|
||||
&_one-field {
|
||||
grid-template-rows: calc(90vh - 78px - ($padding-medium*3)) auto;
|
||||
grid-template-rows: calc(70vh - 78px - ($padding-medium*3)) auto;
|
||||
}
|
||||
|
||||
.vm-text-field_textarea {
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-height: 900px;
|
||||
}
|
||||
|
||||
&-footer {
|
||||
|
|
|
@ -151,7 +151,7 @@ const TracePage: FC = () => {
|
|||
className="vm-link vm-link_colored"
|
||||
href="https://docs.victoriametrics.com/#query-tracing"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
rel="help noreferrer"
|
||||
>
|
||||
https://docs.victoriametrics.com/#query-tracing
|
||||
</a>
|
||||
|
|
|
@ -1,18 +1,22 @@
|
|||
import { getDefaultServer } from "../../utils/default-server-url";
|
||||
import { getQueryStringValue } from "../../utils/query-string";
|
||||
import { getFromStorage, saveToStorage } from "../../utils/storage";
|
||||
|
||||
export interface AppState {
|
||||
serverUrl: string;
|
||||
tenantId: number;
|
||||
darkTheme: boolean
|
||||
}
|
||||
|
||||
export type Action =
|
||||
| { type: "SET_SERVER", payload: string }
|
||||
| { type: "SET_TENANT_ID", payload: number }
|
||||
| { type: "SET_DARK_THEME", payload: boolean }
|
||||
|
||||
export const initialState: AppState = {
|
||||
serverUrl: getDefaultServer(),
|
||||
tenantId: Number(getQueryStringValue("g0.tenantID", 0)),
|
||||
darkTheme: !!getFromStorage("DARK_THEME")
|
||||
};
|
||||
|
||||
export function reducer(state: AppState, action: Action): AppState {
|
||||
|
@ -27,6 +31,12 @@ export function reducer(state: AppState, action: Action): AppState {
|
|||
...state,
|
||||
tenantId: action.payload
|
||||
};
|
||||
case "SET_DARK_THEME":
|
||||
saveToStorage("DARK_THEME", action.payload);
|
||||
return {
|
||||
...state,
|
||||
darkTheme: action.payload
|
||||
};
|
||||
default:
|
||||
throw new Error();
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
&:hover,
|
||||
&_active {
|
||||
background-color: rgba($color-black, 0.06);
|
||||
background-color: $color-hover-black;
|
||||
}
|
||||
|
||||
&_multiselect {
|
||||
|
|
|
@ -6,10 +6,11 @@
|
|||
gap: $padding-small;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background-color: $color-primary;
|
||||
background-color: $color-background-block;
|
||||
padding: $padding-small $padding-small $padding-small $padding-global;
|
||||
border-radius: $border-radius-small $border-radius-small 0 0;
|
||||
color: $color-white;
|
||||
color: $color-text;
|
||||
border-bottom: $border-divider;
|
||||
|
||||
&__title {
|
||||
font-weight: bold;
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
transition: background-color 200ms ease;
|
||||
|
||||
&:hover:not(&_header) {
|
||||
background-color: rgba($color-black, 0.05);
|
||||
background-color: $color-hover-black;
|
||||
}
|
||||
|
||||
&_header {
|
||||
|
@ -43,7 +43,7 @@
|
|||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba($color-black, 0.05);
|
||||
background-color: $color-hover-black;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,8 @@
|
|||
}
|
||||
|
||||
&_gray {
|
||||
color: rgba($color-black, 0.4);
|
||||
color: $color-text;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
&_right {
|
||||
|
|
|
@ -9,6 +9,7 @@ html, body, #root {
|
|||
background-repeat: no-repeat;
|
||||
background-attachment: fixed;
|
||||
margin: 0;
|
||||
background-color: $color-background-body;
|
||||
}
|
||||
|
||||
body {
|
||||
|
@ -54,3 +55,24 @@ input[type=number]::-webkit-outer-spin-button {
|
|||
svg {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Works on Firefox */
|
||||
* {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: $color-text-disabled $color-background-block;
|
||||
}
|
||||
|
||||
/* Works on Chrome, Edge, and Safari */
|
||||
*::-webkit-scrollbar {
|
||||
width: 12px;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-track {
|
||||
background: $color-background-block;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-thumb {
|
||||
background-color: $color-text-disabled;
|
||||
border-radius: 20px;
|
||||
border: 3px solid $color-background-block;
|
||||
}
|
||||
|
|
13
app/vmui/packages/vmui/src/styles/fonts.scss
Normal file
13
app/vmui/packages/vmui/src/styles/fonts.scss
Normal file
|
@ -0,0 +1,13 @@
|
|||
@font-face {
|
||||
font-family: 'Lato';
|
||||
src: url('../assets/fonts/Lato/Lato-Regular.ttf');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Lato';
|
||||
src: url('../assets/fonts/Lato/Lato-Bold.ttf');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
@forward "variables";
|
||||
@forward "core";
|
||||
@forward "reset";
|
||||
@forward "fonts";
|
||||
|
||||
@forward "./components/header-button";
|
||||
@forward "./components/list";
|
||||
|
@ -30,4 +31,17 @@
|
|||
/* backgrounds */
|
||||
--color-background-body: #FEFEFF;
|
||||
--color-background-block: #FFFFFF;
|
||||
--color-background-tooltip: rgba(97,97,97, 0.92);
|
||||
|
||||
/* text */
|
||||
--color-text: #110f0f;
|
||||
--color-text-secondary: #706F6F;
|
||||
--color-text-disabled: #A09F9F;
|
||||
|
||||
/* box-shadow */
|
||||
--box-shadow: rgba(0, 0, 0, 0.08) 1px 2px 6px;
|
||||
--box-shadow-popper: rgba(0, 0, 0, 0.1) 0px 2px 8px 0px;
|
||||
|
||||
--border-divider: 1px solid rgba(0, 0, 0, 0.15);
|
||||
--color-hover-black: rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
|
|
@ -13,14 +13,11 @@ $color-warning-text: var(--color-warning-text);
|
|||
$color-info-text: var(--color-info-text);
|
||||
$color-success-text: var(--color-success-text);
|
||||
|
||||
$color-text: #110f0f;
|
||||
$color-text-secondary: rgba($color-text, 0.6);
|
||||
$color-text-disabled: rgba($color-text, 0.4);
|
||||
$color-text: var(--color-text);
|
||||
$color-text-secondary: var(--color-text-secondary);
|
||||
$color-text-disabled: var(--color-text-disabled);
|
||||
|
||||
$color-black: #110f0f;
|
||||
$color-dove-gray: #616161;
|
||||
$color-silver: #C4C4C4;
|
||||
$color-alto: #D8D8D8;
|
||||
$color-white: #ffffff;
|
||||
|
||||
$color-dodger-blue: #1A90FF;
|
||||
|
@ -30,8 +27,7 @@ $color-tropical-blue: #C9E3F6;
|
|||
/************* background *************/
|
||||
$color-background-body: var(--color-background-body);
|
||||
$color-background-block: var(--color-background-block);
|
||||
$color-background-modal: rgba($color-black, 0.7);
|
||||
$color-background-tooltip: rgba($color-dove-gray, 0.92);
|
||||
$color-background-tooltip: var(--color-background-tooltip);
|
||||
|
||||
|
||||
/************* padding *************/
|
||||
|
@ -43,7 +39,7 @@ $padding-small: 8px;
|
|||
|
||||
/************* fonts *************/
|
||||
$font-family-global: 'Lato', sans-serif;
|
||||
$font-family-monospace: 'JetBrains Mono', monospace;
|
||||
$font-family-monospace: monospace;
|
||||
$font-size-large: 16px;
|
||||
$font-size-medium: 14px;
|
||||
$font-size: 12px;
|
||||
|
@ -51,7 +47,7 @@ $font-size-small: 10px;
|
|||
|
||||
|
||||
/************* border *************/
|
||||
$border-divider: 1px solid rgba($color-black, 0.15);
|
||||
$border-divider: var(--border-divider);
|
||||
|
||||
|
||||
/************* border-radius *************/
|
||||
|
@ -61,6 +57,7 @@ $border-radius-large: 16px;
|
|||
|
||||
|
||||
/************* box-shadows *************/
|
||||
$box-shadow: 1px 2px 12px rgba($color-black, 0.08);
|
||||
$box-shadow-bottom: rgba($color-black, 0.04) 0px 3px 5px;
|
||||
$box-shadow-popper: rgba($color-black, 0.1) 0px 2px 8px 0px;
|
||||
$box-shadow: var(--box-shadow);
|
||||
$box-shadow-popper: var(--box-shadow-popper);
|
||||
|
||||
$color-hover-black: var(--color-hover-black);
|
||||
|
|
|
@ -7,6 +7,7 @@ export type StorageKeys = "BASIC_AUTH_DATA"
|
|||
| "SERIES_LIMITS"
|
||||
| "TABLE_COMPACT"
|
||||
| "TIMEZONE"
|
||||
| "DARK_THEME"
|
||||
|
||||
export const saveToStorage = (key: StorageKeys, value: string | boolean | Record<string, unknown>): void => {
|
||||
if (value) {
|
||||
|
@ -15,6 +16,7 @@ export const saveToStorage = (key: StorageKeys, value: string | boolean | Record
|
|||
} else {
|
||||
removeFromStorage([key]);
|
||||
}
|
||||
window.dispatchEvent(new Event("storage"));
|
||||
};
|
||||
|
||||
// TODO: make this aware of data type that is stored
|
||||
|
|
|
@ -2,6 +2,7 @@ import { RelativeTimeOption, TimeParams, TimePeriod, Timezone } from "../types";
|
|||
import dayjs, { UnitTypeShort } from "dayjs";
|
||||
import { getQueryStringValue } from "./query-string";
|
||||
import { DATE_ISO_FORMAT } from "../constants/date";
|
||||
import timezones from "../constants/timezones";
|
||||
|
||||
const MAX_ITEMS_PER_CHART = window.innerWidth / 4;
|
||||
|
||||
|
@ -9,7 +10,8 @@ export const limitsDurations = { min: 1, max: 1.578e+11 }; // min: 1 ms, max: 5
|
|||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
export const supportedTimezones = Intl.supportedValuesOf("timeZone") as string[];
|
||||
const supportedValuesOf = Intl.supportedValuesOf;
|
||||
export const supportedTimezones = supportedValuesOf ? supportedValuesOf("timeZone") as string[] : timezones;
|
||||
|
||||
// The list of supported units could be the following -
|
||||
// https://prometheus.io/docs/prometheus/latest/querying/basics/#time-durations
|
||||
|
|
|
@ -4,6 +4,7 @@ import { getSecondsFromDuration, roundToMilliseconds } from "../time";
|
|||
import { AxisRange } from "../../state/graph/reducer";
|
||||
import { formatTicks, sizeAxis } from "./helpers";
|
||||
import { TimeParams } from "../../types";
|
||||
import { getCssVariable } from "../theme";
|
||||
|
||||
// see https://github.com/leeoniya/uPlot/tree/master/docs#axis--grid-opts
|
||||
const timeValues = [
|
||||
|
@ -22,10 +23,11 @@ export const getAxes = (series: Series[], unit?: string): Axis[] => Array.from(n
|
|||
scale: a,
|
||||
show: true,
|
||||
size: sizeAxis,
|
||||
stroke: getCssVariable("color-text"),
|
||||
font: "10px Arial",
|
||||
values: (u: uPlot, ticks: number[]) => formatTicks(u, ticks, unit)
|
||||
};
|
||||
if (!a) return { space: 80, values: timeValues };
|
||||
if (!a) return { space: 80, values: timeValues, stroke: getCssVariable("color-text") };
|
||||
if (!(Number(a) % 2)) return { ...axis, side: 1 };
|
||||
return axis;
|
||||
});
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* eslint-disable */
|
||||
import uPlot from "uplot";
|
||||
import {getCssVariable} from "../theme";
|
||||
|
||||
export const seriesBarsPlugin = (opts) => {
|
||||
let pxRatio;
|
||||
|
@ -88,7 +89,7 @@ export const seriesBarsPlugin = (opts) => {
|
|||
u.ctx.save();
|
||||
|
||||
u.ctx.font = font;
|
||||
u.ctx.fillStyle = "black";
|
||||
u.ctx.fillStyle = getCssVariable("color-text");
|
||||
|
||||
uPlot.orient(u, sidx, (
|
||||
series,
|
||||
|
|
1
deployment/k8s/helm/README.md
Normal file
1
deployment/k8s/helm/README.md
Normal file
|
@ -0,0 +1 @@
|
|||
### Helm chart has been moved to [helm-chart](https://github.com/VictoriaMetrics/helm-charts) repository.
|
|
@ -19,9 +19,11 @@ See also [case studies](https://docs.victoriametrics.com/CaseStudies.html).
|
|||
* [VictoriaMetrics vs. OpenTSDB](https://blg.robot-house.us/posts/tsdbs-grow/)
|
||||
* [Monitoring of multiple OpenShift clusters with VictoriaMetrics](https://medium.com/ibm-garage/monitoring-of-multiple-openshift-clusters-with-victoriametrics-d4f0979e2544)
|
||||
* [Fly's Prometheus Metrics](https://fly.io/blog/measuring-fly/)
|
||||
* [Ultra Monitoring with Victoria Metrics](https://dev.to/aws-builders/ultra-monitoring-with-victoria-metrics-1p2)
|
||||
* [Infrastructure monitoring with Prometheus at Zerodha](https://zerodha.tech/blog/infra-monitoring-at-zerodha/)
|
||||
* [Sismology: Iguana Solutions’ Monitoring System](https://medium.com/nerd-for-tech/sismology-iguana-solutions-monitoring-system-f46e4170447f)
|
||||
* [Prometheus High Availability and Fault Tolerance strategy, long term storage with VictoriaMetrics](https://medium.com/miro-engineering/prometheus-high-availability-and-fault-tolerance-strategy-long-term-storage-with-victoriametrics-82f6f3f0409e)
|
||||
* [Monitoring with Prometheus, Grafana, AlertManager and VictoriaMetrics](https://www.sensedia.com/post/monitoring-with-prometheus-grafana-alertmanager-and-victoriametrics)
|
||||
* [How we improved our Kubernetes monitoring at Smarkets, and how you could too](https://smarketshq.com/monitoring-kubernetes-clusters-41a4b24c19e3)
|
||||
* [Kubernetes and VictoriaMetrics in Mist v4.6](https://mist.io/blog/2021-11-26-kubernetes-and-victoriametrics-in-Mist-v4-6)
|
||||
* [Foiled by the Firewall: A Tale of Transition From Prometheus to VictoriaMetrics](https://www.percona.com/blog/2020/12/01/foiled-by-the-firewall-a-tale-of-transition-from-prometheus-to-victoriametrics/)
|
||||
|
@ -59,6 +61,9 @@ See also [case studies](https://docs.victoriametrics.com/CaseStudies.html).
|
|||
* [Prometheus, Grafana, and Kubernetes, Oh My!](https://www.groundcover.com/blog/prometheus-grafana-kubernetes)
|
||||
* [Explaining modern server monitoring stacks for self-hosting](https://dataswamp.org/~solene/2022-09-11-exploring-monitoring-stacks.html)
|
||||
* [How do We Keep Metrics for a Long Time in VictoriaMetrics](https://www.youtube.com/watch?v=SGZjY7xgDwE)
|
||||
* [Brewblox: InfluxDB to Victoria Metrics](https://www.brewblox.com/dev/decisions/20210718_victoria_metrics.html)
|
||||
* [VictoriaMetrics static scraper](https://blog.differentpla.net/blog/2022/10/16/victoria-metrics-static-scraper/)
|
||||
* [VictoriaMetrics and Open Cosmos boldly takes edge computing to the edge of space](https://www.iot-now.com/2022/07/19/122423-victoriametrics-and-open-cosmos-boldly-takes-edge-computing-to-the-edge-of-space/)
|
||||
|
||||
## Our articles
|
||||
|
||||
|
|
|
@ -15,6 +15,15 @@ The following tip changes can be tested by building VictoriaMetrics components f
|
|||
|
||||
## tip
|
||||
|
||||
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): add dark mode - it can be seleted via `settings` menu in the top right corner. See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/3704).
|
||||
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): improve visual appearance of the top menu. See [this feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3678).
|
||||
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): embed fonts into binary instead of loading them from external sources. This allows using `vmui` in full from isolated networks without access to Internet. Thanks to @ScottKevill for [the pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/3696).
|
||||
* FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent.html): reduce memory usage when sending stale markers for targets, which expose big number of metrics. See [this](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3668) and [this](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3675) issues.
|
||||
* FEATURE: add `-internStringMaxLen` command-line flag, which can be used for fine-tuning RAM vs CPU usage in certain workloads. For example, if the stored time series contain long labels, then it may be useful reducing the `-internStringMaxLen` in order to reduce memory usage at the cost of increased CPU usage. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3692).
|
||||
|
||||
* BUGFIX: [VictoriaMetrics cluster](https://docs.victoriametrics.com/Cluster-VictoriaMetrics.html): propagate all the timeout-related errors from `vmstorage` to `vmselect` when `vmstorage`. Previously some timeout errors weren't returned from `vmselect` to `vmstorage`. Instead, `vmstorage` could log the error and close the connection to `vmselect`, so `vmselect` was logging cryptic errors such as `cannot execute funcName="..." on vmstorage "...": EOF`.
|
||||
* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): add support for time zone selection for older versions of browsers. See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/3680).
|
||||
* BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent.html): update API version for [ec2_sd_configs](https://docs.victoriametrics.com/sd_configs.html#ec2_sd_configs) to fix [the issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3700) with missing `__meta_ec2_availability_zone_id` attribute.
|
||||
|
||||
## [v1.86.2](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.86.2)
|
||||
|
||||
|
|
|
@ -1086,7 +1086,9 @@ The [deduplication](#deduplication) isn't applied for the data exported in nativ
|
|||
|
||||
## How to import time series data
|
||||
|
||||
Time series data can be imported into VictoriaMetrics via any supported data ingestion protocol:
|
||||
VictoriaMetrics can discover and scrape metrics from Prometheus-compatible targets (aka "pull" protocol) -
|
||||
see [these docs](#how-to-scrape-prometheus-exporters-such-as-node-exporter).
|
||||
Additionally, VictoriaMetrics can accept metrics via the following popular data ingestion protocols (aka "push" protocols):
|
||||
|
||||
* [Prometheus remote_write API](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write). See [these docs](#prometheus-setup) for details.
|
||||
* DataDog `submit metrics` API. See [these docs](#how-to-send-data-from-datadog-agent) for details.
|
||||
|
|
|
@ -94,7 +94,8 @@ The helm chart repository [https://github.com/VictoriaMetrics/helm-charts/](http
|
|||
4. Update `cluster` chart versions in [`values.yaml`](https://github.com/VictoriaMetrics/helm-charts/blob/master/charts/victoria-metrics-cluster/values.yaml), bump version for `vmselect`, `vminsert` and `vmstorage` and [`Chart.yaml`](https://github.com/VictoriaMetrics/helm-charts/blob/master/charts/victoria-metrics-cluster/Chart.yaml)
|
||||
5. Update `k8s-stack` chart versions in [`values.yaml`](https://github.com/VictoriaMetrics/helm-charts/blob/master/charts/victoria-metrics-k8s-stack/values.yaml), bump version for `vmselect`, `vminsert`, `vmstorage`, `vmsingle`, `vmalert`, `vmagent` and [`Chart.yaml`](https://github.com/VictoriaMetrics/helm-charts/blob/master/charts/victoria-metrics-k8s-stack/Chart.yaml)
|
||||
6. Update `single-node` chart version in [`values.yaml`](https://github.com/VictoriaMetrics/helm-charts/blob/master/charts/victoria-metrics-single/values.yaml) and [`Chart.yaml`](https://github.com/VictoriaMetrics/helm-charts/blob/master/charts/victoria-metrics-single/Chart.yaml)
|
||||
8. Run `make gen-doc`
|
||||
7. Update `vmgateway` chart version in [`values.yaml`](https://github.com/VictoriaMetrics/helm-charts/blob/master/charts/victoria-metrics-gateway/values.yamll) and [`Chart.yaml`](https://github.com/VictoriaMetrics/helm-charts/blob/master/charts/victoria-metrics-gateway/Chart.yaml)
|
||||
8. Run `make gen-docs`
|
||||
9. Run `make package` that creates or updates zip file with the packed chart
|
||||
10. Run `make merge`. It creates or updates metadata for charts in index.yaml
|
||||
11. Push changes to master. `master` is a source of truth
|
||||
|
|
|
@ -1089,7 +1089,9 @@ The [deduplication](#deduplication) isn't applied for the data exported in nativ
|
|||
|
||||
## How to import time series data
|
||||
|
||||
Time series data can be imported into VictoriaMetrics via any supported data ingestion protocol:
|
||||
VictoriaMetrics can discover and scrape metrics from Prometheus-compatible targets (aka "pull" protocol) -
|
||||
see [these docs](#how-to-scrape-prometheus-exporters-such-as-node-exporter).
|
||||
Additionally, VictoriaMetrics can accept metrics via the following popular data ingestion protocols (aka "push" protocols):
|
||||
|
||||
* [Prometheus remote_write API](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write). See [these docs](#prometheus-setup) for details.
|
||||
* DataDog `submit metrics` API. See [these docs](#how-to-send-data-from-datadog-agent) for details.
|
||||
|
|
16
go.mod
16
go.mod
|
@ -3,7 +3,7 @@ module github.com/VictoriaMetrics/VictoriaMetrics
|
|||
go 1.19
|
||||
|
||||
require (
|
||||
cloud.google.com/go/storage v1.28.1
|
||||
cloud.google.com/go/storage v1.29.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.6.1
|
||||
github.com/VictoriaMetrics/fastcache v1.12.0
|
||||
|
@ -26,13 +26,13 @@ require (
|
|||
github.com/golang/snappy v0.0.4
|
||||
github.com/googleapis/gax-go/v2 v2.7.0
|
||||
github.com/influxdata/influxdb v1.11.0
|
||||
github.com/klauspost/compress v1.15.14
|
||||
github.com/klauspost/compress v1.15.15
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||
github.com/oklog/ulid v1.3.1
|
||||
github.com/prometheus/common v0.39.0 // indirect
|
||||
github.com/prometheus/prometheus v0.41.0
|
||||
github.com/urfave/cli/v2 v2.23.7
|
||||
github.com/urfave/cli/v2 v2.24.1
|
||||
github.com/valyala/fastjson v1.6.4
|
||||
github.com/valyala/fastrand v1.1.0
|
||||
github.com/valyala/fasttemplate v1.2.2
|
||||
|
@ -42,19 +42,19 @@ require (
|
|||
golang.org/x/net v0.5.0
|
||||
golang.org/x/oauth2 v0.4.0
|
||||
golang.org/x/sys v0.4.0
|
||||
google.golang.org/api v0.107.0
|
||||
google.golang.org/api v0.108.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.108.0 // indirect
|
||||
cloud.google.com/go v0.109.0 // indirect
|
||||
cloud.google.com/go/compute v1.15.1 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||
cloud.google.com/go/iam v0.10.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2 // indirect
|
||||
github.com/VividCortex/ewma v1.2.0 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
|
||||
github.com/aws/aws-sdk-go v1.44.180 // indirect
|
||||
github.com/aws/aws-sdk-go v1.44.184 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.21 // indirect
|
||||
|
@ -107,13 +107,13 @@ require (
|
|||
go.opentelemetry.io/otel/trace v1.11.2 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/goleak v1.2.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230113213754-f9f960f08ad4 // indirect
|
||||
golang.org/x/exp v0.0.0-20230118134722-a68e582fa157 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/text v0.6.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230119192704-9d59e20e5cd1 // indirect
|
||||
google.golang.org/grpc v1.52.0 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
|
32
go.sum
32
go.sum
|
@ -13,8 +13,8 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV
|
|||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go v0.108.0 h1:xntQwnfn8oHGX0crLVinvHM+AhXvi3QHQIEcX/2hiWk=
|
||||
cloud.google.com/go v0.108.0/go.mod h1:lNUfQqusBJp0bgAg6qrHgYFYbTB+dOiob1itwnlD33Q=
|
||||
cloud.google.com/go v0.109.0 h1:38CZoKGlCnPZjGdyj0ZfpoGae0/wgNfy5F0byyxg0Gk=
|
||||
cloud.google.com/go v0.109.0/go.mod h1:2sYycXt75t/CSB5R9M2wPU1tJmire7AQZTPtITcGBVE=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
|
@ -39,8 +39,8 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
|
|||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
cloud.google.com/go/storage v1.28.1 h1:F5QDG5ChchaAVQhINh24U99OWHURqrW8OmQcGKXcbgI=
|
||||
cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y=
|
||||
cloud.google.com/go/storage v1.29.0 h1:6weCgzRvMg7lzuUurI4697AqIRPU1SvzHhynwpW31jI=
|
||||
cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/Azure/azure-sdk-for-go v65.0.0+incompatible h1:HzKLt3kIwMm4KeJYTdx9EbjRYTySD/t8i1Ee/W5EGXw=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.0 h1:VuHAcMq8pU1IWNT/m5yRaGqbK0BiQKHT8X4DTp9CHdI=
|
||||
|
@ -87,8 +87,8 @@ github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu
|
|||
github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/armon/go-metrics v0.3.10 h1:FR+drcQStOe+32sYyJYyZ7FIdgoGGBnwLl+flodp8Uo=
|
||||
github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aws/aws-sdk-go v1.44.180 h1:VLZuAHI9fa/3WME5JjpVjcPCNfpGHVMiHx8sLHWhMgI=
|
||||
github.com/aws/aws-sdk-go v1.44.180/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
github.com/aws/aws-sdk-go v1.44.184 h1:/MggyE66rOImXJKl1HqhLQITvWvqIV7w1Q4MaG6FHUo=
|
||||
github.com/aws/aws-sdk-go v1.44.184/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
github.com/aws/aws-sdk-go-v2 v1.17.3 h1:shN7NlnVzvDUgPQ+1rLMSxY8OWRNDRYtiqe0p/PgrhY=
|
||||
github.com/aws/aws-sdk-go-v2 v1.17.3/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs=
|
||||
|
@ -316,8 +316,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
|
|||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.15.14 h1:i7WCKDToww0wA+9qrUZ1xOjp218vfFo3nTU6UHp+gOc=
|
||||
github.com/klauspost/compress v1.15.14/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
|
||||
github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw=
|
||||
github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4=
|
||||
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
|
@ -423,8 +423,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/urfave/cli/v2 v2.23.7 h1:YHDQ46s3VghFHFf1DdF+Sh7H4RqhcM+t0TmZRJx4oJY=
|
||||
github.com/urfave/cli/v2 v2.23.7/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
|
||||
github.com/urfave/cli/v2 v2.24.1 h1:/QYYr7g0EhwXEML8jO+8OYt5trPnLHS0p3mrgExJ5NU=
|
||||
github.com/urfave/cli/v2 v2.24.1/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus=
|
||||
|
@ -487,8 +487,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
|
|||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20230113213754-f9f960f08ad4 h1:CNkDRtCj8otM5CFz5jYvbr8ioXX8flVsLfDWEj0M5kk=
|
||||
golang.org/x/exp v0.0.0-20230113213754-f9f960f08ad4/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/exp v0.0.0-20230118134722-a68e582fa157 h1:fiNkyhJPUvxbRPbCqY/D9qdjmPzfHcpK3P4bM4gioSY=
|
||||
golang.org/x/exp v0.0.0-20230118134722-a68e582fa157/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
|
@ -703,8 +703,8 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M
|
|||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/api v0.107.0 h1:I2SlFjD8ZWabaIFOfeEDg3pf0BHJDh6iYQ1ic3Yu/UU=
|
||||
google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=
|
||||
google.golang.org/api v0.108.0 h1:WVBc/faN0DkKtR43Q/7+tPny9ZoLZdIiAyG5Q9vFClg=
|
||||
google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
|
@ -742,8 +742,8 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc
|
|||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5 h1:wJT65XLOzhpSPCdAmmKfz94SlmnQzDzjm3Cj9k3fsXY=
|
||||
google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
||||
google.golang.org/genproto v0.0.0-20230119192704-9d59e20e5cd1 h1:wSjSSQW7LuPdv3m1IrSN33nVxH/kID6OIKy+FMwGB2k=
|
||||
google.golang.org/genproto v0.0.0-20230119192704-9d59e20e5cd1/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
|
|
|
@ -109,7 +109,7 @@ func (cfg *Config) GetEC2APIResponse(action, filtersQueryString, nextPageToken s
|
|||
if len(nextPageToken) > 0 {
|
||||
apiURL += fmt.Sprintf("&NextToken=%s", url.QueryEscape(nextPageToken))
|
||||
}
|
||||
apiURL += "&Version=2013-10-15"
|
||||
apiURL += "&Version=2016-11-15"
|
||||
req, err := newSignedGetRequest(apiURL, "ec2", cfg.region, ac)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot create signed request: %w", err)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package bytesutil
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
@ -8,6 +9,9 @@ import (
|
|||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/fasttime"
|
||||
)
|
||||
|
||||
var internStringMaxLen = flag.Int("internStringMaxLen", 300, "The maximum length for strings to intern. Lower limit may save memory at the cost of higher CPU usage. "+
|
||||
"See https://en.wikipedia.org/wiki/String_interning")
|
||||
|
||||
// InternBytes interns b as a string
|
||||
func InternBytes(b []byte) string {
|
||||
s := ToUnsafeString(b)
|
||||
|
@ -30,6 +34,12 @@ func InternString(s string) string {
|
|||
}
|
||||
// Make a new copy for s in order to remove references from possible bigger string s refers to.
|
||||
sCopy := strings.Clone(s)
|
||||
if len(sCopy) > *internStringMaxLen {
|
||||
// Do not intern long strings, since this may result in high memory usage
|
||||
// like in https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3692
|
||||
return sCopy
|
||||
}
|
||||
|
||||
e := &ismEntry{
|
||||
lastAccessTime: ct,
|
||||
s: sCopy,
|
||||
|
|
|
@ -506,8 +506,9 @@ func TestFloatToDecimalRoundtrip(t *testing.T) {
|
|||
f(vMin)
|
||||
f(vStaleNaN)
|
||||
|
||||
r := rand.New(rand.NewSource(1))
|
||||
for i := 0; i < 1e4; i++ {
|
||||
v := rand.NormFloat64()
|
||||
v := r.NormFloat64()
|
||||
f(v)
|
||||
f(v * 1e-6)
|
||||
f(v * 1e6)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue