Compare commits

...

15 Commits

Author SHA1 Message Date
Amlan Kumar Nandy
860ddf34ca Merge branch 'main' into SIG-3098 2026-01-12 15:32:49 +07:00
Ashwin Bhatkal
9c5b50ae3a chore: add CODEWONERS for dashboard page and container (#9979) 2026-01-12 11:54:11 +05:30
Srikanth Chekuri
fd13c6dee4 tests(integration): organize querier test and use numbered prefixes (#9969) 2026-01-11 11:33:23 +05:30
Srikanth Chekuri
a894b08255 chore: add metric data generators (#9968) 2026-01-10 14:24:53 +05:30
Srikanth Chekuri
2c6c034e60 chore: use uv (#9964) 2026-01-10 14:03:43 +05:30
Abhishek Kumar Singh
0a81bf8060 chore: add ability to delay the evaluation start for new groups (#9621) 2026-01-09 23:26:39 +05:30
Abhishek Kumar Singh
b38ffce7f2 fix: test notification always sends a new notification (#9807) 2026-01-09 22:46:40 +05:30
Vishal Sharma
696d83eeaf chore: add new related keywords in onboarding (#9963) 2026-01-09 14:21:13 +00:00
Amlan Kumar Nandy
d98851dcf2 chore: y-axis unit selector changes in alerts and dashboards (#9936) 2026-01-09 13:17:24 +00:00
Amlan Kumar Nandy
a103bb453d chore: ease in disabling grouping in notification settings (#9698) 2026-01-09 18:37:29 +05:30
Pandey
abae0c7f27 fix(tokenizer): fix concurrent map writes in jwt tokenizer (#9960)
* fix(tokenizer): fix concurrent map writes

* fix(tokenizer): fix concurrent map writes

* fix(tokenizer): fix concurrent map writes

* fix(tokenizer): fix concurrent map writes

* fix(tokenizer): fix concurrent map writes

---------

Co-authored-by: Vikrant Gupta <vikrant@signoz.io>
2026-01-09 10:05:44 +00:00
Abhi kumar
0cc1fb0edb fix: added fix for reduce to resetting back to avg (#9947)
* fix: added fix for reduce to resetting back to avg

* fix: fixed failing tsc

* fix: added fix for querybuilderoperations hook test

* fix: added pr review fixes

* fix: pr review changes

* chore: pr review changes
2026-01-09 14:42:55 +05:30
Amlan Kumar Nandy
f2ef42bd7f chore: alert type selection page improvements (#9724) 2026-01-09 12:45:01 +07:00
Vikrant Gupta
22158a3cee fix(preference): update user preference apis to return 200 when preference exists but has no value (#9957)
### Summary

- update user preference to return `200` in case of no overrides as well instead of `404`
2026-01-08 15:46:50 +00:00
amlannandy
20fec8baa4 chore: fix undefined values error in alerts history 2025-12-16 18:21:47 +07:00
152 changed files with 8741 additions and 3045 deletions

18
.github/CODEOWNERS vendored
View File

@@ -1,10 +1,13 @@
# CODEOWNERS info: https://help.github.com/en/articles/about-code-owners
# Owners are automatically requested for review for PRs that changes code
# that they own.
/frontend/ @SigNoz/frontend-maintainers
# Onboarding
/frontend/src/container/OnboardingV2Container/onboarding-configs/onboarding-config-with-links.json @makeavish
/frontend/src/container/OnboardingV2Container/AddDataSource/AddDataSource.tsx @makeavish
@@ -12,6 +15,7 @@
.github @SigNoz/devops
# Scaffold Owners
/pkg/config/ @therealpandey
/pkg/errors/ @therealpandey
/pkg/factory/ @therealpandey
@@ -21,22 +25,26 @@
.golangci.yml @therealpandey
# Zeus Owners
/pkg/zeus/ @vikrantgupta25
/ee/zeus/ @vikrantgupta25
/pkg/licensing/ @vikrantgupta25
/ee/licensing/ @vikrantgupta25
# SQL Owners
/pkg/sqlmigration/ @vikrantgupta25
/ee/sqlmigration/ @vikrantgupta25
/pkg/sqlschema/ @vikrantgupta25
/ee/sqlschema/ @vikrantgupta25
# Analytics Owners
/pkg/analytics/ @vikrantgupta25
/pkg/statsreporter/ @vikrantgupta25
# Querier Owners
/pkg/querier/ @srikanthccv
/pkg/variables/ @srikanthccv
/pkg/types/querybuildertypes/ @srikanthccv
@@ -46,8 +54,16 @@
/pkg/telemetrymetrics/ @srikanthccv
/pkg/telemetrytraces/ @srikanthccv
# AuthN / AuthZ Owners
# AuthN / AuthZ Owners
/pkg/authz/ @vikrantgupta25 @therealpandey
# Integration tests
/tests/integration/ @therealpandey
# Dashboard Owners
/frontend/src/pages/DashboardPage/ @SigNoz/pulse-frontend
/frontend/src/container/NewDashboard/ @SigNoz/pulse-frontend
/frontend/src/container/GridCardLayout/ @SigNoz/pulse-frontend

View File

@@ -21,11 +21,11 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: 3.13
- name: poetry
- name: uv
uses: astral-sh/setup-uv@v4
- name: install
run: |
python -m pip install poetry==2.1.2
python -m poetry config virtualenvs.in-project true
cd tests/integration && poetry install --no-root
cd tests/integration && uv sync
- name: fmt
run: |
make py-fmt
@@ -67,11 +67,11 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: 3.13
- name: poetry
- name: uv
uses: astral-sh/setup-uv@v4
- name: install
run: |
python -m pip install poetry==2.1.2
python -m poetry config virtualenvs.in-project true
cd tests/integration && poetry install --no-root
cd tests/integration && uv sync
- name: webdriver
run: |
wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
@@ -89,7 +89,7 @@ jobs:
- name: run
run: |
cd tests/integration && \
poetry run pytest \
uv run pytest \
--basetemp=./tmp/ \
src/${{matrix.src}} \
--sqlstore-provider ${{matrix.sqlstore-provider}} \

2
.gitignore vendored
View File

@@ -222,8 +222,6 @@ cython_debug/
#.idea/
### Python Patch ###
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
poetry.toml
# ruff
.ruff_cache/

10
.mockery.yml Normal file
View File

@@ -0,0 +1,10 @@
# Link to template variables: https://pkg.go.dev/github.com/vektra/mockery/v3/config#TemplateData
template: testify
packages:
github.com/SigNoz/signoz/pkg/alertmanager:
config:
all: true
dir: '{{.InterfaceDir}}/mocks'
filename: "mocks.go"
structname: 'Mock{{.InterfaceName}}'
pkgname: '{{.SrcPackageName}}mock'

View File

@@ -202,25 +202,25 @@ docker-buildx-enterprise: go-build-enterprise js-build
##############################################################
.PHONY: py-fmt
py-fmt: ## Run black for integration tests
@cd tests/integration && poetry run black .
@cd tests/integration && uv run black .
.PHONY: py-lint
py-lint: ## Run lint for integration tests
@cd tests/integration && poetry run isort .
@cd tests/integration && poetry run autoflake .
@cd tests/integration && poetry run pylint .
@cd tests/integration && uv run isort .
@cd tests/integration && uv run autoflake .
@cd tests/integration && uv run pylint .
.PHONY: py-test-setup
py-test-setup: ## Runs integration tests
@cd tests/integration && poetry run pytest --basetemp=./tmp/ -vv --reuse --capture=no src/bootstrap/setup.py::test_setup
@cd tests/integration && uv run pytest --basetemp=./tmp/ -vv --reuse --capture=no src/bootstrap/setup.py::test_setup
.PHONY: py-test-teardown
py-test-teardown: ## Runs integration tests with teardown
@cd tests/integration && poetry run pytest --basetemp=./tmp/ -vv --teardown --capture=no src/bootstrap/setup.py::test_teardown
@cd tests/integration && uv run pytest --basetemp=./tmp/ -vv --teardown --capture=no src/bootstrap/setup.py::test_teardown
.PHONY: py-test
py-test: ## Runs integration tests
@cd tests/integration && poetry run pytest --basetemp=./tmp/ -vv --capture=no src/
@cd tests/integration && uv run pytest --basetemp=./tmp/ -vv --capture=no src/
.PHONY: py-clean
py-clean: ## Clear all pycache and pytest cache from tests directory recursively

View File

@@ -9,7 +9,7 @@ SigNoz uses integration tests to verify that different components work together
Before running integration tests, ensure you have the following installed:
- Python 3.13+
- Poetry (for dependency management)
- [uv](https://docs.astral.sh/uv/getting-started/installation/)
- Docker (for containerized services)
### Initial Setup
@@ -19,17 +19,19 @@ Before running integration tests, ensure you have the following installed:
cd tests/integration
```
2. Install dependencies using Poetry:
2. Install dependencies using uv:
```bash
poetry install --no-root
uv sync
```
> **_NOTE:_** the build backend could throw an error while installing `psycopg2`, pleae see https://www.psycopg.org/docs/install.html#build-prerequisites
### Starting the Test Environment
To spin up all the containers necessary for writing integration tests and keep them running:
```bash
poetry run pytest --basetemp=./tmp/ -vv --reuse src/bootstrap/setup.py::test_setup
uv run pytest --basetemp=./tmp/ -vv --reuse src/bootstrap/setup.py::test_setup
```
This command will:
@@ -42,7 +44,7 @@ This command will:
When you're done writing integration tests, clean up the environment:
```bash
poetry run pytest --basetemp=./tmp/ -vv --teardown -s src/bootstrap/setup.py::test_teardown
uv run pytest --basetemp=./tmp/ -vv --teardown -s src/bootstrap/setup.py::test_teardown
```
This will destroy the running integration test setup and clean up resources.
@@ -72,20 +74,20 @@ Python and pytest form the foundation of the integration testing framework. Test
│ ├── sqlite.py
│ ├── types.py
│ └── zookeeper.py
├── poetry.lock
├── uv.lock
├── pyproject.toml
└── src
└── bootstrap
├── __init__.py
├── a_database.py
├── b_register.py
└── c_license.py
├── 01_database.py
├── 02_register.py
└── 03_license.py
```
Each test suite follows some important principles:
1. **Organization**: Test suites live under `src/` in self-contained packages. Fixtures (a pytest concept) live inside `fixtures/`.
2. **Execution Order**: Files are prefixed with `a_`, `b_`, `c_` to ensure sequential execution.
2. **Execution Order**: Files are prefixed with two-digit numbers (`01_`, `02_`, `03_`) to ensure sequential execution.
3. **Time Constraints**: Each suite should complete in under 10 minutes (setup takes ~4 mins).
### Test Suite Design
@@ -107,7 +109,7 @@ Other test suites can be **pipelines, auth, querier.**
## How to write an integration test?
Now start writing an integration test. Create a new file `src/bootstrap/e_version.py` and paste the following:
Now start writing an integration test. Create a new file `src/bootstrap/05_version.py` and paste the following:
```python
import requests
@@ -125,7 +127,7 @@ def test_version(signoz: types.SigNoz) -> None:
We have written a simple test which calls the `version` endpoint of the container in step 1. In **order to just run this function, run the following command:**
```bash
poetry run pytest --basetemp=./tmp/ -vv --reuse src/bootstrap/e_version.py::test_version
uv run pytest --basetemp=./tmp/ -vv --reuse src/bootstrap/05_version.py::test_version
```
> Note: The `--reuse` flag is used to reuse the environment if it is already running. Always use this flag when writing and running integration tests. If you don't use this flag, the environment will be destroyed and recreated every time you run the test.
@@ -153,7 +155,7 @@ def test_user_registration(signoz: types.SigNoz) -> None:
},
timeout=2,
)
assert response.status_code == HTTPStatus.OK
assert response.json()["setupCompleted"] is True
```
@@ -163,27 +165,27 @@ def test_user_registration(signoz: types.SigNoz) -> None:
### Running All Tests
```bash
poetry run pytest --basetemp=./tmp/ -vv --reuse src/
uv run pytest --basetemp=./tmp/ -vv --reuse src/
```
### Running Specific Test Categories
```bash
poetry run pytest --basetemp=./tmp/ -vv --reuse src/<suite>
uv run pytest --basetemp=./tmp/ -vv --reuse src/<suite>
# Run querier tests
poetry run pytest --basetemp=./tmp/ -vv --reuse src/querier/
uv run pytest --basetemp=./tmp/ -vv --reuse src/querier/
# Run auth tests
poetry run pytest --basetemp=./tmp/ -vv --reuse src/auth/
uv run pytest --basetemp=./tmp/ -vv --reuse src/auth/
```
### Running Individual Tests
```bash
poetry run pytest --basetemp=./tmp/ -vv --reuse src/<suite>/<file>.py::test_name
uv run pytest --basetemp=./tmp/ -vv --reuse src/<suite>/<file>.py::test_name
# Run test_register in file a_register.py in auth suite
poetry run pytest --basetemp=./tmp/ -vv --reuse src/auth/a_register.py::test_register
# Run test_register in file 01_register.py in passwordauthn suite
uv run pytest --basetemp=./tmp/ -vv --reuse src/passwordauthn/01_register.py::test_register
```
## How to configure different options for integration tests?
@@ -197,7 +199,7 @@ Tests can be configured using pytest options:
Example:
```bash
poetry run pytest --basetemp=./tmp/ -vv --reuse --sqlstore-provider=postgres --postgres-version=14 src/auth/
uv run pytest --basetemp=./tmp/ -vv --reuse --sqlstore-provider=postgres --postgres-version=14 src/auth/
```
@@ -205,7 +207,7 @@ poetry run pytest --basetemp=./tmp/ -vv --reuse --sqlstore-provider=postgres --p
- **Always use the `--reuse` flag** when setting up the environment to keep containers running
- **Use the `--teardown` flag** when cleaning up to avoid resource leaks
- **Follow the naming convention** with alphabetical prefixes for test execution order
- **Follow the naming convention** with two-digit numeric prefixes (`01_`, `02_`) for test execution order
- **Use proper timeouts** in HTTP requests to avoid hanging tests
- **Clean up test data** between tests to avoid interference
- **Use descriptive test names** that clearly indicate what is being tested

View File

@@ -12,6 +12,7 @@ import (
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/queryparser"
"github.com/SigNoz/signoz/pkg/ruler/rulestore/sqlrulestore"
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
"go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux"
"go.opentelemetry.io/otel/propagation"
@@ -104,6 +105,7 @@ func NewServer(config signoz.Config, signoz *signoz.SigNoz) (*Server, error) {
signoz.Alertmanager,
signoz.SQLStore,
signoz.TelemetryStore,
signoz.TelemetryMetadataStore,
signoz.Prometheus,
signoz.Modules.OrgGetter,
signoz.Querier,
@@ -355,12 +357,13 @@ func (s *Server) Stop(ctx context.Context) error {
return nil
}
func makeRulesManager(ch baseint.Reader, cache cache.Cache, alertmanager alertmanager.Alertmanager, sqlstore sqlstore.SQLStore, telemetryStore telemetrystore.TelemetryStore, prometheus prometheus.Prometheus, orgGetter organization.Getter, querier querier.Querier, providerSettings factory.ProviderSettings, queryParser queryparser.QueryParser) (*baserules.Manager, error) {
func makeRulesManager(ch baseint.Reader, cache cache.Cache, alertmanager alertmanager.Alertmanager, sqlstore sqlstore.SQLStore, telemetryStore telemetrystore.TelemetryStore, metadataStore telemetrytypes.MetadataStore, prometheus prometheus.Prometheus, orgGetter organization.Getter, querier querier.Querier, providerSettings factory.ProviderSettings, queryParser queryparser.QueryParser) (*baserules.Manager, error) {
ruleStore := sqlrulestore.NewRuleStore(sqlstore, queryParser, providerSettings)
maintenanceStore := sqlrulestore.NewMaintenanceStore(sqlstore)
// create manager opts
managerOpts := &baserules.ManagerOptions{
TelemetryStore: telemetryStore,
MetadataStore: metadataStore,
Prometheus: prometheus,
Context: context.Background(),
Logger: zap.L(),
@@ -376,6 +379,7 @@ func makeRulesManager(ch baseint.Reader, cache cache.Cache, alertmanager alertma
RuleStore: ruleStore,
MaintenanceStore: maintenanceStore,
SqlStore: sqlstore,
QueryParser: queryParser,
}
// create Manager

View File

@@ -247,7 +247,8 @@ func (r *AnomalyRule) buildAndRunQuery(ctx context.Context, orgID valuer.UUID, t
}
}
results, err := r.Threshold.Eval(*series, r.Unit(), ruletypes.EvalData{
ActiveAlerts: r.ActiveAlertsLabelFP(),
ActiveAlerts: r.ActiveAlertsLabelFP(),
SendUnmatched: r.ShouldSendUnmatched(),
})
if err != nil {
return nil, err
@@ -291,7 +292,19 @@ func (r *AnomalyRule) buildAndRunQueryV5(ctx context.Context, orgID valuer.UUID,
scoresJSON, _ := json.Marshal(queryResult.AnomalyScores)
r.logger.InfoContext(ctx, "anomaly scores", "scores", string(scoresJSON))
for _, series := range queryResult.AnomalyScores {
// Filter out new series if newGroupEvalDelay is configured
seriesToProcess := queryResult.AnomalyScores
if r.ShouldSkipNewGroups() {
filteredSeries, filterErr := r.BaseRule.FilterNewSeries(ctx, ts, seriesToProcess)
// In case of error we log the error and continue with the original series
if filterErr != nil {
r.logger.ErrorContext(ctx, "Error filtering new series, ", "error", filterErr, "rule_name", r.Name())
} else {
seriesToProcess = filteredSeries
}
}
for _, series := range seriesToProcess {
if r.Condition().RequireMinPoints {
if len(series.Points) < r.Condition().RequiredNumPoints {
r.logger.InfoContext(ctx, "not enough data points to evaluate series, skipping", "ruleid", r.ID(), "numPoints", len(series.Points), "requiredPoints", r.Condition().RequiredNumPoints)
@@ -299,7 +312,8 @@ func (r *AnomalyRule) buildAndRunQueryV5(ctx context.Context, orgID valuer.UUID,
}
}
results, err := r.Threshold.Eval(*series, r.Unit(), ruletypes.EvalData{
ActiveAlerts: r.ActiveAlertsLabelFP(),
ActiveAlerts: r.ActiveAlertsLabelFP(),
SendUnmatched: r.ShouldSendUnmatched(),
})
if err != nil {
return nil, err

View File

@@ -37,6 +37,8 @@ func PrepareTaskFunc(opts baserules.PrepareTaskOptions) (baserules.Task, error)
opts.SLogger,
baserules.WithEvalDelay(opts.ManagerOpts.EvalDelay),
baserules.WithSQLStore(opts.SQLStore),
baserules.WithQueryParser(opts.ManagerOpts.QueryParser),
baserules.WithMetadataStore(opts.ManagerOpts.MetadataStore),
)
if err != nil {
@@ -59,6 +61,8 @@ func PrepareTaskFunc(opts baserules.PrepareTaskOptions) (baserules.Task, error)
opts.Reader,
opts.ManagerOpts.Prometheus,
baserules.WithSQLStore(opts.SQLStore),
baserules.WithQueryParser(opts.ManagerOpts.QueryParser),
baserules.WithMetadataStore(opts.ManagerOpts.MetadataStore),
)
if err != nil {
@@ -82,6 +86,8 @@ func PrepareTaskFunc(opts baserules.PrepareTaskOptions) (baserules.Task, error)
opts.Cache,
baserules.WithEvalDelay(opts.ManagerOpts.EvalDelay),
baserules.WithSQLStore(opts.SQLStore),
baserules.WithQueryParser(opts.ManagerOpts.QueryParser),
baserules.WithMetadataStore(opts.ManagerOpts.MetadataStore),
)
if err != nil {
return task, err
@@ -140,6 +146,8 @@ func TestNotification(opts baserules.PrepareTestRuleOptions) (int, *basemodel.Ap
baserules.WithSendAlways(),
baserules.WithSendUnmatched(),
baserules.WithSQLStore(opts.SQLStore),
baserules.WithQueryParser(opts.ManagerOpts.QueryParser),
baserules.WithMetadataStore(opts.ManagerOpts.MetadataStore),
)
if err != nil {
@@ -160,6 +168,8 @@ func TestNotification(opts baserules.PrepareTestRuleOptions) (int, *basemodel.Ap
baserules.WithSendAlways(),
baserules.WithSendUnmatched(),
baserules.WithSQLStore(opts.SQLStore),
baserules.WithQueryParser(opts.ManagerOpts.QueryParser),
baserules.WithMetadataStore(opts.ManagerOpts.MetadataStore),
)
if err != nil {
@@ -179,6 +189,8 @@ func TestNotification(opts baserules.PrepareTestRuleOptions) (int, *basemodel.Ap
baserules.WithSendAlways(),
baserules.WithSendUnmatched(),
baserules.WithSQLStore(opts.SQLStore),
baserules.WithQueryParser(opts.ManagerOpts.QueryParser),
baserules.WithMetadataStore(opts.ManagerOpts.MetadataStore),
)
if err != nil {
zap.L().Error("failed to prepare a new anomaly rule for test", zap.String("name", alertname), zap.Error(err))

View File

@@ -0,0 +1,283 @@
package rules
import (
"context"
"encoding/json"
"math"
"strconv"
"testing"
"time"
"github.com/SigNoz/signoz/pkg/alertmanager"
alertmanagermock "github.com/SigNoz/signoz/pkg/alertmanager/mocks"
"github.com/SigNoz/signoz/pkg/instrumentation/instrumentationtest"
"github.com/SigNoz/signoz/pkg/prometheus"
"github.com/SigNoz/signoz/pkg/prometheus/prometheustest"
"github.com/SigNoz/signoz/pkg/query-service/rules"
"github.com/SigNoz/signoz/pkg/sqlstore"
"github.com/SigNoz/signoz/pkg/sqlstore/sqlstoretest"
"github.com/SigNoz/signoz/pkg/telemetrystore"
"github.com/SigNoz/signoz/pkg/telemetrystore/telemetrystoretest"
"github.com/SigNoz/signoz/pkg/types/alertmanagertypes"
"github.com/SigNoz/signoz/pkg/types/metrictypes"
"github.com/SigNoz/signoz/pkg/valuer"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
cmock "github.com/srikanthccv/ClickHouse-go-mock"
)
func TestManager_TestNotification_SendUnmatched_ThresholdRule(t *testing.T) {
target := 10.0
recovery := 5.0
for _, tc := range rules.TcTestNotiSendUnmatchedThresholdRule {
t.Run(tc.Name, func(t *testing.T) {
rule := rules.ThresholdRuleAtLeastOnceValueAbove(target, &recovery)
// Marshal rule to JSON as TestNotification expects
ruleBytes, err := json.Marshal(rule)
require.NoError(t, err)
orgID := valuer.GenerateUUID()
// for saving temp alerts that are triggered via TestNotification
triggeredTestAlerts := []map[*alertmanagertypes.PostableAlert][]string{}
// Create manager using test factory with hooks
mgr := rules.NewTestManager(t, &rules.TestManagerOptions{
AlertmanagerHook: func(am alertmanager.Alertmanager) {
fAlert := am.(*alertmanagermock.MockAlertmanager)
// mock set notification config
fAlert.On("SetNotificationConfig", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
// for saving temp alerts that are triggered via TestNotification
if tc.ExpectAlerts > 0 {
fAlert.On("TestAlert", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
triggeredTestAlerts = append(triggeredTestAlerts, args.Get(3).(map[*alertmanagertypes.PostableAlert][]string))
}).Return(nil).Times(tc.ExpectAlerts)
}
},
ManagerOptionsHook: func(opts *rules.ManagerOptions) {
opts.PrepareTestRuleFunc = TestNotification
},
SqlStoreHook: func(store sqlstore.SQLStore) {
mockStore := store.(*sqlstoretest.Provider)
// Mock the organizations query that SendAlerts makes
// Bun generates: SELECT id FROM organizations LIMIT 1 (or SELECT "id" FROM "organizations" LIMIT 1)
orgRows := mockStore.Mock().NewRows([]string{"id"}).AddRow(orgID.StringValue())
// Match bun's generated query pattern - bun may quote identifiers
mockStore.Mock().ExpectQuery("SELECT (.+) FROM (.+)organizations(.+) LIMIT (.+)").WillReturnRows(orgRows)
},
TelemetryStoreHook: func(store telemetrystore.TelemetryStore) {
telemetryStore := store.(*telemetrystoretest.Provider)
// Set up mock data for telemetry store
cols := make([]cmock.ColumnType, 0)
cols = append(cols, cmock.ColumnType{Name: "value", Type: "Float64"})
cols = append(cols, cmock.ColumnType{Name: "attr", Type: "String"})
cols = append(cols, cmock.ColumnType{Name: "ts", Type: "DateTime"})
alertDataRows := cmock.NewRows(cols, tc.Values)
mock := telemetryStore.Mock()
// Generate query arguments for the metric query
evalTime := time.Now().UTC()
evalWindow := 5 * time.Minute
evalDelay := time.Duration(0)
queryArgs := rules.GenerateMetricQueryCHArgs(
evalTime,
evalWindow,
evalDelay,
"probe_success",
metrictypes.Unspecified,
)
mock.ExpectQuery("*WITH __temporal_aggregation_cte*").
WithArgs(queryArgs...).
WillReturnRows(alertDataRows)
},
})
count, apiErr := mgr.TestNotification(context.Background(), orgID, string(ruleBytes))
if apiErr != nil {
t.Logf("TestNotification error: %v, type: %s", apiErr.Err, apiErr.Typ)
}
require.Nil(t, apiErr)
assert.Equal(t, tc.ExpectAlerts, count)
if tc.ExpectAlerts > 0 {
// check if the alert has been triggered
require.Len(t, triggeredTestAlerts, 1)
var gotAlerts []*alertmanagertypes.PostableAlert
for a := range triggeredTestAlerts[0] {
gotAlerts = append(gotAlerts, a)
}
require.Len(t, gotAlerts, tc.ExpectAlerts)
// check if the alert has triggered with correct threshold value
if tc.ExpectValue != 0 {
assert.Equal(t, strconv.FormatFloat(tc.ExpectValue, 'f', -1, 64), gotAlerts[0].Annotations["value"])
}
} else {
// check if no alerts have been triggered
assert.Empty(t, triggeredTestAlerts)
}
})
}
}
func TestManager_TestNotification_SendUnmatched_PromRule(t *testing.T) {
target := 10.0
for _, tc := range rules.TcTestNotificationSendUnmatchedPromRule {
t.Run(tc.Name, func(t *testing.T) {
// Capture base time once per test case to ensure consistent timestamps
baseTime := time.Now().UTC()
rule := rules.BuildPromAtLeastOnceValueAbove(target, nil)
// Marshal rule to JSON as TestNotification expects
ruleBytes, err := json.Marshal(rule)
require.NoError(t, err)
orgID := valuer.GenerateUUID()
// for saving temp alerts that are triggered via TestNotification
triggeredTestAlerts := []map[*alertmanagertypes.PostableAlert][]string{}
// Variable to store promProvider for cleanup
var promProvider *prometheustest.Provider
// Create manager using test factory with hooks
mgr := rules.NewTestManager(t, &rules.TestManagerOptions{
AlertmanagerHook: func(am alertmanager.Alertmanager) {
mockAM := am.(*alertmanagermock.MockAlertmanager)
// mock set notification config
mockAM.On("SetNotificationConfig", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
// for saving temp alerts that are triggered via TestNotification
if tc.ExpectAlerts > 0 {
mockAM.On("TestAlert", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
triggeredTestAlerts = append(triggeredTestAlerts, args.Get(3).(map[*alertmanagertypes.PostableAlert][]string))
}).Return(nil).Times(tc.ExpectAlerts)
}
},
SqlStoreHook: func(store sqlstore.SQLStore) {
mockStore := store.(*sqlstoretest.Provider)
// Mock the organizations query that SendAlerts makes
orgRows := mockStore.Mock().NewRows([]string{"id"}).AddRow(orgID.StringValue())
mockStore.Mock().ExpectQuery("SELECT (.+) FROM (.+)organizations(.+) LIMIT (.+)").WillReturnRows(orgRows)
},
TelemetryStoreHook: func(store telemetrystore.TelemetryStore) {
mockStore := store.(*telemetrystoretest.Provider)
// Set up Prometheus-specific mock data
// Fingerprint columns for Prometheus queries
fingerprintCols := []cmock.ColumnType{
{Name: "fingerprint", Type: "UInt64"},
{Name: "any(labels)", Type: "String"},
}
// Samples columns for Prometheus queries
samplesCols := []cmock.ColumnType{
{Name: "metric_name", Type: "String"},
{Name: "fingerprint", Type: "UInt64"},
{Name: "unix_milli", Type: "Int64"},
{Name: "value", Type: "Float64"},
{Name: "flags", Type: "UInt32"},
}
// Calculate query time range similar to Prometheus rule tests
// TestNotification uses time.Now().UTC() for evaluation
// We calculate the query window based on current time to match what the actual evaluation will use
evalTime := baseTime
evalWindowMs := int64(5 * 60 * 1000) // 5 minutes in ms
evalTimeMs := evalTime.UnixMilli()
queryStart := ((evalTimeMs-2*evalWindowMs)/60000)*60000 + 1 // truncate to minute + 1ms
queryEnd := (evalTimeMs / 60000) * 60000 // truncate to minute
// Create fingerprint data
fingerprint := uint64(12345)
labelsJSON := `{"__name__":"test_metric"}`
fingerprintData := [][]interface{}{
{fingerprint, labelsJSON},
}
fingerprintRows := cmock.NewRows(fingerprintCols, fingerprintData)
// Create samples data from test case values, calculating timestamps relative to baseTime
validSamplesData := make([][]interface{}, 0)
for _, v := range tc.Values {
// Skip NaN and Inf values in the samples data
if math.IsNaN(v.Value) || math.IsInf(v.Value, 0) {
continue
}
// Calculate timestamp relative to baseTime
sampleTimestamp := baseTime.Add(v.Offset).UnixMilli()
validSamplesData = append(validSamplesData, []interface{}{
"test_metric",
fingerprint,
sampleTimestamp,
v.Value,
uint32(0), // flags - 0 means normal value
})
}
samplesRows := cmock.NewRows(samplesCols, validSamplesData)
mock := mockStore.Mock()
// Mock the fingerprint query (for Prometheus label matching)
mock.ExpectQuery("SELECT fingerprint, any").
WithArgs("test_metric", "__name__", "test_metric").
WillReturnRows(fingerprintRows)
// Mock the samples query (for Prometheus metric data)
mock.ExpectQuery("SELECT metric_name, fingerprint, unix_milli").
WithArgs(
"test_metric",
"test_metric",
"__name__",
"test_metric",
queryStart,
queryEnd,
).
WillReturnRows(samplesRows)
// Create Prometheus provider for this test
promProvider = prometheustest.New(context.Background(), instrumentationtest.New().ToProviderSettings(), prometheus.Config{}, store)
},
ManagerOptionsHook: func(opts *rules.ManagerOptions) {
// Set Prometheus provider for PromQL queries
if promProvider != nil {
opts.Prometheus = promProvider
}
opts.PrepareTestRuleFunc = TestNotification
},
})
count, apiErr := mgr.TestNotification(context.Background(), orgID, string(ruleBytes))
if apiErr != nil {
t.Logf("TestNotification error: %v, type: %s", apiErr.Err, apiErr.Typ)
}
require.Nil(t, apiErr)
assert.Equal(t, tc.ExpectAlerts, count)
if tc.ExpectAlerts > 0 {
// check if the alert has been triggered
require.Len(t, triggeredTestAlerts, 1)
var gotAlerts []*alertmanagertypes.PostableAlert
for a := range triggeredTestAlerts[0] {
gotAlerts = append(gotAlerts, a)
}
require.Len(t, gotAlerts, tc.ExpectAlerts)
// check if the alert has triggered with correct threshold value
if tc.ExpectValue != 0 && !math.IsNaN(tc.ExpectValue) && !math.IsInf(tc.ExpectValue, 0) {
assert.Equal(t, strconv.FormatFloat(tc.ExpectValue, 'f', -1, 64), gotAlerts[0].Annotations["value"])
}
} else {
// check if no alerts have been triggered
assert.Empty(t, triggeredTestAlerts)
}
promProvider.Close()
})
}
}

View File

@@ -45,6 +45,7 @@
"DEFAULT": "Open source Observability Platform | SigNoz",
"ALERT_HISTORY": "SigNoz | Alert Rule History",
"ALERT_OVERVIEW": "SigNoz | Alert Rule Overview",
"ALERT_TYPE_SELECTION": "SigNoz | Select Alert Type",
"INFRASTRUCTURE_MONITORING_HOSTS": "SigNoz | Infra Monitoring",
"INFRASTRUCTURE_MONITORING_KUBERNETES": "SigNoz | Infra Monitoring",
"METER_EXPLORER": "SigNoz | Meter Explorer",

View File

@@ -93,13 +93,15 @@ export const OnboardingV2 = Loadable(
() => import(/* webpackChunkName: "Onboarding V2" */ 'pages/OnboardingPageV2'),
);
export const DashboardPage = Loadable(
export const DashboardsListPage = Loadable(
() =>
import(/* webpackChunkName: "DashboardPage" */ 'pages/DashboardsListPage'),
import(
/* webpackChunkName: "DashboardsListPage" */ 'pages/DashboardsListPage'
),
);
export const NewDashboardPage = Loadable(
() => import(/* webpackChunkName: "New DashboardPage" */ 'pages/NewDashboard'),
export const DashboardPage = Loadable(
() => import(/* webpackChunkName: "DashboardPage" */ 'pages/DashboardPage'),
);
export const DashboardWidget = Loadable(

View File

@@ -1,4 +1,5 @@
import ROUTES from 'constants/routes';
import AlertTypeSelectionPage from 'pages/AlertTypeSelection';
import MessagingQueues from 'pages/MessagingQueues';
import MeterExplorer from 'pages/MeterExplorer';
import { RouteProps } from 'react-router-dom';
@@ -12,6 +13,7 @@ import {
CreateAlertChannelAlerts,
CreateNewAlerts,
DashboardPage,
DashboardsListPage,
DashboardWidget,
EditRulesPage,
ErrorDetails,
@@ -27,7 +29,6 @@ import {
LogsIndexToFields,
LogsSaveViews,
MetricsExplorer,
NewDashboardPage,
OldLogsExplorer,
Onboarding,
OnboardingV2,
@@ -159,14 +160,14 @@ const routes: AppRoutes[] = [
{
path: ROUTES.ALL_DASHBOARD,
exact: true,
component: DashboardPage,
component: DashboardsListPage,
isPrivate: true,
key: 'ALL_DASHBOARD',
},
{
path: ROUTES.DASHBOARD,
exact: true,
component: NewDashboardPage,
component: DashboardPage,
isPrivate: true,
key: 'DASHBOARD',
},
@@ -198,6 +199,13 @@ const routes: AppRoutes[] = [
isPrivate: true,
key: 'LIST_ALL_ALERT',
},
{
path: ROUTES.ALERT_TYPE_SELECTION,
exact: true,
component: AlertTypeSelectionPage,
isPrivate: true,
key: 'ALERT_TYPE_SELECTION',
},
{
path: ROUTES.ALERTS_NEW,
exact: true,

View File

@@ -16,7 +16,7 @@ import {
QueryRangePayloadV5,
} from 'types/api/v5/queryRange';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { prepareQueryRangePayloadV5 } from './prepareQueryRangePayloadV5';
@@ -41,7 +41,7 @@ describe('prepareQueryRangePayloadV5', () => {
temporality: '',
timeAggregation: 'sum',
spaceAggregation: 'avg',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
],
timeAggregation: 'sum',
@@ -62,7 +62,7 @@ describe('prepareQueryRangePayloadV5', () => {
limit: null,
stepInterval: 600,
orderBy: [],
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
legend: 'Legend A',
...overrides,
});
@@ -416,7 +416,7 @@ describe('prepareQueryRangePayloadV5', () => {
metricName: 'cpu_usage',
timeAggregation: 'sum',
spaceAggregation: 'avg',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
temporality: undefined,
}),
],
@@ -569,7 +569,7 @@ describe('prepareQueryRangePayloadV5', () => {
},
],
legend: '{{service.name}}',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
offset: 0,
pageSize: 100,
},

View File

@@ -4,7 +4,7 @@ import { getWidgetQueryBuilder } from 'container/MetricsApplication/MetricsAppli
import { getWidgetQuery } from 'pages/MessagingQueues/MQDetails/MetricPage/MetricPageUtil';
import { Widgets } from 'types/api/dashboard/getAll';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
import { v4 as uuidv4 } from 'uuid';
// dynamic step interval
@@ -57,7 +57,7 @@ export const celeryAllStateWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: getStepInterval(startTime, endTime),
timeAggregation: 'rate',
@@ -121,7 +121,7 @@ export const celeryRetryStateWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: getStepInterval(startTime, endTime),
timeAggregation: 'count',
@@ -181,7 +181,7 @@ export const celeryFailedStateWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: getStepInterval(startTime, endTime),
timeAggregation: 'rate',
@@ -241,7 +241,7 @@ export const celerySuccessStateWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: getStepInterval(startTime, endTime),
timeAggregation: 'rate',
@@ -288,7 +288,7 @@ export const celeryTasksByWorkerWidgetData = (
limit: 10,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: getStepInterval(startTime, endTime),
timeAggregation: 'rate',
@@ -351,7 +351,7 @@ export const celeryErrorByWorkerWidgetData = (
},
],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
{
dataSource: 'traces',
@@ -385,7 +385,7 @@ export const celeryErrorByWorkerWidgetData = (
},
],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
{
queryName: 'F1',
@@ -436,7 +436,7 @@ export const celeryLatencyByWorkerWidgetData = (
limit: 10,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: getStepInterval(startTime, endTime),
timeAggregation: 'p99',
@@ -485,7 +485,7 @@ export const celeryActiveTasksWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: getStepInterval(startTime, endTime),
timeAggregation: 'latest',
@@ -539,7 +539,7 @@ export const celeryTaskLatencyWidgetData = (
},
],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: getStepInterval(startTime, endTime),
timeAggregation: type || 'p99',
@@ -590,7 +590,7 @@ export const celerySlowestTasksTableWidgetData = getWidgetQueryBuilder(
},
],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -652,7 +652,7 @@ export const celeryRetryTasksTableWidgetData = getWidgetQueryBuilder(
},
],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -715,7 +715,7 @@ export const celeryFailedTasksTableWidgetData = getWidgetQueryBuilder(
},
],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -776,7 +776,7 @@ export const celerySuccessTasksTableWidgetData = getWidgetQueryBuilder(
},
],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -838,7 +838,7 @@ export const celeryTimeSeriesTablesWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -877,7 +877,7 @@ export const celeryAllStateCountWidgetData = getWidgetQueryBuilder(
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'count_distinct',
@@ -926,7 +926,7 @@ export const celerySuccessStateCountWidgetData = getWidgetQueryBuilder(
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'count_distinct',
@@ -975,7 +975,7 @@ export const celeryFailedStateCountWidgetData = getWidgetQueryBuilder(
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'count_distinct',
@@ -1024,7 +1024,7 @@ export const celeryRetryStateCountWidgetData = getWidgetQueryBuilder(
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'count_distinct',

View File

@@ -98,7 +98,20 @@ function ClientSideQBSearch(
const [isOpen, setIsOpen] = useState<boolean>(false);
// create the tags from the initial query here, this should only be computed on the first load as post that tags and query will be always in sync.
const [tags, setTags] = useState<ITag[]>(filters.items as ITag[]);
const [tags, setTags] = useState<ITag[]>(() => {
const currentTags: ITag[] = [];
filters.items.forEach((item) => {
if (item.key) {
currentTags.push({
id: item.id,
key: item.key,
op: item.op,
value: item.value,
});
}
});
return currentTags;
});
// this will maintain the current state of in process filter item
const [currentFilterItem, setCurrentFilterItem] = useState<ITag | undefined>();
@@ -143,14 +156,17 @@ function ClientSideQBSearch(
setSearchValue((parsedValue as BaseAutocompleteData)?.key);
} else if (currentState === DropdownState.OPERATOR) {
if (value === OPERATORS.EXISTS || value === OPERATORS.NOT_EXISTS) {
setTags((prev) => [
...prev,
{
key: currentFilterItem?.key,
op: value,
value: '',
} as ITag,
]);
setTags((prev) => {
const newTags = [...prev];
if (currentFilterItem?.key) {
newTags.push({
key: currentFilterItem.key,
op: value,
value: '',
});
}
return newTags;
});
setCurrentFilterItem(undefined);
setSearchValue('');
setCurrentState(DropdownState.ATTRIBUTE_KEY);
@@ -176,14 +192,17 @@ function ClientSideQBSearch(
setSearchValue('');
setCurrentState(DropdownState.ATTRIBUTE_KEY);
setCurrentFilterItem(undefined);
setTags((prev) => [
...prev,
{
key: currentFilterItem?.key,
op: currentFilterItem?.op,
value: tagValue,
} as ITag,
]);
setTags((prev) => {
const newTags = [...prev];
if (currentFilterItem?.key) {
newTags.push({
key: currentFilterItem.key,
op: currentFilterItem?.op,
value: tagValue,
});
}
return newTags;
});
return;
}
// this is for adding subsequent comma seperated values
@@ -195,14 +214,17 @@ function ClientSideQBSearch(
setSearchValue('');
setCurrentState(DropdownState.ATTRIBUTE_KEY);
setCurrentFilterItem(undefined);
setTags((prev) => [
...prev,
{
key: currentFilterItem?.key,
op: currentFilterItem?.op,
value,
} as ITag,
]);
setTags((prev) => {
const newTags = [...prev];
if (currentFilterItem?.key) {
newTags.push({
key: currentFilterItem?.key,
op: currentFilterItem?.op,
value,
});
}
return newTags;
});
}
}
},
@@ -255,14 +277,17 @@ function ClientSideQBSearch(
currentFilterItem?.op === OPERATORS.NOT_EXISTS
) {
// is exists and not exists operator is present then convert directly to tag! no need of value here
setTags((prev) => [
...prev,
{
key: currentFilterItem?.key,
op: currentFilterItem?.op,
value: '',
},
]);
setTags((prev) => {
const newTags = [...prev];
if (currentFilterItem?.key) {
newTags.push({
key: currentFilterItem.key,
op: currentFilterItem.op,
value: '',
});
}
return newTags;
});
setCurrentFilterItem(undefined);
setSearchValue('');
setCurrentState(DropdownState.ATTRIBUTE_KEY);
@@ -274,23 +299,25 @@ function ClientSideQBSearch(
: 1,
)
) {
setTags((prev) => [
...prev,
{
key: currentFilterItem?.key as BaseAutocompleteData,
op: currentFilterItem?.op as string,
value: currentFilterItem?.value || '',
},
]);
setTags((prev) => {
const newTags = [...prev];
if (currentFilterItem) {
const newTag = {
key: currentFilterItem?.key,
op: currentFilterItem?.op,
value: currentFilterItem?.value,
};
newTags.push(newTag);
}
return newTags;
});
setCurrentFilterItem(undefined);
setSearchValue('');
setCurrentState(DropdownState.ATTRIBUTE_KEY);
}
}
}, [
currentFilterItem?.key,
currentFilterItem?.op,
currentFilterItem?.value,
currentFilterItem,
searchValue,
whereClauseConfig?.customKey,
whereClauseConfig?.customOp,
@@ -321,14 +348,17 @@ function ClientSideQBSearch(
tagOperator === OPERATORS.EXISTS ||
tagOperator === OPERATORS.NOT_EXISTS
) {
setTags((prev) => [
...prev,
{
key: currentFilterItem?.key,
op: tagOperator,
value: '',
} as ITag,
]);
setTags((prev) => {
const newTags = [...prev];
if (currentFilterItem?.key) {
newTags.push({
key: currentFilterItem.key,
op: tagOperator,
value: '',
});
}
return newTags;
});
setCurrentFilterItem(undefined);
setSearchValue('');
setCurrentState(DropdownState.ATTRIBUTE_KEY);
@@ -498,12 +528,18 @@ function ClientSideQBSearch(
if (!isEqual(filters, filterTags)) {
onChange(filterTags);
setTags(
filterTags.items.map((tag) => ({
...tag,
op: getOperatorFromValue(tag.op),
})) as ITag[],
);
const newTags: ITag[] = [];
filterTags.items.forEach((tag) => {
if (tag.key) {
newTags.push({
id: tag.id,
key: tag.key,
op: getOperatorFromValue(tag.op),
value: tag.value,
});
}
});
setTags(newTags);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [tags]);

View File

@@ -6,7 +6,7 @@ import {
} from 'types/api/queryBuilder/queryAutocompleteResponse';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
import { nanoToMilli } from 'utils/timeUtils';
export const columns = [
@@ -121,7 +121,7 @@ export const getHostTracesQueryPayload = (
],
groupBy: [],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
],
queryFormulas: [],

View File

@@ -3,7 +3,7 @@ import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
import { v4 as uuidv4 } from 'uuid';
export const getHostLogsQueryPayload = (
@@ -45,7 +45,7 @@ export const getHostLogsQueryPayload = (
],
groupBy: [],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
offset: 0,
pageSize: 100,
},

View File

@@ -10,7 +10,7 @@ import {
import QueryAddOns from '../QueryV2/QueryAddOns/QueryAddOns';
import { PANEL_TYPES } from 'constants/queryBuilder';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
// Mocks: only what is required for this component to render and for us to assert handler calls
const mockHandleChangeQueryData = jest.fn();
@@ -200,7 +200,7 @@ describe('QueryAddOns', () => {
it('auto-opens reduce-to content when reduceTo is set', () => {
render(
<QueryAddOns
query={baseQuery({ reduceTo: 'sum' })}
query={baseQuery({ reduceTo: ReduceOperators.SUM })}
version="v5"
isListViewPanel={false}
showReduceTo
@@ -216,8 +216,10 @@ describe('QueryAddOns', () => {
it('calls handleSetQueryData when reduce-to value changes', async () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
const query = baseQuery({
reduceTo: 'avg',
aggregations: [{ id: 'a', operator: 'count', reduceTo: 'avg' }],
reduceTo: ReduceOperators.AVG,
aggregations: [
{ id: 'a', operator: 'count', reduceTo: ReduceOperators.AVG },
],
});
render(
<QueryAddOns
@@ -258,7 +260,7 @@ describe('QueryAddOns', () => {
aggregations: [
{
...(query.aggregations?.[0] as any),
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
},
],
});

View File

@@ -6,7 +6,7 @@ import {
DataTypes,
} from 'types/api/queryBuilder/queryAutocompleteResponse';
import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
import { extractQueryPairs } from 'utils/queryContextUtils';
import {
@@ -803,7 +803,7 @@ describe('convertAggregationToExpression', () => {
timeAggregation: 'avg',
spaceAggregation: 'max',
alias: 'test_alias',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
temporality: 'delta',
});
@@ -812,7 +812,7 @@ describe('convertAggregationToExpression', () => {
metricName: 'test_metric',
timeAggregation: 'avg',
spaceAggregation: 'max',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
temporality: 'delta',
},
]);

View File

@@ -34,7 +34,7 @@ function YAxisUnitSelector({
initialValue,
);
const currentUniversalUnitName = getUniversalNameFromMetricUnit(value);
return `Unit mismatch. Saved unit is ${initialUniversalUnitName}, but ${currentUniversalUnitName} is selected.`;
return `Unit mismatch. The metric was sent with unit ${initialUniversalUnitName}, but ${currentUniversalUnitName} is selected.`;
}
return '';
}, [initialValue, value, loading]);
@@ -82,6 +82,7 @@ function YAxisUnitSelector({
'warning-state': incompatibleUnitMessage,
})}
data-testid={dataTestId}
allowClear
>
{categories.map((category) => (
<Select.OptGroup key={category.name} label={category.name}>

View File

@@ -106,7 +106,7 @@ describe('YAxisUnitSelector', () => {
fireEvent.mouseOver(warningIcon);
return screen
.findByText(
'Unit mismatch. Saved unit is Seconds (s), but Bytes (B) is selected.',
'Unit mismatch. The metric was sent with unit Seconds (s), but Bytes (B) is selected.',
)
.then((el) => expect(el).toBeInTheDocument());
});

View File

@@ -12,4 +12,8 @@
.anticon {
color: var(--bg-amber-400) !important;
}
.ant-select-clear {
right: 28px;
}
}

View File

@@ -51,4 +51,6 @@ export enum QueryParams {
thresholds = 'thresholds',
selectedExplorerView = 'selectedExplorerView',
variables = 'variables',
version = 'version',
showNewCreateAlertsPage = 'showNewCreateAlertsPage',
}

View File

@@ -138,11 +138,11 @@ export const mapOfFormulaToFilters: Record<
};
export const REDUCE_TO_VALUES: SelectOption<ReduceOperators, string>[] = [
{ value: 'last', label: 'Latest of values in timeframe' },
{ value: 'sum', label: 'Sum of values in timeframe' },
{ value: 'avg', label: 'Average of values in timeframe' },
{ value: 'max', label: 'Max of values in timeframe' },
{ value: 'min', label: 'Min of values in timeframe' },
{ value: ReduceOperators.LAST, label: 'Latest of values in timeframe' },
{ value: ReduceOperators.SUM, label: 'Sum of values in timeframe' },
{ value: ReduceOperators.AVG, label: 'Average of values in timeframe' },
{ value: ReduceOperators.MAX, label: 'Max of values in timeframe' },
{ value: ReduceOperators.MIN, label: 'Min of values in timeframe' },
];
export const initialHavingValues: HavingForm = {
@@ -180,7 +180,7 @@ export const initialQueryBuilderFormValues: IBuilderQuery = {
temporality: '',
timeAggregation: MetricAggregateOperator.COUNT,
spaceAggregation: MetricAggregateOperator.SUM,
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
],
functions: [],
@@ -196,7 +196,7 @@ export const initialQueryBuilderFormValues: IBuilderQuery = {
orderBy: [],
groupBy: [],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
source: '',
};
@@ -228,7 +228,7 @@ export const initialQueryBuilderFormMeterValues: IBuilderQuery = {
temporality: '',
timeAggregation: MeterAggregateOperator.COUNT,
spaceAggregation: MeterAggregateOperator.SUM,
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
],
functions: [],
@@ -244,7 +244,7 @@ export const initialQueryBuilderFormMeterValues: IBuilderQuery = {
orderBy: [],
groupBy: [],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
};
export const initialQueryBuilderFormValuesMap: Record<

View File

@@ -27,6 +27,7 @@ const ROUTES = {
ALERTS_NEW: '/alerts/new',
ALERT_HISTORY: '/alerts/history',
ALERT_OVERVIEW: '/alerts/overview',
ALERT_TYPE_SELECTION: '/alerts/type-selection',
ALL_CHANNELS: '/settings/channels',
CHANNELS_NEW: '/settings/channels/new',
CHANNELS_EDIT: '/settings/channels/edit/:channelId',

View File

@@ -37,7 +37,7 @@ import {
} from 'types/api/v5/queryRange';
import { QueryData } from 'types/api/widgets/getQuery';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
import { v4 } from 'uuid';
import { domainNameKey } from './constants';
@@ -401,7 +401,7 @@ export const getDomainMetricsQueryPayload = (
orderBy: [],
groupBy: [],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
{
dataSource: DataSource.TRACES,
@@ -429,7 +429,7 @@ export const getDomainMetricsQueryPayload = (
orderBy: [],
groupBy: [],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
{
dataSource: DataSource.TRACES,
@@ -457,7 +457,7 @@ export const getDomainMetricsQueryPayload = (
orderBy: [],
groupBy: [],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
{
dataSource: DataSource.TRACES,
@@ -485,7 +485,7 @@ export const getDomainMetricsQueryPayload = (
orderBy: [],
groupBy: [],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
],
queryFormulas: [
@@ -653,7 +653,7 @@ export const getEndPointsQueryPayload = (
limit: 1000,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'count',
@@ -700,7 +700,7 @@ export const getEndPointsQueryPayload = (
limit: 1000,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'p99',
@@ -748,7 +748,7 @@ export const getEndPointsQueryPayload = (
limit: 1000,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'max',
@@ -805,7 +805,7 @@ export const getEndPointsQueryPayload = (
limit: 1000,
orderBy: [],
queryName: 'D',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'count',
@@ -1431,7 +1431,7 @@ export const getEndPointDetailsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -1461,7 +1461,7 @@ export const getEndPointDetailsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'p99',
@@ -1491,7 +1491,7 @@ export const getEndPointDetailsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'count',
@@ -1521,7 +1521,7 @@ export const getEndPointDetailsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'D',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'max',
@@ -1551,7 +1551,7 @@ export const getEndPointDetailsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'E',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'count',
@@ -1629,7 +1629,7 @@ export const getEndPointDetailsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'count',
@@ -1665,7 +1665,7 @@ export const getEndPointDetailsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'p99',
@@ -1705,7 +1705,7 @@ export const getEndPointDetailsQueryPayload = (
},
],
legend: 'rate',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
],
queryFormulas: [],
@@ -1781,7 +1781,7 @@ export const getEndPointDetailsQueryPayload = (
type: 'attribute',
},
],
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
],
queryFormulas: [],
@@ -1850,7 +1850,7 @@ export const getEndPointDetailsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'count',
@@ -1887,7 +1887,7 @@ export const getEndPointDetailsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'p99',
@@ -1924,7 +1924,7 @@ export const getEndPointDetailsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -1961,7 +1961,7 @@ export const getEndPointDetailsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'D',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'count',
@@ -2039,7 +2039,7 @@ export const getEndPointDetailsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: null,
timeAggregation: 'rate',
@@ -2110,7 +2110,7 @@ export const getEndPointDetailsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: null,
timeAggregation: 'p99',
@@ -2208,7 +2208,7 @@ export const getEndPointZeroStateQueryPayload = (
type: 'tag',
},
],
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
],
queryFormulas: [],
@@ -2787,7 +2787,7 @@ export const getStatusCodeBarChartWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -2909,7 +2909,7 @@ export const getAllEndpointsWidgetData = (
limit: 1000,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'count',
@@ -2941,7 +2941,7 @@ export const getAllEndpointsWidgetData = (
limit: 1000,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'p99',
@@ -2973,7 +2973,7 @@ export const getAllEndpointsWidgetData = (
limit: 1000,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'max',
@@ -3005,7 +3005,7 @@ export const getAllEndpointsWidgetData = (
limit: 1000,
orderBy: [],
queryName: 'D',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'count',
@@ -3191,7 +3191,7 @@ export const getRateOverTimeWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: null,
timeAggregation: 'rate',
@@ -3242,7 +3242,7 @@ export const getLatencyOverTimeWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: null,
timeAggregation: 'p99',

View File

@@ -1,24 +1,12 @@
import ROUTES from 'constants/routes';
import * as usePrefillAlertConditions from 'container/FormAlertRules/usePrefillAlertConditions';
import AlertTypeSelectionPage from 'pages/AlertTypeSelection';
import CreateAlertPage from 'pages/CreateAlert';
import { act, fireEvent, render } from 'tests/test-utils';
import { AlertTypes } from 'types/api/alerts/alertTypes';
import { ALERT_TYPE_TO_TITLE, ALERT_TYPE_URL_MAP } from './constants';
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useLocation: (): { pathname: string } => ({
pathname: `${process.env.FRONTEND_API_ENDPOINT}${ROUTES.ALERTS_NEW}`,
}),
}));
jest.mock('hooks/useSafeNavigate', () => ({
useSafeNavigate: (): any => ({
safeNavigate: jest.fn(),
}),
}));
jest
.spyOn(usePrefillAlertConditions, 'usePrefillAlertConditions')
.mockReturnValue({
@@ -66,13 +54,20 @@ describe('Alert rule documentation redirection', () => {
window.open = mockWindowOpen;
});
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useLocation: (): { pathname: string } => ({
pathname: `${process.env.FRONTEND_API_ENDPOINT}${ROUTES.ALERT_TYPE_SELECTION}`,
}),
}));
beforeEach(() => {
act(() => {
renderResult = render(
<CreateAlertPage />,
<AlertTypeSelectionPage />,
{},
{
initialRoute: ROUTES.ALERTS_NEW,
initialRoute: ROUTES.ALERT_TYPE_SELECTION,
},
);
});
@@ -117,18 +112,20 @@ describe('Alert rule documentation redirection', () => {
expect(mockWindowOpen).toHaveBeenCalledTimes(alertTypeCount);
});
});
describe('Create alert page redirection', () => {
Object.values(AlertTypes)
.filter((type) => type !== AlertTypes.ANOMALY_BASED_ALERT)
.forEach((alertType) => {
it(`should redirect to create alert page for ${alertType} and "Check an example alert" should redirect to the correct documentation`, () => {
const { getByTestId, getByRole } = renderResult;
const alertTypeLink = getByTestId(`alert-type-card-${alertType}`);
act(() => {
fireEvent.click(alertTypeLink);
});
const { getByRole } = render(
<CreateAlertPage />,
{},
{
initialRoute: `${ROUTES.ALERTS_NEW}?alertType=${alertType}`,
},
);
act(() => {
fireEvent.click(

View File

@@ -0,0 +1,131 @@
import { render, screen } from '@testing-library/react';
import { QueryParams } from 'constants/query';
import { initialQueriesMap } from 'constants/queryBuilder';
import * as useCompositeQueryParamHooks from 'hooks/queryBuilder/useGetCompositeQueryParam';
import * as useUrlQueryHooks from 'hooks/useUrlQuery';
import { AlertTypes } from 'types/api/alerts/alertTypes';
import { DataSource } from 'types/common/queryBuilder';
import CreateAlertRule from '../index';
jest.mock('container/FormAlertRules', () => ({
__esModule: true,
default: function MockFormAlertRules({
alertType,
}: {
alertType: AlertTypes;
}): JSX.Element {
return (
<div>
<h1>Form Alert Rules</h1>
<p>{alertType}</p>
</div>
);
},
AlertDetectionTypes: {
THRESHOLD_ALERT: 'threshold_rule',
ANOMALY_DETECTION_ALERT: 'anomaly_rule',
},
}));
jest.mock('container/CreateAlertV2', () => ({
__esModule: true,
default: function MockCreateAlertV2(): JSX.Element {
return <div>Create Alert V2</div>;
},
}));
const useCompositeQueryParamSpy = jest.spyOn(
useCompositeQueryParamHooks,
'useGetCompositeQueryParam',
);
const useUrlQuerySpy = jest.spyOn(useUrlQueryHooks, 'default');
const mockSetUrlQuery = jest.fn();
const mockToString = jest.fn();
const mockGetUrlQuery = jest.fn();
const FORM_ALERT_RULES_TEXT = 'Form Alert Rules';
const CREATE_ALERT_V2_TEXT = 'Create Alert V2';
describe('CreateAlertRule', () => {
beforeEach(() => {
jest.clearAllMocks();
useUrlQuerySpy.mockReturnValue(({
set: mockSetUrlQuery,
toString: mockToString,
get: mockGetUrlQuery,
} as Partial<URLSearchParams>) as URLSearchParams);
useCompositeQueryParamSpy.mockReturnValue(initialQueriesMap.metrics);
});
it('should render v1 flow when showNewCreateAlertsPage is false', () => {
mockGetUrlQuery.mockReturnValue(null);
render(<CreateAlertRule />);
expect(screen.getByText(FORM_ALERT_RULES_TEXT)).toBeInTheDocument();
});
it('should render v2 flow when showNewCreateAlertsPage is true', () => {
mockGetUrlQuery.mockImplementation((key: string) => {
if (key === QueryParams.showNewCreateAlertsPage) {
return 'true';
}
return null;
});
render(<CreateAlertRule />);
expect(screen.getByText(CREATE_ALERT_V2_TEXT)).toBeInTheDocument();
});
it('should render v1 flow when ruleType is anomaly_rule even if showNewCreateAlertsPage is true', () => {
mockGetUrlQuery.mockImplementation((key: string) => {
if (key === QueryParams.showNewCreateAlertsPage) {
return 'true';
}
if (key === QueryParams.ruleType) {
return 'anomaly_rule';
}
return null;
});
render(<CreateAlertRule />);
expect(screen.getByText(FORM_ALERT_RULES_TEXT)).toBeInTheDocument();
expect(screen.queryByText(CREATE_ALERT_V2_TEXT)).not.toBeInTheDocument();
});
it('should use alertType from URL when provided', () => {
mockGetUrlQuery.mockImplementation((key: string) => {
if (key === QueryParams.alertType) {
return AlertTypes.LOGS_BASED_ALERT;
}
return null;
});
render(<CreateAlertRule />);
expect(screen.getByText(FORM_ALERT_RULES_TEXT)).toBeInTheDocument();
expect(screen.getByText(AlertTypes.LOGS_BASED_ALERT)).toBeInTheDocument();
});
it('should use alertType from compositeQuery dataSource when alertType is not in URL', () => {
mockGetUrlQuery.mockReturnValue(null);
useCompositeQueryParamSpy.mockReturnValue({
...initialQueriesMap.metrics,
builder: {
...initialQueriesMap.metrics.builder,
queryData: [
{
...initialQueriesMap.metrics.builder.queryData[0],
dataSource: DataSource.TRACES,
},
],
},
});
render(<CreateAlertRule />);
expect(screen.getByText(FORM_ALERT_RULES_TEXT)).toBeInTheDocument();
expect(screen.getByText(AlertTypes.TRACES_BASED_ALERT)).toBeInTheDocument();
});
it('should default to METRICS_BASED_ALERT when no alertType and no compositeQuery', () => {
mockGetUrlQuery.mockReturnValue(null);
useCompositeQueryParamSpy.mockReturnValue(null);
render(<CreateAlertRule />);
expect(screen.getByText(FORM_ALERT_RULES_TEXT)).toBeInTheDocument();
expect(screen.getByText(AlertTypes.METRICS_BASED_ALERT)).toBeInTheDocument();
});
});

View File

@@ -1,133 +1,49 @@
import { Form, Row } from 'antd';
import logEvent from 'api/common/logEvent';
import { Form } from 'antd';
import { ENTITY_VERSION_V5 } from 'constants/app';
import { QueryParams } from 'constants/query';
import CreateAlertV2 from 'container/CreateAlertV2';
import FormAlertRules, { AlertDetectionTypes } from 'container/FormAlertRules';
import { ThresholdProps } from 'container/NewWidget/RightContainer/Threshold/types';
import { useGetCompositeQueryParam } from 'hooks/queryBuilder/useGetCompositeQueryParam';
import history from 'lib/history';
import { useEffect, useState } from 'react';
import { useLocation } from 'react-router-dom';
import useUrlQuery from 'hooks/useUrlQuery';
import { useMemo } from 'react';
import { AlertTypes } from 'types/api/alerts/alertTypes';
import { AlertDef } from 'types/api/alerts/def';
import { ALERT_TYPE_VS_SOURCE_MAPPING } from './config';
import {
alertDefaults,
anamolyAlertDefaults,
exceptionAlertDefaults,
logAlertDefaults,
traceAlertDefaults,
} from './defaults';
import SelectAlertType from './SelectAlertType';
import { ALERTS_VALUES_MAP } from './defaults';
function CreateRules(): JSX.Element {
const [initValues, setInitValues] = useState<AlertDef | null>(null);
const location = useLocation();
const queryParams = new URLSearchParams(location.search);
const alertTypeFromURL = queryParams.get(QueryParams.ruleType);
const version = queryParams.get('version');
const alertTypeFromParams =
alertTypeFromURL === AlertDetectionTypes.ANOMALY_DETECTION_ALERT
? AlertTypes.ANOMALY_BASED_ALERT
: queryParams.get(QueryParams.alertType);
const { thresholds } = (location.state as {
thresholds: ThresholdProps[];
}) || {
thresholds: null,
};
const compositeQuery = useGetCompositeQueryParam();
function getAlertTypeFromDataSource(): AlertTypes | null {
if (!compositeQuery) {
return null;
}
const dataSource = compositeQuery?.builder?.queryData[0]?.dataSource;
return ALERT_TYPE_VS_SOURCE_MAPPING[dataSource];
}
const [alertType, setAlertType] = useState<AlertTypes>(
(alertTypeFromParams as AlertTypes) || getAlertTypeFromDataSource(),
);
const [formInstance] = Form.useForm();
const compositeQuery = useGetCompositeQueryParam();
const queryParams = useUrlQuery();
const onSelectType = (typ: AlertTypes): void => {
setAlertType(typ);
switch (typ) {
case AlertTypes.LOGS_BASED_ALERT:
setInitValues(logAlertDefaults);
break;
case AlertTypes.TRACES_BASED_ALERT:
setInitValues(traceAlertDefaults);
break;
case AlertTypes.EXCEPTIONS_BASED_ALERT:
setInitValues(exceptionAlertDefaults);
break;
case AlertTypes.ANOMALY_BASED_ALERT:
setInitValues({
...anamolyAlertDefaults,
version: version || ENTITY_VERSION_V5,
ruleType: AlertDetectionTypes.ANOMALY_DETECTION_ALERT,
});
break;
default:
setInitValues({
...alertDefaults,
version: version || ENTITY_VERSION_V5,
ruleType: AlertDetectionTypes.THRESHOLD_ALERT,
});
}
queryParams.set(
QueryParams.alertType,
typ === AlertTypes.ANOMALY_BASED_ALERT
? AlertTypes.METRICS_BASED_ALERT
: typ,
);
if (
typ === AlertTypes.ANOMALY_BASED_ALERT ||
alertTypeFromURL === AlertDetectionTypes.ANOMALY_DETECTION_ALERT
) {
queryParams.set(
QueryParams.ruleType,
AlertDetectionTypes.ANOMALY_DETECTION_ALERT,
);
} else {
queryParams.set(QueryParams.ruleType, AlertDetectionTypes.THRESHOLD_ALERT);
}
const generatedUrl = `${location.pathname}?${queryParams.toString()}`;
history.replace(generatedUrl, {
thresholds,
});
};
useEffect(() => {
if (alertType) {
onSelectType(alertType);
} else {
logEvent('Alert: New alert data source selection page visited', {});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [alertType]);
if (!initValues) {
return (
<Row wrap={false}>
<SelectAlertType onSelect={onSelectType} />
</Row>
);
}
const ruleTypeFromURL = queryParams.get(QueryParams.ruleType);
const alertTypeFromURL = queryParams.get(QueryParams.alertType);
const version = queryParams.get(QueryParams.version);
const showNewCreateAlertsPageFlag =
queryParams.get('showNewCreateAlertsPage') === 'true';
queryParams.get(QueryParams.showNewCreateAlertsPage) === 'true';
const alertType = useMemo(() => {
if (ruleTypeFromURL === AlertDetectionTypes.ANOMALY_DETECTION_ALERT) {
return AlertTypes.ANOMALY_BASED_ALERT;
}
if (!alertTypeFromURL) {
const dataSource = compositeQuery?.builder.queryData?.[0]?.dataSource;
if (dataSource) {
return ALERT_TYPE_VS_SOURCE_MAPPING[dataSource];
}
return AlertTypes.METRICS_BASED_ALERT;
}
return alertTypeFromURL as AlertTypes;
}, [alertTypeFromURL, ruleTypeFromURL, compositeQuery?.builder.queryData]);
const initialAlertValue: AlertDef = useMemo(
() => ({
...ALERTS_VALUES_MAP[alertType],
version: version || ENTITY_VERSION_V5,
}),
[alertType, version],
);
if (
showNewCreateAlertsPageFlag &&
@@ -140,7 +56,7 @@ function CreateRules(): JSX.Element {
<FormAlertRules
alertType={alertType}
formInstance={formInstance}
initialValue={initValues}
initialValue={initialAlertValue}
ruleId=""
/>
);

View File

@@ -1,8 +1,9 @@
import { Select, Tooltip, Typography } from 'antd';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { Info } from 'lucide-react';
import { useMemo } from 'react';
import { useCallback, useMemo } from 'react';
import { ALL_SELECTED_VALUE } from '../constants';
import { useCreateAlertState } from '../context';
function MultipleNotifications(): JSX.Element {
@@ -12,6 +13,12 @@ function MultipleNotifications(): JSX.Element {
} = useCreateAlertState();
const { currentQuery } = useQueryBuilder();
const isAllOptionSelected = useMemo(
() =>
notificationSettings.multipleNotifications?.includes(ALL_SELECTED_VALUE),
[notificationSettings.multipleNotifications],
);
const spaceAggregationOptions = useMemo(() => {
const allGroupBys = currentQuery.builder.queryData?.reduce<string[]>(
(acc, query) => {
@@ -21,15 +28,60 @@ function MultipleNotifications(): JSX.Element {
[],
);
const uniqueGroupBys = [...new Set(allGroupBys)];
return uniqueGroupBys.map((key) => ({
const options = uniqueGroupBys.map((key) => ({
label: key,
value: key,
disabled: isAllOptionSelected,
'data-testid': 'multiple-notifications-select-option',
}));
}, [currentQuery.builder.queryData]);
if (options.length > 0) {
return [
{
label: 'All',
value: ALL_SELECTED_VALUE,
'data-testid': 'multiple-notifications-select-option',
},
...options,
];
}
return options;
}, [currentQuery.builder.queryData, isAllOptionSelected]);
const isMultipleNotificationsEnabled = spaceAggregationOptions.length > 0;
const onSelectChange = useCallback(
(newSelectedOptions: string[]): void => {
const currentSelectedOptions = notificationSettings.multipleNotifications;
const allOptionLastSelected =
!currentSelectedOptions?.includes(ALL_SELECTED_VALUE) &&
newSelectedOptions.includes(ALL_SELECTED_VALUE);
if (allOptionLastSelected) {
setNotificationSettings({
type: 'SET_MULTIPLE_NOTIFICATIONS',
payload: [ALL_SELECTED_VALUE],
});
} else {
setNotificationSettings({
type: 'SET_MULTIPLE_NOTIFICATIONS',
payload: newSelectedOptions,
});
}
},
[setNotificationSettings, notificationSettings.multipleNotifications],
);
const groupByDescription = useMemo(() => {
if (isAllOptionSelected) {
return 'All = grouping of alerts is disabled';
}
if (notificationSettings.multipleNotifications?.length) {
return `Alerts with same ${notificationSettings.multipleNotifications?.join(
', ',
)} will be grouped`;
}
return 'Empty = all matching alerts combined into one notification';
}, [isAllOptionSelected, notificationSettings.multipleNotifications]);
const multipleNotificationsInput = useMemo(() => {
const placeholder = isMultipleNotificationsEnabled
? 'Select fields to group by (optional)'
@@ -38,12 +90,7 @@ function MultipleNotifications(): JSX.Element {
<div>
<Select
options={spaceAggregationOptions}
onChange={(value): void => {
setNotificationSettings({
type: 'SET_MULTIPLE_NOTIFICATIONS',
payload: value,
});
}}
onChange={onSelectChange}
value={notificationSettings.multipleNotifications}
mode="multiple"
placeholder={placeholder}
@@ -54,11 +101,7 @@ function MultipleNotifications(): JSX.Element {
/>
{isMultipleNotificationsEnabled && (
<Typography.Paragraph className="multiple-notifications-select-description">
{notificationSettings.multipleNotifications?.length
? `Alerts with same ${notificationSettings.multipleNotifications?.join(
', ',
)} will be grouped`
: 'Empty = all matching alerts combined into one notification'}
{groupByDescription}
</Typography.Paragraph>
)}
</div>
@@ -72,9 +115,10 @@ function MultipleNotifications(): JSX.Element {
}
return input;
}, [
groupByDescription,
isMultipleNotificationsEnabled,
notificationSettings.multipleNotifications,
setNotificationSettings,
onSelectChange,
spaceAggregationOptions,
]);

View File

@@ -1,6 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { ALL_SELECTED_VALUE } from 'container/CreateAlertV2/constants';
import * as createAlertContext from 'container/CreateAlertV2/context';
import {
INITIAL_ALERT_THRESHOLD_STATE,
@@ -28,6 +29,7 @@ jest.mock('hooks/queryBuilder/useQueryBuilder', () => ({
}));
const TEST_QUERY = 'test-query';
const TEST_QUERY_2 = 'test-query-2';
const TEST_GROUP_BY_FIELDS = [{ key: 'service' }, { key: 'environment' }];
const TRUE = 'true';
const FALSE = 'false';
@@ -151,7 +153,7 @@ describe('MultipleNotifications', () => {
groupBy: [{ key: 'http.status_code' }],
},
{
queryName: 'test-query-2',
queryName: TEST_QUERY_2,
groupBy: [{ key: 'service' }],
},
],
@@ -167,6 +169,99 @@ describe('MultipleNotifications', () => {
expect(
screen.getByRole('option', { name: 'http.status_code' }),
).toBeInTheDocument();
expect(screen.getByRole('option', { name: 'service' })).toBeInTheDocument();
});
it('selecting the "all" option shows correct group by description', () => {
useQueryBuilder.mockReturnValue({
currentQuery: {
builder: {
queryData: [
{
queryName: TEST_QUERY_2,
groupBy: [{ key: 'service' }],
},
],
},
},
});
jest.spyOn(createAlertContext, 'useCreateAlertState').mockReturnValue(
createMockAlertContextState({
notificationSettings: {
...INITIAL_NOTIFICATION_SETTINGS_STATE,
multipleNotifications: [ALL_SELECTED_VALUE],
},
}),
);
render(<MultipleNotifications />);
expect(
screen.getByText('All = grouping of alerts is disabled'),
).toBeInTheDocument();
});
it('selecting "all" option should disable selection of other options', async () => {
useQueryBuilder.mockReturnValue({
currentQuery: {
builder: {
queryData: [
{
queryName: TEST_QUERY_2,
groupBy: [{ key: 'service' }],
},
],
},
},
});
render(<MultipleNotifications />);
const select = screen.getByRole(COMBOBOX_ROLE);
await userEvent.click(select);
const serviceOption = screen.getAllByTestId(
'multiple-notifications-select-option',
);
expect(serviceOption).toHaveLength(2);
expect(serviceOption[0]).not.toHaveClass('ant-select-item-option-disabled');
expect(serviceOption[1]).toHaveClass('ant-select-item-option-disabled');
});
it('selecting "all" option should remove all other selected options', async () => {
useQueryBuilder.mockReturnValue({
currentQuery: {
builder: {
queryData: [
{
queryName: TEST_QUERY_2,
groupBy: [{ key: 'service' }],
},
],
},
},
});
jest.spyOn(createAlertContext, 'useCreateAlertState').mockReturnValue(
createMockAlertContextState({
notificationSettings: {
...INITIAL_NOTIFICATION_SETTINGS_STATE,
multipleNotifications: ['service'],
},
setNotificationSettings: mockSetNotificationSettings,
}),
);
render(<MultipleNotifications />);
const select = screen.getByRole(COMBOBOX_ROLE);
await userEvent.click(select);
const serviceOption = screen.getAllByTestId(
'multiple-notifications-select-option',
);
expect(serviceOption).toHaveLength(2);
await userEvent.click(serviceOption[0]);
expect(mockSetNotificationSettings).toHaveBeenCalledWith({
type: 'SET_MULTIPLE_NOTIFICATIONS',
payload: [ALL_SELECTED_VALUE],
});
});
});

View File

@@ -35,24 +35,21 @@ function ChartPreview({ alertDef }: ChartPreviewProps): JSX.Element {
const yAxisUnit = alertState.yAxisUnit || '';
const fetchYAxisUnit =
const shouldUpdateYAxisUnit =
!isEditMode && alertType === AlertTypes.METRICS_BASED_ALERT;
const selectedQueryName = thresholdState.selectedQuery;
const { yAxisUnit: initialYAxisUnit, isLoading } = useGetYAxisUnit(
selectedQueryName,
{
enabled: fetchYAxisUnit,
},
);
// Every time a new metric is selected, set the y-axis unit to its unit value if present
// Only for metrics-based alerts
// Only for metrics-based alerts in create mode
useEffect(() => {
if (fetchYAxisUnit) {
if (shouldUpdateYAxisUnit) {
setAlertState({ type: 'SET_Y_AXIS_UNIT', payload: initialYAxisUnit });
}
}, [initialYAxisUnit, setAlertState, fetchYAxisUnit]);
}, [initialYAxisUnit, setAlertState, shouldUpdateYAxisUnit]);
const headline = (
<div className="chart-preview-headline">

View File

@@ -72,3 +72,5 @@ export const defaultPostableAlertRuleV2: PostableAlertRuleV2 = {
alert: 'TEST_ALERT',
evaluation: defaultEvaluation,
};
export const ALL_SELECTED_VALUE = '__all__';

View File

@@ -1,4 +1,5 @@
import { renderHook } from '@testing-library/react';
import { ReduceOperators } from 'types/common/queryBuilder';
import { usePrefillAlertConditions } from '../usePrefillAlertConditions';
@@ -55,7 +56,7 @@ const mockStagedQuery = {
builder: {
queryData: [
{
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
],
},
@@ -84,10 +85,10 @@ describe('usePrefillAlertConditions', () => {
builder: {
queryData: [
{
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
{
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
],
},
@@ -102,10 +103,10 @@ describe('usePrefillAlertConditions', () => {
builder: {
queryData: [
{
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
{
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
},
],
},

View File

@@ -6,6 +6,8 @@ import saveAlertApi from 'api/alerts/save';
import testAlertApi from 'api/alerts/testAlert';
import logEvent from 'api/common/logEvent';
import { getInvolvedQueriesInTraceOperator } from 'components/QueryBuilderV2/QueryV2/TraceOperator/utils/utils';
import YAxisUnitSelector from 'components/YAxisUnitSelector';
import { YAxisSource } from 'components/YAxisUnitSelector/types';
import { ALERTS_DATA_SOURCE_MAP } from 'constants/alerts';
import { FeatureKeys } from 'constants/features';
import { QueryParams } from 'constants/query';
@@ -14,9 +16,9 @@ import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import ROUTES from 'constants/routes';
import QueryTypeTag from 'container/NewWidget/LeftContainer/QueryTypeTag';
import PlotTag from 'container/NewWidget/LeftContainer/WidgetGraph/PlotTag';
import { BuilderUnitsFilter } from 'container/QueryBuilder/filters';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
import useGetYAxisUnit from 'hooks/useGetYAxisUnit';
import { useNotifications } from 'hooks/useNotifications';
import { useSafeNavigate } from 'hooks/useSafeNavigate';
import useUrlQuery from 'hooks/useUrlQuery';
@@ -230,16 +232,18 @@ function FormAlertRules({
};
useEffect(() => {
const ruleType =
detectionMethod === AlertDetectionTypes.ANOMALY_DETECTION_ALERT
? AlertDetectionTypes.ANOMALY_DETECTION_ALERT
: AlertDetectionTypes.THRESHOLD_ALERT;
if (detectionMethod) {
const ruleType =
detectionMethod === AlertDetectionTypes.ANOMALY_DETECTION_ALERT
? AlertDetectionTypes.ANOMALY_DETECTION_ALERT
: AlertDetectionTypes.THRESHOLD_ALERT;
queryParams.set(QueryParams.ruleType, ruleType);
queryParams.set(QueryParams.ruleType, ruleType);
const generatedUrl = `${location.pathname}?${queryParams.toString()}`;
const generatedUrl = `${location.pathname}?${queryParams.toString()}`;
safeNavigate(generatedUrl);
safeNavigate(generatedUrl);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [detectionMethod]);
@@ -481,7 +485,7 @@ function FormAlertRules({
chQueries: mapQueryDataToApi(currentQuery.clickhouse_sql, 'name').data,
queryType: currentQuery.queryType,
panelType: panelType || initQuery.panelType,
unit: currentQuery.unit,
unit: yAxisUnit,
}),
},
};
@@ -500,6 +504,7 @@ function FormAlertRules({
alertType,
initQuery,
panelType,
yAxisUnit,
]);
const saveRule = useCallback(async () => {
@@ -525,8 +530,7 @@ function FormAlertRules({
if (response.statusCode === 200) {
logData = {
status: 'success',
statusMessage:
!ruleId || isEmpty(ruleId) ? t('rule_created') : t('rule_edited'),
statusMessage: isNewRule ? t('rule_created') : t('rule_edited'),
};
notifications.success({
@@ -578,7 +582,7 @@ function FormAlertRules({
dataSource: ALERTS_DATA_SOURCE_MAP[postableAlert?.alertType as AlertTypes],
channelNames: postableAlert?.preferredChannels,
broadcastToAll: postableAlert?.broadcastToAll,
isNewRule: !ruleId || isEmpty(ruleId),
isNewRule,
ruleId,
queryType: currentQuery.queryType,
alertId: postableAlert?.id,
@@ -663,7 +667,7 @@ function FormAlertRules({
dataSource: ALERTS_DATA_SOURCE_MAP[alertDef?.alertType as AlertTypes],
channelNames: postableAlert?.preferredChannels,
broadcastToAll: postableAlert?.broadcastToAll,
isNewRule: !ruleId || isEmpty(ruleId),
isNewRule,
ruleId,
queryType: currentQuery.queryType,
status: statusResponse.status,
@@ -735,8 +739,6 @@ function FormAlertRules({
alertDef?.broadcastToAll ||
(alertDef.preferredChannels && alertDef.preferredChannels.length > 0);
const isRuleCreated = !ruleId || isEmpty(ruleId);
function handleRedirection(option: AlertTypes): void {
let url;
if (
@@ -751,7 +753,7 @@ function FormAlertRules({
if (url) {
logEvent('Alert: Check example alert clicked', {
dataSource: ALERTS_DATA_SOURCE_MAP[alertDef?.alertType as AlertTypes],
isNewRule: !ruleId || isEmpty(ruleId),
isNewRule,
ruleId,
queryType: currentQuery.queryType,
link: url,
@@ -761,7 +763,7 @@ function FormAlertRules({
}
useEffect(() => {
if (!isRuleCreated) {
if (!isNewRule) {
logEvent('Alert: Edit page visited', {
ruleId,
dataSource: ALERTS_DATA_SOURCE_MAP[alertType as AlertTypes],
@@ -786,6 +788,24 @@ function FormAlertRules({
featureFlags?.find((flag) => flag.name === FeatureKeys.ANOMALY_DETECTION)
?.active || false;
// Only update automatically when creating a new metrics-based alert rule
const shouldUpdateYAxisUnit = useMemo(
() => isNewRule && alertType === AlertTypes.METRICS_BASED_ALERT,
[isNewRule, alertType],
);
const { yAxisUnit: initialYAxisUnit, isLoading } = useGetYAxisUnit(
alertDef.condition.selectedQueryName,
);
// Every time a new metric is selected, set the y-axis unit to its unit
// Only for metrics-based alerts in create mode
useEffect(() => {
if (shouldUpdateYAxisUnit) {
setYAxisUnit(initialYAxisUnit || '');
}
}, [initialYAxisUnit, shouldUpdateYAxisUnit]);
return (
<>
{Element}
@@ -793,7 +813,7 @@ function FormAlertRules({
<div
id="top"
className={`form-alert-rules-container ${
isRuleCreated ? 'create-mode' : 'edit-mode'
isNewRule ? 'create-mode' : 'edit-mode'
}`}
>
<div className="overview-header">
@@ -841,9 +861,12 @@ function FormAlertRules({
</div>
<StepContainer>
<BuilderUnitsFilter
<YAxisUnitSelector
value={yAxisUnit}
initialValue={initialYAxisUnit}
onChange={onUnitChangeHandler}
yAxisUnit={yAxisUnit}
source={YAxisSource.ALERTS}
loading={isLoading}
/>
</StepContainer>
@@ -921,7 +944,7 @@ function FormAlertRules({
type="default"
onClick={onCancelHandler}
>
{(!ruleId || isEmpty(ruleId)) && t('button_cancelchanges')}
{isNewRule && t('button_cancelchanges')}
{ruleId && !isEmpty(ruleId) && t('button_discard')}
</ActionButton>
</ButtonContainer>

View File

@@ -8,7 +8,7 @@ import { Provider } from 'react-redux';
import store from 'store';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
import {
MENUITEM_KEYS_VS_LABELS,
@@ -68,7 +68,7 @@ const mockProps: WidgetGraphComponentProps = {
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'count_distinct',

View File

@@ -1,6 +1,6 @@
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
import { getBarStepIntervalPoints, updateBarStepInterval } from '../utils';
@@ -126,7 +126,7 @@ describe('GridCardLayout Utils', () => {
limit: null,
offset: 0,
pageSize: 0,
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
legend: '',
},
],

View File

@@ -1,3 +1,5 @@
import { ReduceOperators } from 'types/common/queryBuilder';
/* eslint-disable sonarjs/no-duplicate-string */
export const tableDataMultipleQueriesSuccessResponse = {
columns: [
@@ -131,7 +133,7 @@ export const widgetQueryWithLegend = {
},
],
legend: 'p99',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
{
dataSource: 'metrics',
@@ -158,7 +160,7 @@ export const widgetQueryWithLegend = {
orderBy: [],
groupBy: [],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
],
queryFormulas: [],
@@ -374,7 +376,7 @@ export const widgetQueryQBv5MultiAggregations = {
},
],
legend: 'p99',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
{
dataSource: 'metrics',
@@ -414,7 +416,7 @@ export const widgetQueryQBv5MultiAggregations = {
},
],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
{
dataSource: 'metrics',
@@ -454,7 +456,7 @@ export const widgetQueryQBv5MultiAggregations = {
},
],
legend: 'max',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
],
queryFormulas: [],

View File

@@ -4,7 +4,7 @@ import { PANEL_TYPES } from 'constants/queryBuilder';
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
import { v4 } from 'uuid';
export const clusterWidgetInfo = [
@@ -177,7 +177,7 @@ export const getClusterMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -216,7 +216,7 @@ export const getClusterMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'min',
@@ -255,7 +255,7 @@ export const getClusterMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'max',
@@ -294,7 +294,7 @@ export const getClusterMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'D',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -367,7 +367,7 @@ export const getClusterMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -406,7 +406,7 @@ export const getClusterMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'min',
@@ -445,7 +445,7 @@ export const getClusterMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'max',
@@ -484,7 +484,7 @@ export const getClusterMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'D',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -570,7 +570,7 @@ export const getClusterMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'max',
stepInterval: 60,
timeAggregation: 'latest',
@@ -656,7 +656,7 @@ export const getClusterMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'max',
stepInterval: 60,
timeAggregation: 'latest',
@@ -742,7 +742,7 @@ export const getClusterMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'latest',
@@ -794,7 +794,7 @@ export const getClusterMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -892,7 +892,7 @@ export const getClusterMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'max',
@@ -944,7 +944,7 @@ export const getClusterMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'max',
@@ -996,7 +996,7 @@ export const getClusterMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'max',
@@ -1048,7 +1048,7 @@ export const getClusterMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'D',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'max',
@@ -1164,7 +1164,7 @@ export const getClusterMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1210,7 +1210,7 @@ export const getClusterMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1256,7 +1256,7 @@ export const getClusterMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1366,7 +1366,7 @@ export const getClusterMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'max',
@@ -1418,7 +1418,7 @@ export const getClusterMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'max',
@@ -1470,7 +1470,7 @@ export const getClusterMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'max',
@@ -1522,7 +1522,7 @@ export const getClusterMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'D',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'max',

View File

@@ -4,7 +4,7 @@ import { PANEL_TYPES } from 'constants/queryBuilder';
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
import { v4 } from 'uuid';
export const daemonSetWidgetInfo = [
@@ -126,7 +126,7 @@ export const getDaemonSetMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -176,7 +176,7 @@ export const getDaemonSetMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -226,7 +226,7 @@ export const getDaemonSetMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -310,7 +310,7 @@ export const getDaemonSetMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -360,7 +360,7 @@ export const getDaemonSetMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -410,7 +410,7 @@ export const getDaemonSetMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -507,7 +507,7 @@ export const getDaemonSetMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -604,7 +604,7 @@ export const getDaemonSetMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'increase',

View File

@@ -4,7 +4,7 @@ import { PANEL_TYPES } from 'constants/queryBuilder';
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
import { v4 } from 'uuid';
export const deploymentWidgetInfo = [
@@ -111,7 +111,7 @@ export const getDeploymentMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -150,7 +150,7 @@ export const getDeploymentMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -189,7 +189,7 @@ export const getDeploymentMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -262,7 +262,7 @@ export const getDeploymentMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -301,7 +301,7 @@ export const getDeploymentMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -340,7 +340,7 @@ export const getDeploymentMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -426,7 +426,7 @@ export const getDeploymentMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -512,7 +512,7 @@ export const getDeploymentMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'increase',

View File

@@ -12,7 +12,7 @@ import {
TagFilterItem,
} from 'types/api/queryBuilder/queryBuilderData';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
import { nanoToMilli } from 'utils/timeUtils';
import { v4 as uuidv4 } from 'uuid';
@@ -73,7 +73,7 @@ export const getEntityEventsOrLogsQueryPayload = (
],
groupBy: [],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
offset: 0,
pageSize: 100,
},
@@ -223,7 +223,7 @@ export const getEntityTracesQueryPayload = (
],
groupBy: [],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
],
queryFormulas: [],

View File

@@ -4,7 +4,7 @@ import { PANEL_TYPES } from 'constants/queryBuilder';
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
import { v4 } from 'uuid';
export const jobWidgetInfo = [
@@ -101,7 +101,7 @@ export const getJobMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -185,7 +185,7 @@ export const getJobMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -282,7 +282,7 @@ export const getJobMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -379,7 +379,7 @@ export const getJobMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'increase',

View File

@@ -4,7 +4,7 @@ import { PANEL_TYPES } from 'constants/queryBuilder';
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
import { v4 } from 'uuid';
export const namespaceWidgetInfo = [
@@ -185,7 +185,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -224,7 +224,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'latest',
@@ -263,7 +263,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'min',
@@ -302,7 +302,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'D',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'max',
@@ -375,7 +375,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -414,7 +414,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'latest',
@@ -453,7 +453,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -492,7 +492,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'D',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -531,7 +531,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'E',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'min',
@@ -570,7 +570,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'F',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'max',
@@ -650,7 +650,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: 20,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -730,7 +730,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: 10,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -816,7 +816,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -902,7 +902,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'increase',
@@ -982,7 +982,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'max',
stepInterval: 60,
timeAggregation: 'latest',
@@ -1028,7 +1028,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'max',
stepInterval: 60,
timeAggregation: 'latest',
@@ -1074,7 +1074,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'max',
stepInterval: 60,
timeAggregation: 'latest',
@@ -1160,7 +1160,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'max',
stepInterval: 60,
timeAggregation: 'latest',
@@ -1212,7 +1212,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'max',
stepInterval: 60,
timeAggregation: 'latest',
@@ -1292,7 +1292,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'max',
stepInterval: 60,
timeAggregation: 'latest',
@@ -1338,7 +1338,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'max',
stepInterval: 60,
timeAggregation: 'latest',
@@ -1384,7 +1384,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'max',
stepInterval: 60,
timeAggregation: 'latest',
@@ -1430,7 +1430,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'D',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'max',
stepInterval: 60,
timeAggregation: 'latest',
@@ -1510,7 +1510,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'max',
stepInterval: 60,
timeAggregation: 'latest',
@@ -1556,7 +1556,7 @@ export const getNamespaceMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'last',
reduceTo: ReduceOperators.LAST,
spaceAggregation: 'max',
stepInterval: 60,
timeAggregation: 'avg',

View File

@@ -4,7 +4,7 @@ import { PANEL_TYPES } from 'constants/queryBuilder';
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
import { v4 } from 'uuid';
export const nodeWidgetInfo = [
@@ -178,7 +178,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -217,7 +217,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'max',
stepInterval: 60,
timeAggregation: 'latest',
@@ -256,7 +256,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'latest',
@@ -295,7 +295,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'D',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'max',
@@ -334,7 +334,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'E',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'min',
@@ -407,7 +407,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -446,7 +446,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'max',
stepInterval: 60,
timeAggregation: 'latest',
@@ -485,7 +485,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'latest',
@@ -524,7 +524,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'D',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'max',
@@ -563,7 +563,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'E',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'min',
@@ -602,7 +602,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'F',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -641,7 +641,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'G',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -714,7 +714,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -753,7 +753,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'max',
stepInterval: 60,
timeAggregation: 'latest',
@@ -792,7 +792,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'latest',
@@ -878,7 +878,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -917,7 +917,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'max',
stepInterval: 60,
timeAggregation: 'latest',
@@ -956,7 +956,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'latest',
@@ -1049,7 +1049,7 @@ export const getNodeMetricsQueryPayload = (
limit: 10,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1129,7 +1129,7 @@ export const getNodeMetricsQueryPayload = (
limit: 10,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1215,7 +1215,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'increase',
@@ -1301,7 +1301,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -1374,7 +1374,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1413,7 +1413,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1452,7 +1452,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1525,7 +1525,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1564,7 +1564,7 @@ export const getNodeMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',

View File

@@ -4,7 +4,7 @@ import { PANEL_TYPES } from 'constants/queryBuilder';
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
import { v4 } from 'uuid';
export const podWidgetInfo = [
@@ -228,7 +228,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -278,7 +278,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'max',
@@ -328,7 +328,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'min',
@@ -412,7 +412,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -462,7 +462,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -512,7 +512,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'max',
@@ -562,7 +562,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'D',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'min',
@@ -612,7 +612,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'E',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'max',
@@ -662,7 +662,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'F',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'min',
@@ -746,7 +746,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -796,7 +796,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'max',
@@ -846,7 +846,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'min',
@@ -930,7 +930,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -980,7 +980,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1030,7 +1030,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'max',
@@ -1080,7 +1080,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'D',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'max',
@@ -1130,7 +1130,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'E',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'min',
@@ -1180,7 +1180,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'F',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'min',
@@ -1264,7 +1264,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1314,7 +1314,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1405,7 +1405,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1496,7 +1496,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1587,7 +1587,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1644,7 +1644,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'max',
stepInterval: 60,
timeAggregation: 'latest',
@@ -1701,7 +1701,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'max',
stepInterval: 60,
timeAggregation: 'latest',
@@ -1805,7 +1805,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1862,7 +1862,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1919,7 +1919,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -2010,7 +2010,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -2067,7 +2067,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'max',
stepInterval: 60,
timeAggregation: 'latest',
@@ -2124,7 +2124,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'max',
stepInterval: 60,
timeAggregation: 'latest',
@@ -2234,7 +2234,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -2331,7 +2331,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'increase',
@@ -2415,7 +2415,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -2465,7 +2465,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -2515,7 +2515,7 @@ export const getPodMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',

View File

@@ -4,7 +4,7 @@ import { PANEL_TYPES } from 'constants/queryBuilder';
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
import { v4 } from 'uuid';
export const statefulSetWidgetInfo = [
@@ -139,7 +139,7 @@ export const getStatefulSetMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -189,7 +189,7 @@ export const getStatefulSetMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'latest',
@@ -239,7 +239,7 @@ export const getStatefulSetMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'latest',
@@ -309,7 +309,7 @@ export const getStatefulSetMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',
@@ -359,7 +359,7 @@ export const getStatefulSetMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',
@@ -429,7 +429,7 @@ export const getStatefulSetMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -479,7 +479,7 @@ export const getStatefulSetMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'latest',
@@ -529,7 +529,7 @@ export const getStatefulSetMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'latest',
@@ -599,7 +599,7 @@ export const getStatefulSetMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',
@@ -649,7 +649,7 @@ export const getStatefulSetMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',
@@ -732,7 +732,7 @@ export const getStatefulSetMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -815,7 +815,7 @@ export const getStatefulSetMetricsQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'increase',

View File

@@ -4,7 +4,7 @@ import { PANEL_TYPES } from 'constants/queryBuilder';
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
import { v4 } from 'uuid';
export const volumeWidgetInfo = [
@@ -141,7 +141,7 @@ export const getVolumeQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -233,7 +233,7 @@ export const getVolumeQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -324,7 +324,7 @@ export const getVolumeQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -416,7 +416,7 @@ export const getVolumeQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -508,7 +508,7 @@ export const getVolumeQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',

View File

@@ -29,8 +29,8 @@ import useComponentPermission from 'hooks/useComponentPermission';
import useDebouncedFn from 'hooks/useDebouncedFunction';
import useInterval from 'hooks/useInterval';
import { useNotifications } from 'hooks/useNotifications';
import { useSafeNavigate } from 'hooks/useSafeNavigate';
import useUrlQuery from 'hooks/useUrlQuery';
import history from 'lib/history';
import { mapQueryDataFromApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataFromApi';
import { useAppContext } from 'providers/App/App';
import { useCallback, useState } from 'react';
@@ -50,6 +50,7 @@ const { Search } = Input;
function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
const { t } = useTranslation('common');
const { safeNavigate } = useSafeNavigate();
const { user } = useAppContext();
const [addNewAlert, action] = useComponentPermission(
['add_new_alert', 'action'],
@@ -112,7 +113,8 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
number: allAlertRules?.length,
layout: 'new',
});
history.push(`${ROUTES.ALERTS_NEW}?showNewCreateAlertsPage=true`);
params.set(QueryParams.showNewCreateAlertsPage, 'true');
safeNavigate(`${ROUTES.ALERT_TYPE_SELECTION}?${params.toString()}`);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
@@ -121,7 +123,7 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
number: allAlertRules?.length,
layout: 'classic',
});
history.push(ROUTES.ALERTS_NEW);
safeNavigate(ROUTES.ALERT_TYPE_SELECTION);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
@@ -161,7 +163,7 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
if (openInNewTab) {
window.open(`${ROUTES.ALERT_OVERVIEW}?${params.toString()}`, '_blank');
} else {
history.push(`${ROUTES.ALERT_OVERVIEW}?${params.toString()}`);
safeNavigate(`${ROUTES.ALERT_OVERVIEW}?${params.toString()}`);
}
};
@@ -190,7 +192,7 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
setTimeout(() => {
const clonedAlert = refetchData.payload[refetchData.payload.length - 1];
params.set(QueryParams.ruleId, String(clonedAlert.id));
history.push(`${ROUTES.EDIT_ALERTS}?${params.toString()}`);
safeNavigate(`${ROUTES.EDIT_ALERTS}?${params.toString()}`);
}, 2000);
}
if (status === 'error') {

View File

@@ -5,7 +5,7 @@ import {
} from 'types/api/queryBuilder/queryAutocompleteResponse';
import { Query, TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
export const mockLog: ILog = {
id: 'test-log-id',
@@ -54,7 +54,7 @@ export const mockQuery: Query = {
op: 'AND',
},
expression: 'A',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
},
],
queryFormulas: [],

View File

@@ -3,7 +3,7 @@ import { PANEL_TYPES } from 'constants/queryBuilder';
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
export const getPodQueryPayload = (
clusterName: string,
@@ -114,7 +114,7 @@ export const getPodQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -191,7 +191,7 @@ export const getPodQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -268,7 +268,7 @@ export const getPodQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -325,7 +325,7 @@ export const getPodQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'latest',
@@ -409,7 +409,7 @@ export const getPodQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -466,7 +466,7 @@ export const getPodQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'latest',
@@ -553,7 +553,7 @@ export const getPodQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -614,7 +614,7 @@ export const getPodQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'latest',
@@ -702,7 +702,7 @@ export const getPodQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -763,7 +763,7 @@ export const getPodQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'latest',
@@ -851,7 +851,7 @@ export const getPodQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -912,7 +912,7 @@ export const getPodQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1001,7 +1001,7 @@ export const getPodQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -1122,7 +1122,7 @@ export const getNodeQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -1171,7 +1171,7 @@ export const getNodeQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1260,7 +1260,7 @@ export const getNodeQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1309,7 +1309,7 @@ export const getNodeQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1412,7 +1412,7 @@ export const getNodeQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -1493,7 +1493,7 @@ export const getNodeQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1554,7 +1554,7 @@ export const getNodeQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1675,7 +1675,7 @@ export const getHostQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -1716,7 +1716,7 @@ export const getHostQueryPayload = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -1792,7 +1792,7 @@ export const getHostQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1853,7 +1853,7 @@ export const getHostQueryPayload = (
limit: 30,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1894,7 +1894,7 @@ export const getHostQueryPayload = (
limit: 30,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1935,7 +1935,7 @@ export const getHostQueryPayload = (
limit: 30,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -2017,7 +2017,7 @@ export const getHostQueryPayload = (
limit: 30,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -2093,7 +2093,7 @@ export const getHostQueryPayload = (
limit: 30,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -2169,7 +2169,7 @@ export const getHostQueryPayload = (
limit: 30,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -2245,7 +2245,7 @@ export const getHostQueryPayload = (
limit: 30,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -2321,7 +2321,7 @@ export const getHostQueryPayload = (
limit: 30,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
@@ -2382,7 +2382,7 @@ export const getHostQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -2464,7 +2464,7 @@ export const getHostQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -2539,7 +2539,7 @@ export const getHostQueryPayload = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'max',

View File

@@ -6,7 +6,11 @@ import { cleanup, render, screen, waitFor } from 'tests/test-utils';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { Query, QueryState } from 'types/api/queryBuilder/queryBuilderData';
import { EQueryType } from 'types/common/dashboard';
import { DataSource, QueryBuilderContextType } from 'types/common/queryBuilder';
import {
DataSource,
QueryBuilderContextType,
ReduceOperators,
} from 'types/common/queryBuilder';
import { explorerViewToPanelType } from 'utils/explorerUtils';
import LogExplorerQuerySection from './index';
@@ -166,7 +170,7 @@ const createMockQuery = (filterExpression?: string): Query => ({
orderBy: [{ columnName: 'timestamp', order: 'desc' }],
pageSize: 0,
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
stepInterval: 60,
},
],

View File

@@ -66,7 +66,7 @@ describe('useInitialQuery - Priority-Based Resource Filtering', () => {
queryName: 'A',
expression: 'A',
disabled: false,
reduceTo: 'avg' as ReduceOperators,
reduceTo: ReduceOperators.AVG,
legend: '',
},
],

View File

@@ -7,7 +7,7 @@ import {
IBuilderQuery,
} from 'types/api/queryBuilder/queryBuilderData';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
import { v4 as uuid } from 'uuid';
interface GetWidgetQueryProps {
@@ -101,7 +101,7 @@ export const getTotalLogSizeWidgetData = (): Widgets =>
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'increase',
@@ -138,7 +138,7 @@ export const getTotalTraceSizeWidgetData = (): Widgets =>
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'increase',
@@ -175,7 +175,7 @@ export const getTotalMetricDatapointCountWidgetData = (): Widgets =>
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'increase',
@@ -212,7 +212,7 @@ export const getLogCountWidgetData = (): Widgets =>
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'increase',
@@ -249,7 +249,7 @@ export const getLogSizeWidgetData = (): Widgets =>
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'increase',
@@ -286,7 +286,7 @@ export const getSpanCountWidgetData = (): Widgets =>
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'increase',
@@ -323,7 +323,7 @@ export const getSpanSizeWidgetData = (): Widgets =>
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'increase',
@@ -360,7 +360,7 @@ export const getMetricCountWidgetData = (): Widgets =>
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'increase',

View File

@@ -9,6 +9,7 @@ import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
import {
MetricAggregateOperator,
QueryBuilderData,
ReduceOperators,
Temporality,
} from 'types/common/queryBuilder';
@@ -51,7 +52,7 @@ export const getQueryBuilderQueries = ({
items: filterItems[index],
op: 'AND',
},
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: spaceAggregateOperators[index],
timeAggregation: timeAggregateOperators[index],
dataSource,
@@ -95,7 +96,7 @@ export const getQueryBuilderQuerieswithFormula = ({
aggregateAttribute: autocompleteData[index],
queryName: alphabet[index],
expression: alphabet[index],
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
filters: {
items: additionalItems[index],
op: 'AND',

View File

@@ -4,7 +4,7 @@ import { SpaceAggregation, TimeAggregation } from 'api/v5/v5';
import { initialQueriesMap } from 'constants/queryBuilder';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
export function formatTimestampToReadableDate(timestamp: string): string {
const date = new Date(timestamp);
@@ -114,7 +114,7 @@ export function getMetricDetailsQuery(
metricName,
timeAggregation: timeAggregation as TimeAggregation,
spaceAggregation: spaceAggregation as SpaceAggregation,
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
temporality: '',
},
],

View File

@@ -3,7 +3,7 @@ import { useFullScreenHandle } from 'react-full-screen';
import Description from './DashboardDescription';
import GridGraphs from './GridGraphs';
function NewDashboard(): JSX.Element {
function DashboardContainer(): JSX.Element {
const handle = useFullScreenHandle();
return (
<div>
@@ -13,4 +13,4 @@ function NewDashboard(): JSX.Element {
);
}
export default NewDashboard;
export default DashboardContainer;

View File

@@ -20,6 +20,16 @@
width: 32px;
}
}
.y-axis-unit-selector-v2 {
flex-direction: row !important;
align-items: center;
gap: 24px !important;
.y-axis-unit-selector-component {
width: 100%;
}
}
}
.lightMode {

View File

@@ -7,18 +7,19 @@ import { isEmpty } from 'lodash-es';
import { Dispatch, SetStateAction, useCallback, useEffect } from 'react';
import { ColumnUnit } from 'types/api/dashboard/getAll';
import YAxisUnitSelector from '../YAxisUnitSelector';
import YAxisUnitSelectorV2 from '../DashboardYAxisUnitSelectorWrapper';
interface ColumnUnitSelectorProps {
columnUnits: ColumnUnit;
setColumnUnits: Dispatch<SetStateAction<ColumnUnit>>;
isNewDashboard: boolean;
}
export function ColumnUnitSelector(
props: ColumnUnitSelectorProps,
): JSX.Element {
const { currentQuery } = useQueryBuilder();
const { columnUnits, setColumnUnits } = props;
const { columnUnits, setColumnUnits, isNewDashboard } = props;
const aggregationQueries = useGetQueryLabels(currentQuery);
@@ -71,19 +72,22 @@ export function ColumnUnitSelector(
return (
<section className="column-unit-selector">
<Typography.Text className="heading">Column Units</Typography.Text>
{aggregationQueries.map(({ value, label }) => (
<YAxisUnitSelector
value={columnUnits[value] || ''}
onSelect={(unitValue: string): void =>
handleColumnUnitSelect(value, unitValue)
}
fieldLabel={label}
key={value}
handleClear={(): void => {
handleColumnUnitSelect(value, '');
}}
/>
))}
{aggregationQueries.map(({ value, label }) => {
const baseQueryName = value.split('.')[0];
return (
<YAxisUnitSelectorV2
value={columnUnits[value] || ''}
onSelect={(unitValue: string): void =>
handleColumnUnitSelect(value, unitValue)
}
fieldLabel={label}
key={value}
selectedQueryName={baseQueryName}
// Update the column unit value automatically only in create mode
shouldUpdateYAxisUnit={isNewDashboard}
/>
);
})}
</section>
);
}

View File

@@ -3,6 +3,7 @@ import { QueryBuilderProvider } from 'providers/QueryBuilder';
import { useLocation } from 'react-router-dom';
import { render } from 'tests/test-utils';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { ReduceOperators } from 'types/common/queryBuilder';
import { ColumnUnitSelector } from '../ColumnUnitSelector';
@@ -42,7 +43,7 @@ const compositeQueryParam = {
},
],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
],
queryFormulas: [
@@ -98,7 +99,12 @@ describe('Column unit selector panel unit test', () => {
(useLocation as jest.Mock).mockReturnValue(mockLocation);
const { getByText } = render(
<QueryBuilderProvider>
<ColumnUnitSelector columnUnits={{}} setColumnUnits={(): void => {}} />,
<ColumnUnitSelector
columnUnits={{}}
setColumnUnits={(): void => {}}
isNewDashboard={false}
/>
,
</QueryBuilderProvider>,
);

View File

@@ -0,0 +1,54 @@
import { Typography } from 'antd';
import YAxisUnitSelectorComponent from 'components/YAxisUnitSelector';
import { YAxisSource } from 'components/YAxisUnitSelector/types';
import useGetYAxisUnit from 'hooks/useGetYAxisUnit';
import { Dispatch, SetStateAction, useEffect } from 'react';
type OnSelectType = Dispatch<SetStateAction<string>> | ((val: string) => void);
/**
* Wrapper component for the y-axis unit selector for dashboards.
*/
function DashboardYAxisUnitSelectorWrapper({
value,
onSelect,
fieldLabel,
shouldUpdateYAxisUnit,
selectedQueryName,
}: {
value: string;
onSelect: OnSelectType;
fieldLabel: string;
shouldUpdateYAxisUnit: boolean;
selectedQueryName?: string;
}): JSX.Element {
const { yAxisUnit: initialYAxisUnit, isLoading } = useGetYAxisUnit(
selectedQueryName,
);
useEffect(() => {
if (shouldUpdateYAxisUnit) {
onSelect(initialYAxisUnit || '');
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [initialYAxisUnit, shouldUpdateYAxisUnit]);
return (
<div className="y-axis-unit-selector-v2">
<Typography.Text className="heading">{fieldLabel}</Typography.Text>
<YAxisUnitSelectorComponent
value={value}
onChange={onSelect}
initialValue={initialYAxisUnit}
source={YAxisSource.DASHBOARDS}
loading={isLoading}
/>
</div>
);
}
DashboardYAxisUnitSelectorWrapper.defaultProps = {
selectedQueryName: undefined,
};
export default DashboardYAxisUnitSelectorWrapper;

View File

@@ -191,7 +191,8 @@
text-transform: uppercase;
}
.y-axis-unit-selector {
.y-axis-unit-selector,
.y-axis-unit-selector-v2 {
margin-top: 16px;
display: flex;
flex-direction: column;
@@ -224,6 +225,21 @@
}
}
}
.y-axis-unit-selector-v2 {
.y-axis-unit-selector-component {
.ant-select {
width: 100%;
border-radius: 2px;
.ant-select-selector {
border: 1px solid var(--bg-slate-400);
background: var(--bg-ink-300);
}
}
}
}
.soft-min-max {
display: flex;
align-items: center;
@@ -444,6 +460,17 @@
}
}
.y-axis-unit-selector-v2 {
.y-axis-unit-selector-component {
.ant-select {
.ant-select-selector {
border: 1px solid var(--bg-vanilla-300);
background: var(--bg-vanilla-300);
}
}
}
}
.fill-gaps {
border: 1px solid var(--bg-vanilla-300);
background: var(--bg-vanilla-300);
@@ -472,7 +499,8 @@
color: var(--bg-ink-400);
}
.y-axis-unit-selector {
.y-axis-unit-selector,
.y-axis-unit-selector-v2 {
.heading {
color: var(--bg-ink-400);
}

View File

@@ -15,6 +15,9 @@ const findCategoryByName = (
type OnSelectType = Dispatch<SetStateAction<string>> | ((val: string) => void);
/**
* @deprecated Use DashboardYAxisUnitSelectorWrapper instead.
*/
function YAxisUnitSelector({
value,
onSelect,

View File

@@ -0,0 +1,79 @@
import { render, screen } from '@testing-library/react';
import { UniversalYAxisUnit } from 'components/YAxisUnitSelector/types';
import * as getYAxisUnitHooks from 'hooks/useGetYAxisUnit';
import DashboardYAxisUnitSelectorWrapper from '../DashboardYAxisUnitSelectorWrapper';
describe('YAxisUnitSelectorV2', () => {
const mockUseGetYAxisUnit = jest.spyOn(getYAxisUnitHooks, 'default');
const onSelect = jest.fn();
beforeEach(() => {
jest.clearAllMocks();
mockUseGetYAxisUnit.mockReturnValue({
yAxisUnit: UniversalYAxisUnit.BYTES,
isLoading: false,
isError: false,
});
});
it('should render the selector with correct label and value', () => {
render(
<DashboardYAxisUnitSelectorWrapper
value={UniversalYAxisUnit.BYTES}
onSelect={onSelect}
fieldLabel="Bytes label"
shouldUpdateYAxisUnit={false}
/>,
);
expect(screen.getByText('Bytes label')).toBeInTheDocument();
expect(screen.getByText('Bytes (B)')).toBeInTheDocument();
});
it('should call onSelect when showWarning is true and useGetYAxisUnit is called and provides the correct value', () => {
mockUseGetYAxisUnit.mockReturnValueOnce({
yAxisUnit: UniversalYAxisUnit.SECONDS,
isLoading: false,
isError: false,
});
render(
<DashboardYAxisUnitSelectorWrapper
value={UniversalYAxisUnit.BYTES}
onSelect={onSelect}
fieldLabel="Bytes label"
shouldUpdateYAxisUnit
/>,
);
expect(onSelect).toHaveBeenCalledWith(UniversalYAxisUnit.SECONDS);
});
it('should not call onSelect when showWarning is false', () => {
render(
<DashboardYAxisUnitSelectorWrapper
value={UniversalYAxisUnit.BYTES}
onSelect={onSelect}
fieldLabel="Bytes label"
shouldUpdateYAxisUnit={false}
/>,
);
expect(onSelect).not.toHaveBeenCalled();
});
it('should call onSelect when yAxisUnit is undefined even if showWarning is true', () => {
mockUseGetYAxisUnit.mockReturnValueOnce({
yAxisUnit: undefined,
isLoading: false,
isError: false,
});
render(
<DashboardYAxisUnitSelectorWrapper
value={UniversalYAxisUnit.BYTES}
onSelect={onSelect}
fieldLabel="Bytes label"
shouldUpdateYAxisUnit
/>,
);
expect(onSelect).toHaveBeenCalledWith('');
});
});

View File

@@ -168,6 +168,7 @@ describe('RightContainer - Alerts Section', () => {
contextLinks: { linksData: [] },
setContextLinks: jest.fn(),
enableDrillDown: false,
isNewDashboard: false,
};
beforeEach(() => {

View File

@@ -67,11 +67,11 @@ import {
panelTypeVsYAxisUnit,
} from './constants';
import ContextLinks from './ContextLinks';
import DashboardYAxisUnitSelectorWrapper from './DashboardYAxisUnitSelectorWrapper';
import LegendColors from './LegendColors/LegendColors';
import ThresholdSelector from './Threshold/ThresholdSelector';
import { ThresholdProps } from './Threshold/types';
import { timePreferance } from './timeItems';
import YAxisUnitSelector from './YAxisUnitSelector';
const { TextArea } = Input;
const { Option } = Select;
@@ -129,6 +129,7 @@ function RightContainer({
contextLinks,
setContextLinks,
enableDrillDown = false,
isNewDashboard,
}: RightContainerProps): JSX.Element {
const { selectedDashboard } = useDashboard();
const [inputValue, setInputValue] = useState(title);
@@ -348,11 +349,12 @@ function RightContainer({
<ColumnUnitSelector
columnUnits={columnUnits}
setColumnUnits={setColumnUnits}
isNewDashboard={isNewDashboard}
/>
)}
{allowYAxisUnit && (
<YAxisUnitSelector
<DashboardYAxisUnitSelectorWrapper
onSelect={setYAxisUnit}
value={yAxisUnit || ''}
fieldLabel={
@@ -361,6 +363,8 @@ function RightContainer({
? 'Unit'
: 'Y Axis Unit'
}
// Only update the y-axis unit value automatically in create mode
shouldUpdateYAxisUnit={isNewDashboard}
/>
)}
@@ -612,6 +616,7 @@ export interface RightContainerProps {
contextLinks: ContextLinksData;
setContextLinks: Dispatch<SetStateAction<ContextLinksData>>;
enableDrillDown?: boolean;
isNewDashboard: boolean;
}
RightContainer.defaultProps = {

View File

@@ -860,6 +860,7 @@ function NewWidget({
contextLinks={contextLinks}
setContextLinks={setContextLinks}
enableDrillDown={enableDrillDown}
isNewDashboard={isNewDashboard}
/>
</OverlayScrollbar>
</RightContainerWrapper>

View File

@@ -18,7 +18,7 @@ import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
const enum ApplicationLogsType {
FROM_LOG_FILE = 'from-log-file',
@@ -68,7 +68,7 @@ export default function LogsConnectionStatus(): JSX.Element {
],
groupBy: [],
legend: '',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
offset: 0,
pageSize: 100,
timeAggregation: '',

View File

@@ -316,6 +316,7 @@
"application performance monitoring",
"java",
"java agent",
"java-agent",
"java apm",
"java application",
"java instrumentation",
@@ -596,7 +597,8 @@
"traces",
"tracing",
"ts",
"typescript"
"typescript",
"react native"
],
"id": "javascript",
"imgUrl": "/Logos/javascript.svg",
@@ -1982,6 +1984,7 @@
],
"module": "logs",
"relatedSearchKeywords": [
"amazon",
"aws",
"aws lambda logs",
"aws lambda nodejs logs",
@@ -2057,6 +2060,8 @@
"java logs to signoz",
"java observability",
"logging",
"java-agent",
"java agent",
"logs",
"opentelemetry",
"otel",
@@ -2064,7 +2069,9 @@
"otel logs java",
"otel-java-sdk",
"sdk",
"structured logging java"
"structured logging java",
"Logback",
"log4j"
],
"link": "/docs/userguide/collecting_application_logs_otel_sdk_java/"
},
@@ -2280,6 +2287,7 @@
],
"module": "logs",
"relatedSearchKeywords": [
"amazon",
"aws",
"aws ec2",
"aws ec2 log collection",
@@ -2347,6 +2355,7 @@
],
"module": "infra-monitoring-hosts",
"relatedSearchKeywords": [
"amazon",
"aws",
"aws container service",
"aws ecs",
@@ -2410,6 +2419,7 @@
],
"module": "infra-monitoring-k8s",
"relatedSearchKeywords": [
"amazon",
"aws",
"aws eks",
"aws kubernetes",
@@ -2472,6 +2482,7 @@
],
"module": "logs",
"relatedSearchKeywords": [
"amazon",
"aws",
"aws elb",
"aws elb logs",
@@ -2503,6 +2514,7 @@
],
"module": "logs",
"relatedSearchKeywords": [
"amazon",
"aws",
"aws vpc logs",
"collect vpc logs",
@@ -2533,6 +2545,7 @@
],
"module": "dashboards",
"relatedSearchKeywords": [
"amazon",
"amazon rds",
"aws",
"aws database",
@@ -2598,6 +2611,7 @@
],
"module": "dashboards",
"relatedSearchKeywords": [
"amazon",
"aws",
"aws lambda",
"aws lambda insights",
@@ -4431,6 +4445,7 @@
"vuejs",
"nuxtjs",
"svelte",
"sveltekit",
"nextjs"
],
"link": "/docs/frontend-monitoring/web-vitals-with-metrics/"
@@ -4464,6 +4479,7 @@
"vuejs",
"nuxtjs",
"svelte",
"sveltekit",
"nextjs"
],
"link": "/docs/frontend-monitoring/web-vitals-with-traces/"
@@ -4504,6 +4520,7 @@
"vuejs",
"nuxtjs",
"svelte",
"sveltekit",
"nextjs"
],
"link": "/docs/frontend-monitoring/document-load/"
@@ -5412,6 +5429,7 @@
"vuejs",
"nuxtjs",
"svelte",
"sveltekit",
"nextjs"
],
"link": "/docs/frontend-monitoring/sending-logs-with-opentelemetry/"
@@ -5441,6 +5459,7 @@
"vuejs",
"nuxtjs",
"svelte",
"sveltekit",
"nextjs"
],
"link": "/docs/frontend-monitoring/sending-traces-with-opentelemetry/"
@@ -5470,6 +5489,7 @@
"vuejs",
"nuxtjs",
"svelte",
"sveltekit",
"nextjs"
],
"link": "/docs/frontend-monitoring/sending-metrics-with-opentelemetry/"

View File

@@ -1,3 +1,5 @@
import { ReduceOperators } from 'types/common/queryBuilder';
export const tablePanelWidgetQuery = {
id: '727533b0-7718-4f99-a1db-a1875649325c',
title: '',
@@ -56,7 +58,7 @@ export const tablePanelWidgetQuery = {
},
],
legend: 'latency-per-service',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
],
queryFormulas: [],
@@ -245,7 +247,7 @@ export const tablePanelQueryResponse = {
},
],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
},
},

View File

@@ -1,3 +1,5 @@
import { ReduceOperators } from 'types/common/queryBuilder';
export const valuePanelWidget = {
id: 'b8b93086-ef01-47bf-9044-1e7abd583be4',
title: 'signoz latency in ms',
@@ -49,7 +51,7 @@ export const valuePanelWidget = {
orderBy: [],
groupBy: [],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
],
queryFormulas: [],
@@ -229,7 +231,7 @@ export const valuePanelQueryResponse = {
orderBy: [],
groupBy: [],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
},
},

View File

@@ -1,6 +1,7 @@
import { render, screen } from '@testing-library/react';
import { MetricType } from 'api/metricsExplorer/getMetricsList';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
import { ReduceOperators } from 'types/common/queryBuilder';
import { ReduceToFilter } from './ReduceToFilter';
@@ -37,7 +38,15 @@ describe('ReduceToFilter', () => {
render(
<ReduceToFilter
query={baseQuery({
aggregations: [{ reduceTo: 'sum' } as any],
aggregations: [
{
reduceTo: ReduceOperators.SUM,
metricName: 'test',
temporality: '',
timeAggregation: 'sum',
spaceAggregation: 'sum',
},
],
aggregateAttribute: { key: 'test', type: MetricType.SUM },
})}
onChange={mockOnChange}
@@ -51,7 +60,7 @@ describe('ReduceToFilter', () => {
render(
<ReduceToFilter
query={baseQuery({
reduceTo: 'max',
reduceTo: ReduceOperators.MAX,
aggregateAttribute: { key: 'test', type: MetricType.GAUGE },
})}
onChange={mockOnChange}
@@ -60,29 +69,4 @@ describe('ReduceToFilter', () => {
expect(screen.getByText('Max of values in timeframe')).toBeInTheDocument();
});
it('updates to sum when aggregateAttribute.type is SUM', async () => {
const { rerender } = render(
<ReduceToFilter
query={baseQuery({
aggregateAttribute: { key: 'test', type: MetricType.GAUGE },
})}
onChange={mockOnChange}
/>,
);
rerender(
<ReduceToFilter
query={baseQuery({
aggregateAttribute: { key: 'test2', type: MetricType.SUM },
})}
onChange={mockOnChange}
/>,
);
const reduceToFilterText = (await screen.findByText(
'Sum of values in timeframe',
)) as HTMLElement;
expect(reduceToFilterText).toBeInTheDocument();
});
});

View File

@@ -1,7 +1,6 @@
import { Select } from 'antd';
import { MetricType } from 'api/metricsExplorer/getMetricsList';
import { REDUCE_TO_VALUES } from 'constants/queryBuilder';
import { memo, useEffect, useRef, useState } from 'react';
import { memo, useEffect, useState } from 'react';
import { MetricAggregation } from 'types/api/v5/queryRange';
// ** Types
import { ReduceOperators } from 'types/common/queryBuilder';
@@ -13,10 +12,9 @@ export const ReduceToFilter = memo(function ReduceToFilter({
query,
onChange,
}: ReduceToFilterProps): JSX.Element {
const isMounted = useRef<boolean>(false);
const [currentValue, setCurrentValue] = useState<
SelectOption<ReduceOperators, string>
>(REDUCE_TO_VALUES[2]); // default to avg
>(REDUCE_TO_VALUES[2]);
const handleChange = (
newValue: SelectOption<ReduceOperators, string>,
@@ -27,30 +25,16 @@ export const ReduceToFilter = memo(function ReduceToFilter({
useEffect(
() => {
if (!isMounted.current) {
const reduceToValue =
(query.aggregations?.[0] as MetricAggregation)?.reduceTo || query.reduceTo;
const reduceToValue =
(query.aggregations?.[0] as MetricAggregation)?.reduceTo || query.reduceTo;
setCurrentValue(
REDUCE_TO_VALUES.find((option) => option.value === reduceToValue) ||
REDUCE_TO_VALUES[2],
);
isMounted.current = true;
return;
}
const aggregationAttributeType = query.aggregateAttribute?.type as
| MetricType
| undefined;
if (aggregationAttributeType === MetricType.SUM) {
handleChange(REDUCE_TO_VALUES[1]);
} else {
handleChange(REDUCE_TO_VALUES[2]);
}
setCurrentValue(
REDUCE_TO_VALUES.find((option) => option.value === reduceToValue) ||
REDUCE_TO_VALUES[2],
);
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[query.aggregateAttribute?.key],
[(query.aggregations?.[0] as MetricAggregation)?.reduceTo, query.reduceTo],
);
return (

View File

@@ -1,3 +1,5 @@
import { ReduceOperators } from 'types/common/queryBuilder';
/* eslint-disable sonarjs/no-duplicate-string */
export const QueryTableProps: any = {
props: {
@@ -130,7 +132,7 @@ export const QueryTableProps: any = {
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -284,7 +286,7 @@ export const WidgetHeaderProps: any = {
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -613,7 +615,7 @@ export const WidgetHeaderProps: any = {
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',

View File

@@ -4,7 +4,7 @@ import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { Filter } from 'types/api/v5/queryRange';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
import { v4 as uuidv4 } from 'uuid';
/**
@@ -55,7 +55,7 @@ export const getSpanLogsQueryPayload = (
],
groupBy: [],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
offset: 0,
pageSize: 100,
},

View File

@@ -7,7 +7,11 @@ import {
} from 'types/api/queryBuilder/queryAutocompleteResponse';
import { Query, TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { EQueryType } from 'types/common/dashboard';
import { DataSource, LogsAggregatorOperator } from 'types/common/queryBuilder';
import {
DataSource,
LogsAggregatorOperator,
ReduceOperators,
} from 'types/common/queryBuilder';
import { v4 as uuid } from 'uuid';
export const getTraceToLogsQuery = (
@@ -58,7 +62,7 @@ export const getTraceToLogsQuery = (
legend: '',
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
stepInterval: getStep({
start: minTime,
end: maxTime,

View File

@@ -1,6 +1,6 @@
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
export const BASE_FILTER_QUERY: IBuilderQuery = {
queryName: 'A',
@@ -32,7 +32,7 @@ export const BASE_FILTER_QUERY: IBuilderQuery = {
],
groupBy: [],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
offset: 0,
selectColumns: [],
};

View File

@@ -6,7 +6,11 @@ import {
DataTypes,
} from 'types/api/queryBuilder/queryAutocompleteResponse';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
import { DataSource, MetricAggregateOperator } from 'types/common/queryBuilder';
import {
DataSource,
MetricAggregateOperator,
ReduceOperators,
} from 'types/common/queryBuilder';
import { useQueryBuilder } from '../useQueryBuilder';
import { useQueryOperations } from '../useQueryBuilderOperations';
@@ -54,7 +58,7 @@ describe('useQueryBuilderOperations - Empty Aggregate Attribute Type', () => {
stepInterval: 60,
expression: '',
disabled: false,
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
legend: '',
};
@@ -189,6 +193,7 @@ describe('useQueryBuilderOperations - Empty Aggregate Attribute Type', () => {
metricName: 'new_sum_metric',
temporality: '',
spaceAggregation: MetricAggregateOperator.SUM,
reduceTo: ReduceOperators.SUM,
},
],
}),
@@ -208,6 +213,7 @@ describe('useQueryBuilderOperations - Empty Aggregate Attribute Type', () => {
metricName: 'original_sum_metric',
temporality: '',
spaceAggregation: MetricAggregateOperator.SUM,
reduceTo: ReduceOperators.SUM,
},
],
};
@@ -240,6 +246,7 @@ describe('useQueryBuilderOperations - Empty Aggregate Attribute Type', () => {
metricName: 'new_sum_metric',
temporality: '',
spaceAggregation: MetricAggregateOperator.SUM,
reduceTo: ReduceOperators.SUM,
},
],
}),
@@ -261,6 +268,7 @@ describe('useQueryBuilderOperations - Empty Aggregate Attribute Type', () => {
metricName: 'original_gauge',
temporality: '',
spaceAggregation: '',
reduceTo: ReduceOperators.AVG,
},
],
};
@@ -291,6 +299,7 @@ describe('useQueryBuilderOperations - Empty Aggregate Attribute Type', () => {
metricName: '',
temporality: '',
spaceAggregation: MetricAggregateOperator.SUM,
reduceTo: ReduceOperators.AVG,
},
],
};
@@ -316,6 +325,7 @@ describe('useQueryBuilderOperations - Empty Aggregate Attribute Type', () => {
metricName: 'new_gauge',
temporality: '',
spaceAggregation: MetricAggregateOperator.AVG,
reduceTo: ReduceOperators.AVG,
},
],
}),

View File

@@ -43,7 +43,11 @@ import {
HandleChangeQueryDataV5,
UseQueryOperations,
} from 'types/common/operations.types';
import { DataSource, MetricAggregateOperator } from 'types/common/queryBuilder';
import {
DataSource,
MetricAggregateOperator,
ReduceOperators,
} from 'types/common/queryBuilder';
import { SelectOption } from 'types/common/select';
import { getFormatedLegend } from 'utils/getFormatedLegend';
@@ -318,6 +322,7 @@ export const useQueryOperations: UseQueryOperations = ({
metricName: newQuery.aggregateAttribute?.key || '',
temporality: '',
spaceAggregation: MetricAggregateOperator.SUM,
reduceTo: ReduceOperators.SUM,
},
];
} else if (newQuery.aggregateAttribute?.type === ATTRIBUTE_TYPES.GAUGE) {
@@ -327,6 +332,7 @@ export const useQueryOperations: UseQueryOperations = ({
metricName: newQuery.aggregateAttribute?.key || '',
temporality: '',
spaceAggregation: MetricAggregateOperator.AVG,
reduceTo: ReduceOperators.AVG,
},
];
} else if (
@@ -340,6 +346,7 @@ export const useQueryOperations: UseQueryOperations = ({
metricName: newQuery.aggregateAttribute?.key || '',
temporality: '',
spaceAggregation: MetricAggregateOperator.P90,
reduceTo: ReduceOperators.AVG,
},
];
} else {
@@ -349,6 +356,7 @@ export const useQueryOperations: UseQueryOperations = ({
metricName: newQuery.aggregateAttribute?.key || '',
temporality: '',
spaceAggregation: '',
reduceTo: ReduceOperators.AVG,
},
];
}

View File

@@ -3,6 +3,8 @@ import {
useGetMetrics,
} from 'container/MetricsExplorer/Explorer/utils';
import { useEffect, useMemo, useState } from 'react';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
import { MetricAggregation } from 'types/api/v5/queryRange';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
@@ -14,6 +16,19 @@ interface UseGetYAxisUnitResult {
isError: boolean;
}
function getMetricNameFromQueryData(queryData: IBuilderQuery): string | null {
if (queryData.dataSource !== DataSource.METRICS) {
return null;
}
if (queryData.aggregateAttribute?.key) {
return queryData.aggregateAttribute?.key;
}
if (queryData.aggregations?.length && queryData.aggregations.length > 0) {
return (queryData.aggregations?.[0] as MetricAggregation)?.metricName;
}
return null;
}
/**
* Hook to get the y-axis unit for a given metrics-based query.
* @param selectedQueryName - The name of the query to get the y-axis unit for.
@@ -45,19 +60,18 @@ function useGetYAxisUnit(
// If a selected query name is provided, return the metric name for that query only
if (selectedQueryName) {
stagedQuery?.builder?.queryData?.forEach((query) => {
if (
query.queryName === selectedQueryName &&
query.aggregateAttribute?.key
) {
currentMetricNames.push(query.aggregateAttribute?.key);
const metricName = getMetricNameFromQueryData(query);
if (query.queryName === selectedQueryName && metricName) {
currentMetricNames.push(metricName);
}
});
return currentMetricNames.length ? currentMetricNames : null;
}
// Else, return all metric names
stagedQuery?.builder?.queryData?.forEach((query) => {
if (query.aggregateAttribute?.key) {
currentMetricNames.push(query.aggregateAttribute?.key);
const metricName = getMetricNameFromQueryData(query);
if (metricName) {
currentMetricNames.push(metricName);
}
});
return currentMetricNames.length ? currentMetricNames : null;

View File

@@ -3,7 +3,7 @@ import { PANEL_TYPES } from 'constants/queryBuilder';
import { ICompositeMetricQuery } from 'types/api/alerts/compositeQuery';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
export const compositeQueryWithoutVariables = ({
builderQueries: {
@@ -26,7 +26,7 @@ export const compositeQueryWithoutVariables = ({
limit: 0,
offset: 0,
pageSize: 0,
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
timeAggregation: 'rate',
spaceAggregation: 'sum',
ShiftBy: 0,
@@ -57,7 +57,7 @@ export const stepIntervalUnchanged = {
temporality: '',
timeAggregation: 'count',
spaceAggregation: 'sum',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
],
functions: [],
@@ -70,7 +70,7 @@ export const stepIntervalUnchanged = {
orderBy: [],
groupBy: [],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
source: '',
offset: 0,
pageSize: 0,
@@ -149,7 +149,7 @@ export const compositeQueryWithVariables = ({
limit: 0,
offset: 0,
pageSize: 0,
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
timeAggregation: 'rate',
spaceAggregation: 'sum',
ShiftBy: 0,
@@ -180,7 +180,7 @@ export const replaceVariables = {
temporality: '',
timeAggregation: 'count',
spaceAggregation: 'sum',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
],
functions: [],
@@ -235,7 +235,7 @@ export const replaceVariables = {
},
],
legend: '{{service_name}}-{{operation}}',
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
source: '',
offset: 0,
pageSize: 0,
@@ -265,7 +265,7 @@ export const defaultOutput = {
aggregations: [
{
metricName: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
temporality: '',
timeAggregation: 'count',
@@ -286,7 +286,7 @@ export const defaultOutput = {
orderBy: [],
pageSize: 0,
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
source: '',
spaceAggregation: 'sum',
stepInterval: 240,
@@ -324,7 +324,7 @@ export const compositeQueriesWithFunctions = ({
limit: 0,
offset: 0,
pageSize: 0,
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'p90',
ShiftBy: 0,
},
@@ -347,7 +347,7 @@ export const compositeQueriesWithFunctions = ({
limit: 0,
offset: 0,
pageSize: 0,
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
timeAggregation: 'rate',
spaceAggregation: 'sum',
ShiftBy: 0,
@@ -395,7 +395,7 @@ export const outputWithFunctions = {
temporality: '',
timeAggregation: 'count',
spaceAggregation: 'sum',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
],
functions: [],
@@ -408,7 +408,7 @@ export const outputWithFunctions = {
orderBy: [],
groupBy: [],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
source: '',
offset: 0,
pageSize: 0,
@@ -432,7 +432,7 @@ export const outputWithFunctions = {
temporality: '',
timeAggregation: 'count',
spaceAggregation: 'sum',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
],
functions: [],
@@ -445,7 +445,7 @@ export const outputWithFunctions = {
orderBy: [],
groupBy: [],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
source: '',
offset: 0,
pageSize: 0,

View File

@@ -1,3 +1,5 @@
import { ReduceOperators } from 'types/common/queryBuilder';
export const explorerView = {
status: 'success',
data: [
@@ -60,7 +62,7 @@ export const explorerView = {
order: 'desc',
},
],
reduceTo: 'sum',
reduceTo: ReduceOperators.SUM,
ShiftBy: 0,
},
},
@@ -116,7 +118,7 @@ export const explorerView = {
order: 'desc',
},
],
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
timeAggregation: 'rate',
spaceAggregation: 'sum',
ShiftBy: 0,

View File

@@ -1,3 +1,5 @@
import { ReduceOperators } from 'types/common/queryBuilder';
export const publishedPublicDashboardMeta = {
status: 'success',
data: {
@@ -71,7 +73,7 @@ export const publicDashboardResponse = {
aggregations: [
{
metricName: 'container.cpu.time',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
temporality: '',
timeAggregation: 'rate',

View File

@@ -0,0 +1,56 @@
import { Row } from 'antd';
import logEvent from 'api/common/logEvent';
import { QueryParams } from 'constants/query';
import ROUTES from 'constants/routes';
import SelectAlertType from 'container/CreateAlertRule/SelectAlertType';
import { AlertDetectionTypes } from 'container/FormAlertRules';
import { useSafeNavigate } from 'hooks/useSafeNavigate';
import useUrlQuery from 'hooks/useUrlQuery';
import { useCallback, useEffect } from 'react';
import { AlertTypes } from 'types/api/alerts/alertTypes';
function AlertTypeSelectionPage(): JSX.Element {
const { safeNavigate } = useSafeNavigate();
const queryParams = useUrlQuery();
useEffect(() => {
logEvent('Alert: New alert data source selection page visited', {});
}, []);
const handleSelectType = useCallback(
(type: AlertTypes): void => {
// For anamoly based alert, we need to set the ruleType to anomaly_rule
// and alertType to metrics_based_alert
if (type === AlertTypes.ANOMALY_BASED_ALERT) {
queryParams.set(
QueryParams.ruleType,
AlertDetectionTypes.ANOMALY_DETECTION_ALERT,
);
queryParams.set(QueryParams.alertType, AlertTypes.METRICS_BASED_ALERT);
// For other alerts, we need to set the ruleType to threshold_rule
// and alertType to the selected type
} else {
queryParams.set(QueryParams.ruleType, AlertDetectionTypes.THRESHOLD_ALERT);
queryParams.set(QueryParams.alertType, type);
}
const showNewCreateAlertsPageFlag = queryParams.get(
QueryParams.showNewCreateAlertsPage,
);
if (showNewCreateAlertsPageFlag === 'true') {
queryParams.set(QueryParams.showNewCreateAlertsPage, 'true');
}
safeNavigate(`${ROUTES.ALERTS_NEW}?${queryParams.toString()}`);
},
[queryParams, safeNavigate],
);
return (
<Row wrap={false}>
<SelectAlertType onSelect={handleSelectType} />
</Row>
);
}
export default AlertTypeSelectionPage;

View File

@@ -0,0 +1,184 @@
import { fireEvent, render, screen } from '@testing-library/react';
import { FeatureKeys } from 'constants/features';
import { QueryParams } from 'constants/query';
import { AlertDetectionTypes } from 'container/FormAlertRules';
import { getAppContextMockState } from 'container/RoutingPolicies/__tests__/testUtils';
import * as navigateHooks from 'hooks/useSafeNavigate';
import * as useUrlQueryHooks from 'hooks/useUrlQuery';
import * as appHooks from 'providers/App/App';
import { AlertTypes } from 'types/api/alerts/alertTypes';
import AlertTypeSelection from '../AlertTypeSelection';
const useUrlQuerySpy = jest.spyOn(useUrlQueryHooks, 'default');
const useSafeNavigateSpy = jest.spyOn(navigateHooks, 'useSafeNavigate');
const useAppContextSpy = jest.spyOn(appHooks, 'useAppContext');
const mockSetUrlQuery = jest.fn();
const mockSafeNavigate = jest.fn();
const mockToString = jest.fn();
const mockGetUrlQuery = jest.fn();
describe('AlertTypeSelection', () => {
beforeEach(() => {
jest.clearAllMocks();
useAppContextSpy.mockReturnValue(getAppContextMockState());
useUrlQuerySpy.mockReturnValue(({
set: mockSetUrlQuery,
toString: mockToString,
get: mockGetUrlQuery,
} as Partial<URLSearchParams>) as URLSearchParams);
useSafeNavigateSpy.mockReturnValue({
safeNavigate: mockSafeNavigate,
});
});
it('should render all alert type options when anomaly detection is enabled', () => {
useAppContextSpy.mockReturnValue({
...getAppContextMockState({}),
featureFlags: [
{
name: FeatureKeys.ANOMALY_DETECTION,
active: true,
usage: 0,
usage_limit: -1,
route: '',
},
],
});
render(<AlertTypeSelection />);
expect(screen.getByText('metric_based_alert')).toBeInTheDocument();
expect(screen.getByText('log_based_alert')).toBeInTheDocument();
expect(screen.getByText('traces_based_alert')).toBeInTheDocument();
expect(screen.getByText('exceptions_based_alert')).toBeInTheDocument();
expect(screen.getByText('anomaly_based_alert')).toBeInTheDocument();
});
it('should render all alert type options except anomaly based alert when anomaly detection is disabled', () => {
render(<AlertTypeSelection />);
expect(screen.getByText('metric_based_alert')).toBeInTheDocument();
expect(screen.getByText('log_based_alert')).toBeInTheDocument();
expect(screen.getByText('traces_based_alert')).toBeInTheDocument();
expect(screen.getByText('exceptions_based_alert')).toBeInTheDocument();
expect(screen.queryByText('anomaly_based_alert')).not.toBeInTheDocument();
});
it('should navigate to metrics based alert with correct params', () => {
render(<AlertTypeSelection />);
fireEvent.click(screen.getByText('metric_based_alert'));
expect(mockSetUrlQuery).toHaveBeenCalledTimes(2);
expect(mockSetUrlQuery).toHaveBeenCalledWith(
QueryParams.ruleType,
AlertDetectionTypes.THRESHOLD_ALERT,
);
expect(mockSetUrlQuery).toHaveBeenCalledWith(
QueryParams.alertType,
AlertTypes.METRICS_BASED_ALERT,
);
expect(mockSafeNavigate).toHaveBeenCalled();
});
it('should navigate to anomaly based alert with correct params', () => {
useAppContextSpy.mockReturnValue({
...getAppContextMockState({}),
featureFlags: [
{
name: FeatureKeys.ANOMALY_DETECTION,
active: true,
usage: 0,
usage_limit: -1,
route: '',
},
],
});
render(<AlertTypeSelection />);
fireEvent.click(screen.getByText('anomaly_based_alert'));
expect(mockSetUrlQuery).toHaveBeenCalledTimes(2);
expect(mockSetUrlQuery).toHaveBeenCalledWith(
QueryParams.ruleType,
AlertDetectionTypes.ANOMALY_DETECTION_ALERT,
);
expect(mockSetUrlQuery).toHaveBeenCalledWith(
QueryParams.alertType,
AlertTypes.METRICS_BASED_ALERT,
);
expect(mockSafeNavigate).toHaveBeenCalled();
});
it('should navigate to log based alert with correct params', () => {
render(<AlertTypeSelection />);
fireEvent.click(screen.getByText('log_based_alert'));
expect(mockSetUrlQuery).toHaveBeenCalledTimes(2);
expect(mockSetUrlQuery).toHaveBeenCalledWith(
QueryParams.ruleType,
AlertDetectionTypes.THRESHOLD_ALERT,
);
expect(mockSetUrlQuery).toHaveBeenCalledWith(
QueryParams.alertType,
AlertTypes.LOGS_BASED_ALERT,
);
expect(mockSafeNavigate).toHaveBeenCalled();
});
it('should navigate to traces based alert with correct params', () => {
render(<AlertTypeSelection />);
fireEvent.click(screen.getByText('traces_based_alert'));
expect(mockSetUrlQuery).toHaveBeenCalledTimes(2);
expect(mockSetUrlQuery).toHaveBeenCalledWith(
QueryParams.ruleType,
AlertDetectionTypes.THRESHOLD_ALERT,
);
expect(mockSetUrlQuery).toHaveBeenCalledWith(
QueryParams.alertType,
AlertTypes.TRACES_BASED_ALERT,
);
expect(mockSafeNavigate).toHaveBeenCalled();
});
it('should navigate to exceptions based alert with correct params', () => {
render(<AlertTypeSelection />);
fireEvent.click(screen.getByText('exceptions_based_alert'));
expect(mockSetUrlQuery).toHaveBeenCalledTimes(2);
expect(mockSetUrlQuery).toHaveBeenCalledWith(
QueryParams.ruleType,
AlertDetectionTypes.THRESHOLD_ALERT,
);
expect(mockSetUrlQuery).toHaveBeenCalledWith(
QueryParams.alertType,
AlertTypes.EXCEPTIONS_BASED_ALERT,
);
expect(mockSafeNavigate).toHaveBeenCalled();
});
it('should navigate to new create alerts page with correct params if showNewCreateAlertsPage is true', () => {
useUrlQuerySpy.mockReturnValue(({
set: mockSetUrlQuery,
toString: mockToString,
get: mockGetUrlQuery.mockReturnValue('true'),
} as Partial<URLSearchParams>) as URLSearchParams);
render(<AlertTypeSelection />);
fireEvent.click(screen.getByText('metric_based_alert'));
expect(mockSetUrlQuery).toHaveBeenCalledTimes(3);
expect(mockSetUrlQuery).toHaveBeenCalledWith(
QueryParams.ruleType,
AlertDetectionTypes.THRESHOLD_ALERT,
);
expect(mockSetUrlQuery).toHaveBeenCalledWith(
QueryParams.alertType,
AlertTypes.METRICS_BASED_ALERT,
);
expect(mockSetUrlQuery).toHaveBeenCalledWith(
QueryParams.showNewCreateAlertsPage,
'true',
);
expect(mockSafeNavigate).toHaveBeenCalled();
});
});

View File

@@ -0,0 +1,3 @@
import AlertTypeSelectionPage from './AlertTypeSelection';
export default AlertTypeSelectionPage;

View File

@@ -9,7 +9,7 @@ import {
DataTypes,
} from 'types/api/queryBuilder/queryAutocompleteResponse';
import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
import { v4 as uuidv4 } from 'uuid';
export const celeryOverviewRequestRateWidgetData = (
@@ -42,7 +42,7 @@ export const celeryOverviewRequestRateWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -95,7 +95,7 @@ export const celeryOverviewErrorRateWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -135,7 +135,7 @@ export const celeryOverviewAvgLatencyWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'p95',
@@ -178,7 +178,7 @@ export const celeryOverviewRequestRateGraphData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: getStepInterval(startTime, endTime),
timeAggregation: 'rate',
@@ -238,7 +238,7 @@ export const celeryOverviewErrorRateGraphData = (
orderBy: [],
groupBy: groupByFilter ? [groupByFilter] : [],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
{
dataSource: DataSource.TRACES,
@@ -278,7 +278,7 @@ export const celeryOverviewErrorRateGraphData = (
orderBy: [],
groupBy: groupByFilter ? [groupByFilter] : [],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
{
dataSource: DataSource.TRACES,
@@ -305,7 +305,7 @@ export const celeryOverviewErrorRateGraphData = (
orderBy: [],
groupBy: groupByFilter ? [groupByFilter] : [],
legend: '',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
},
{
queryName: 'F1',
@@ -358,7 +358,7 @@ export const celeryOverviewAvgLatencyGraphData = (
limit: null,
orderBy: [],
queryName: 'C',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: getStepInterval(startTime, endTime),
timeAggregation: 'p90',
@@ -385,7 +385,7 @@ export const celeryOverviewAvgLatencyGraphData = (
limit: null,
orderBy: [],
queryName: 'D',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: getStepInterval(startTime, endTime),
timeAggregation: 'p95',
@@ -412,7 +412,7 @@ export const celeryOverviewAvgLatencyGraphData = (
limit: null,
orderBy: [],
queryName: 'E',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: getStepInterval(startTime, endTime),
timeAggregation: 'p99',

View File

@@ -2,7 +2,7 @@ import { Typography } from 'antd';
import { AxiosError } from 'axios';
import NotFound from 'components/NotFound';
import Spinner from 'components/Spinner';
import NewDashboard from 'container/NewDashboard';
import DashboardContainer from 'container/NewDashboard';
import { useDashboard } from 'providers/Dashboard/Dashboard';
import { useEffect } from 'react';
import { ErrorType } from 'types/common';
@@ -35,7 +35,7 @@ function DashboardPage(): JSX.Element {
return <Spinner tip="Loading.." />;
}
return <NewDashboard />;
return <DashboardContainer />;
}
export default DashboardPage;

View File

@@ -8,7 +8,7 @@ import {
IBuilderQuery,
} from 'types/api/queryBuilder/queryBuilderData';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
import { v4 as uuid } from 'uuid';
interface GetWidgetQueryProps {
@@ -111,7 +111,7 @@ export const getRequestTimesWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',
@@ -146,7 +146,7 @@ export const getBrokerCountWidgetData = (dotMetricsEnabled: boolean): Widgets =>
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'sum',
@@ -185,7 +185,7 @@ export const getProducerFetchRequestPurgatoryWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',
@@ -229,7 +229,7 @@ export const getBrokerNetworkThroughputWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',
@@ -271,7 +271,7 @@ export const getIoWaitTimeWidgetData = (dotMetricsEnabled: boolean): Widgets =>
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -314,7 +314,7 @@ export const getRequestResponseWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',
@@ -344,7 +344,7 @@ export const getRequestResponseWidgetData = (
limit: null,
orderBy: [],
queryName: 'B',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',
@@ -387,7 +387,7 @@ export const getAverageRequestLatencyWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',
@@ -437,7 +437,7 @@ export const getKafkaProducerByteRateWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',
@@ -482,7 +482,7 @@ export const getBytesConsumedWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',
@@ -545,7 +545,7 @@ export const getConsumerOffsetWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',
@@ -595,7 +595,7 @@ export const getConsumerGroupMemberWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'sum',
@@ -656,7 +656,7 @@ export const getConsumerLagByGroupWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',
@@ -706,7 +706,7 @@ export const getConsumerFetchRateWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',
@@ -749,7 +749,7 @@ export const getMessagesConsumedWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',
@@ -790,7 +790,7 @@ export const getJvmGCCountWidgetData = (dotMetricsEnabled: boolean): Widgets =>
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -833,7 +833,7 @@ export const getJvmGcCollectionsElapsedWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
@@ -878,7 +878,7 @@ export const getCpuRecentUtilizationWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',
@@ -917,7 +917,7 @@ export const getJvmMemoryHeapWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',
@@ -965,7 +965,7 @@ export const getPartitionCountPerTopicWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'sum',
@@ -1020,7 +1020,7 @@ export const getCurrentOffsetPartitionWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1076,7 +1076,7 @@ export const getOldestOffsetWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',
@@ -1132,7 +1132,7 @@ export const getInsyncReplicasWidgetData = (
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'avg',

View File

@@ -15,7 +15,7 @@ import { ErrorResponse, SuccessResponse } from 'types/api';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
import { DataSource, ReduceOperators } from 'types/common/queryBuilder';
import { v4 as uuid } from 'uuid';
export const KAFKA_SETUP_DOC_LINK =
@@ -148,7 +148,7 @@ export function getWidgetQuery({
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
spaceAggregation: 'avg',
stepInterval: 60,
timeAggregation: 'max',

View File

@@ -60,6 +60,7 @@ import {
IsDefaultQueryProps,
QueryBuilderContextType,
QueryBuilderData,
ReduceOperators,
} from 'types/common/queryBuilder';
import { sanitizeOrderByForExplorer } from 'utils/sanitizeOrderBy';
import { v4 as uuid } from 'uuid';
@@ -329,7 +330,7 @@ export function QueryBuilderProvider({
// set to default values
orderBy: [],
limit: null,
reduceTo: 'avg',
reduceTo: ReduceOperators.AVG,
};
},
[],

View File

@@ -1,5 +1,7 @@
// ===================== Base Types =====================
import { ReduceOperators } from 'types/common/queryBuilder';
import { Warning } from '..';
export type Step = string | number; // Duration string (e.g., "30s") or seconds as number
@@ -190,7 +192,7 @@ export interface MetricAggregation {
temporality: Temporality;
timeAggregation: TimeAggregation;
spaceAggregation: SpaceAggregation;
reduceTo?: string;
reduceTo?: ReduceOperators;
}
export interface SecondaryAggregation {

View File

@@ -219,7 +219,13 @@ export type PanelTypeKeys =
| 'TRACE'
| 'EMPTY_WIDGET';
export type ReduceOperators = 'last' | 'sum' | 'avg' | 'max' | 'min';
export enum ReduceOperators {
LAST = 'last',
SUM = 'sum',
AVG = 'avg',
MAX = 'max',
MIN = 'min',
}
export type QueryBuilderData = {
queryData: IBuilderQuery[];

View File

@@ -127,4 +127,5 @@ export const routePermission: Record<keyof typeof ROUTES, ROLES[]> = {
METER: ['ADMIN', 'EDITOR', 'VIEWER'],
METER_EXPLORER_VIEWS: ['ADMIN', 'EDITOR', 'VIEWER'],
PUBLIC_DASHBOARD: ['ADMIN', 'EDITOR', 'VIEWER'],
ALERT_TYPE_SELECTION: ['ADMIN', 'EDITOR'],
};

2
go.mod
View File

@@ -54,7 +54,7 @@ require (
github.com/smartystreets/goconvey v1.8.1
github.com/soheilhy/cmux v0.1.5
github.com/spf13/cobra v1.10.1
github.com/srikanthccv/ClickHouse-go-mock v0.12.0
github.com/srikanthccv/ClickHouse-go-mock v0.13.0
github.com/stretchr/testify v1.11.1
github.com/swaggest/jsonschema-go v0.3.78
github.com/swaggest/rest v0.2.75

4
go.sum
View File

@@ -964,8 +964,8 @@ github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3A
github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw=
github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4=
github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
github.com/srikanthccv/ClickHouse-go-mock v0.12.0 h1:KUzaWTwuqMc2uf5FylM/oAcTFdE2DdZjvISm9V0/NAA=
github.com/srikanthccv/ClickHouse-go-mock v0.12.0/go.mod h1:1oUmLtXEXOyS0EEWVKlKEfLfv9y02agCMAvD3tVnhlo=
github.com/srikanthccv/ClickHouse-go-mock v0.13.0 h1:/b7DQphGkh29ocNtLh4DGmQxQYA0CfHz65Wy2zAH2GM=
github.com/srikanthccv/ClickHouse-go-mock v0.13.0/go.mod h1:LiiyBUdXNwB/1DE9rgK/8q9qjVYsTzg6WXQ/3mU3TeY=
github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=

File diff suppressed because it is too large Load Diff

View File

@@ -172,7 +172,6 @@ func (module *module) GetByUser(ctx context.Context, userID valuer.UUID, name pr
return nil, err
}
return nil, err
}
if storableUserPreference != nil {

Some files were not shown because too many files have changed in this diff Show More