Compare commits

..

145 Commits

Author SHA1 Message Date
nikhilmantri0902
78b9ce6d4f chore: v2 clusters list api 2026-04-28 18:31:56 +05:30
nikhilmantri0902
9203602abd chore: rename 2026-04-28 17:30:11 +05:30
Nikhil Mantri
c10d278ec4 Merge branch 'infraM/v2_nodes_list_api' into infraM/v2_namespaces_list_api 2026-04-28 17:12:27 +05:30
nikhilmantri0902
8b0e8f666e chore: v2 nodes api 2026-04-28 17:02:19 +05:30
nikhilmantri0902
1d89b03f10 chore: merged main and resolved conflicts 2026-04-28 16:38:57 +05:30
Nikhil Mantri
ffd493617f feat(infra-monitoring): v2 pods list API (#10833)
* chore: baseline setup

* chore: endpoint detail update

* chore: added logic for hosts v3 api

* fix: bug fix

* chore: disk usage

* chore: added validate function

* chore: added some unit tests

* chore: return status as a string

* chore: yarn generate api

* chore: removed isSendingK8sAgentsMetricsCode

* chore: moved funcs

* chore: added validation on order by

* chore: added pods list logic

* chore: updated openapi yml

* chore: updated spec

* chore: pods api meta start time

* chore: nil pointer check

* chore: nil pointer dereference fix in req.Filter

* chore: added temporalities of metrics

* chore: added pods metrics temporality

* chore: unified composite key function

* chore: code improvements

* chore: added pods list api updates

* chore: hostStatusNone added for clarity that this field can be left empty as well in payload

* chore: yarn generate api

* chore: return errors from getMetadata and lint fix

* chore: return errors from getMetadata and lint fix

* chore: added hostName logic

* chore: modified getMetadata query

* chore: add type for response and files rearrange

* chore: warnings added passing from queryResponse warning to host lists response struct

* chore: added better metrics existence check

* chore: added a TODO remark

* chore: added required metrics check

* chore: distributed samples table to local table change for get metadata

* chore: frontend fix

* chore: endpoint correction

* chore: endpoint modification openapi

* chore: escape backtick to prevent sql injection

* chore: rearrage

* chore: improvements

* chore: validate order by to validate function

* chore: improved description

* chore: added TODOs and made filterByStatus a part of filter struct

* chore: ignore empty string hosts in get active hosts

* feat(infra-monitoring): v2 hosts list - return counts of active & inactive hosts for custom group by attributes (#10956)

* chore: add functionality for showing active and inactive counts in custom group by

* chore: bug fix

* chore: added subquery for active and total count

* chore: ignore empty string hosts in get active hosts

* fix: sinceUnixMilli for determining active hosts compute once per request

* chore: refactor code

* chore: rename HostsList -> ListHosts

* chore: rearrangement

* chore: inframonitoring types renaming

* chore: added types package

* chore: file structure further breakdown for clarity

* chore: comments correction

* chore: removed temporalities

* chore: pods code restructuring

* chore: comments resolve

* chore: added json tag required: true

* chore: removed pod metric temporalities

* chore: removed internal server error

* chore: added status unauthorized

* chore: remove a defensive nil map check, the function ensure non-nil map when err nil

* chore: cleanup and rename

* chore: make sort stable in case of tiebreaker by comparing composite group by keys

* chore: regen api client for inframonitoring

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: added required tags

* chore: added support for pod phase unknown

* chore: removed pods - order by phase

* chore: improved api description to document -1 as no data in numeric fields

* fix: rebase fixes

* feat(infra-monitoring): v2 pods list apis - phase counts when custom grouping (#11088)

* chore: added phase counts feature

* chore: added queries for pod phase counts in custom group by

* chore: added unknown phase count

* fix: isPodUIDInGroupBy in buildPodRecords

* chore: 3 cte --> 2 cte

* chore: pod phase with local table of time series as counts

* chore: comment correction

* chore: corrected comment

* chore: value column for samples table added

* chore: removed query G for phase counts

* chore: rename variable

* chore: added PodPhaseNum constants to types

* chore: updated comment

* chore: formatted file

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Ashwin Bhatkal <ashwin96@gmail.com>
2026-04-28 10:19:26 +00:00
Pandey
3f95d35ad5 chore: add @therealpandey with @srikanthcvv (#11126)
#### Temporary

- add @therealpandey with @srikanthcvv
2026-04-28 10:01:39 +00:00
Piyush Singariya
9e5678d6b3 CI: JSON QB E2E Integration Suite (#10863)
* feat: enable JSON Path index

* fix: contextual path index usage

* test: fix unit tests

* feat: align negative operators to include other logs

* fix: primitive conditions working

* fix: indexed tests passing

* fix: array type filtering from dynamic arrays

* fix: unit tests

* fix: remove not used paths from testdata

* fix: unit tests

* fix: comment

* fix: indexed unit tests

* fix: array json element comparison

* feat: change filtering of dynamic arrays

* fix: dynamic array tests

* fix: stringified integer value input

* fix: better review for test file

* fix: negative operator check

* ci: lint changes

* chore: import tests from older pr

* fix: better tests

* fix: logs.py

* fix: body tests ready

* fix: better validations

* fix: dynamically change insert stmt for body_v2 availability

* test: with higher migrator version

* fix: type ambiguity

* fix: test

* test: updated validation

* fix: tons of changes

* chore: remove redundent comparison

* ci: tests fixed

* fix: upgraded collector version

* fix: qbtoexpr tests

* fix: go sum

* chore: upgrade collector version v0.144.3-rc.4

* fix: tests

* ci: test fix

* revert: remove db binaries

* test: selectField tests added

* fix: added safeguards in plan generation

* fix: name changed to field_map

* chore: changes based on review

* fix: changes based on review

* fix: remove unused promoted fixture

* test: integration test fix attempt 1

* fix: json access plan remval of AvailableTypes

* fix: invalid index usage on terminal condition

* test: added indexed tests separately

* test: select order by tests added

* fix: update jsontypeexporter

* fix: branches should tell missing array types

* fix: comment removed

* ci: test with updated collector

* fix: issue with FuzzyMatching and API failing

* test: select orderby works

* fix: int64 mapping

* fix: replacing JSONIndex with TelemetryFieldKeyIndex

* chore: update collector to stable release

* chore: update migrator version to stable release

* chore: error fix and unused code

* chore: go mod tidy

* chore: some changes in test to improve quality

* test: enhanced tests to work with backtick required key

* chore: comment removal

* fix: change based on review

* fix: change based on review

* fix: openapi ci

* ci: fix go tests

* fix: index needs body prefix

* fix: tests

* ci: polluted test fix

* fix: shift test files

* refactor(telemetrytypes): replace JSONDataTypeIndex with TelemetryFieldKeySkipIndex

* revert: mcp related changes

* feat: check query log as fixture

* fix: reuse querier fixtures

* chore: rename jsontypeexporter.py

* chore: py-fmt

* fix: minor fix

* fix: py-lint

* fix: changes based on review

* chore: fmt
2026-04-28 08:49:44 +00:00
nikhilmantri0902
7d702763cc chore: namespaces code 2026-04-28 13:44:21 +05:30
nikhilmantri0902
3a61a78986 chore: merged base branch 2026-04-28 12:48:20 +05:30
Abhi kumar
941016f12c Feat/crosshair series highlight (#11013)
* chore: added changes for crosshair sync for tooltip

* chore: minor cleanup

* chore: updated the core structure

* chore: updated the types

* chore: minor cleanup

* feat: added changes for sereis highlighting on crosshair sync

* chore: pr review fixes

* chore: handled other cases of groupby

* chore: minor changes

* feat: tooltip sync across panels (#11114)

* feat: added changes for syncing tooltip

* fix: fixed other tooltips closing when clicked on top of root tooltip

* fix: highlighting first series

* chore: removed y-axis sync for tooltip mode

* chore: minor fix

* chore: fmt fix
2026-04-28 06:52:51 +00:00
Nikhil Mantri
46e833faba Merge branch 'main' into infraM/v2_pods_list_api 2026-04-28 12:15:56 +05:30
nikhilmantri0902
4bd7492629 chore: updated comment 2026-04-28 12:07:04 +05:30
Vinicius Lourenço
500ce85ccb chore(oxlint): run fixes (#11123)
Some checks failed
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
* chore(oxlint): run fixes

* test(to-strict): failing due to missing props
2026-04-28 04:27:45 +00:00
Prakhar Dewan
d1c9864f52 chore: remove unused files (#11033)
Some checks failed
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
* chore: remove unused files

* chore: add knip.json file
2026-04-27 19:23:12 +00:00
Manika Malhotra
f80b650390 chore(onboarding): add open-source tooling to interest in signoz option (#11083) 2026-04-27 14:55:09 +00:00
nikhilmantri0902
401701e036 chore: metadata fix 2026-04-27 19:23:11 +05:30
Nityananda Gohain
64c356b484 feat: types and handler for span attribute mapping (ai-o11y) (#10909)
Some checks failed
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
* feat: 1.types and handler for ai-o11y attribute mapping

* feat: 1.types and handler for ai-o11y attribute mapping

* fix: cleanup

* fix: minor changes

* fix: remove stutters

* fix: remove lint issues

* fix: lint issues

* fix: address comments

* fix: address comments

* fix: address more comments

* fix: more changes

* fix: address comments

* fix: address comments

* fix: address comments

* fix: use mustnewuuid
2026-04-27 11:45:52 +00:00
swapnil-signoz
97885babe8 feat: adding cloud integration implementation details for Azure (#11058)
* refactor: moving types to cloud provider specific namespace/pkg

* refactor: separating cloud provider types

* refactor: using upper case key for AWS

* feat: adding cloud integration azure types

* feat: adding azure services

* refactor: updating omitempty tags

* refactor: updating azure integration config

* feat: completing azure types

* refactor: lint issues

* feat: adding service definitions for azure

* refactor: update service names for Azure Blob Storage telemetry

* refactor: updating definitions with metrics and strategy

* refactor: updating command key

* fix: handle optional connection URL in AWS integration

* feat: wip

* refactor: updating strategy struct

* refactor: updating telemetry strategy

* refactor: updating connection artifact struct

* refactor: updating blob storage service name

* refactor: updating azure blob storage service name

* refactor: update Azure service identifiers

* refactor: updating service defs

* fix: update integration account ID and add agent version to Azure CLI and PowerShell commands

* refactor: updating deny settings mode

* refactor: updating types

* refactor: adding missing case for azure service update

* feat: implement Azure connection commands and add unit tests

* refactor: using template for Azure connection artifact creation and update tests
2026-04-27 11:23:52 +00:00
nikhilmantri0902
3bec0df0ad chore: nodes list v2 full blown 2026-04-27 16:17:39 +05:30
Nikhil Mantri
24fe9a986d feat(infra-monitoring): v2 pods list apis - phase counts when custom grouping (#11088)
* chore: added phase counts feature

* chore: added queries for pod phase counts in custom group by

* chore: added unknown phase count

* fix: isPodUIDInGroupBy in buildPodRecords

* chore: 3 cte --> 2 cte

* chore: pod phase with local table of time series as counts

* chore: comment correction

* chore: corrected comment

* chore: value column for samples table added

* chore: removed query G for phase counts

* chore: rename variable

* chore: added PodPhaseNum constants to types
2026-04-27 16:04:55 +05:30
nikhilmantri0902
520e92049c Merge branch 'feat/v2_pods_list_api_phase_counts' of github.com:SigNoz/signoz into infraM/v2_nodes_list_api 2026-04-27 15:43:09 +05:30
Piyush Singariya
78e3916aea chore: replace JSONDataTypeIndex and bump otel-collector to v0.144.3 (#11110)
* refactor(telemetrytypes): replace JSONDataTypeIndex with TelemetryFieldKeySkipIndex

* revert: mcp related changes

* fix: openapi fails

---------

Co-authored-by: Ankit Nayan <ankit@signoz.io>
2026-04-27 15:40:50 +05:30
Nikhil Mantri
92d297ac9d Merge branch 'main' into infraM/v2_pods_list_api 2026-04-27 15:05:04 +05:30
nikhilmantri0902
eff29aefba chore: added PodPhaseNum constants to types 2026-04-27 13:59:08 +05:30
nikhilmantri0902
ca73453c9e chore: rename variable 2026-04-27 13:53:17 +05:30
nikhilmantri0902
1d836d674f chore: removed query G for phase counts 2026-04-27 13:46:03 +05:30
nikhilmantri0902
83724b0cde chore: value column for samples table added 2026-04-27 13:09:46 +05:30
Yunus M
a4266fa703 feat: enable JSON body query support and add group by functionality (#11042)
* feat: enable JSON body query support and add group by functionality

* chore: update the FF
2026-04-27 07:24:03 +00:00
nikhilmantri0902
3050e37ec7 chore: corrected comment 2026-04-27 12:43:17 +05:30
Ashwin Bhatkal
bdbaa32485 Merge branch 'main' into infraM/v2_pods_list_api 2026-04-27 11:44:13 +05:30
nikhilmantri0902
55b2215025 chore: comment correction 2026-04-24 17:14:56 +05:30
nikhilmantri0902
e90378e618 Merge branch 'infraM/v2_pods_list_api' into feat/v2_pods_list_api_phase_counts 2026-04-24 16:47:15 +05:30
nikhilmantri0902
4592b78f48 chore: pod phase with local table of time series as counts 2026-04-24 15:27:38 +05:30
nikhilmantri0902
d81c99feae chore: 3 cte --> 2 cte 2026-04-24 14:58:26 +05:30
nikhilmantri0902
65a456ff9e fix: isPodUIDInGroupBy in buildPodRecords 2026-04-24 14:36:43 +05:30
nikhilmantri0902
264577b673 chore: added unknown phase count 2026-04-24 13:29:09 +05:30
Ashwin Bhatkal
b35c6676f9 fix: rebase fixes 2026-04-24 13:17:02 +05:30
nikhilmantri0902
c78c9a42db chore: merged base 2026-04-24 13:03:21 +05:30
nikhilmantri0902
1095caa123 chore: improved api description to document -1 as no data in numeric fields 2026-04-24 12:11:45 +05:30
nikhilmantri0902
9043b49762 chore: removed pods - order by phase 2026-04-24 12:04:51 +05:30
nikhilmantri0902
d4084a7494 chore: added support for pod phase unknown 2026-04-24 11:46:26 +05:30
nikhilmantri0902
27c564b3bf chore: added required tags 2026-04-24 11:21:20 +05:30
Nikhil Mantri
f02c491828 Merge branch 'main' into infraM/v2_pods_list_api 2026-04-24 10:47:13 +05:30
Nikhil Mantri
3d53b8f77f Merge branch 'main' into infraM/v2_pods_list_api 2026-04-23 18:44:33 +05:30
nikhilmantri0902
dffe94fec4 chore: conflicts resolved 2026-04-23 18:39:39 +05:30
nikhilmantri0902
b7d4f18aae chore: added queries for pod phase counts in custom group by 2026-04-23 18:01:26 +05:30
nikhilmantri0902
9ad2ec428a chore: added phase counts feature 2026-04-23 16:50:39 +05:30
nikhilmantri0902
c9360fcf13 Merge branch 'infraM/v2_hosts_list_api' into infraM/v2_pods_list_api 2026-04-23 11:23:49 +05:30
nikhilmantri0902
b5ab45db20 chore: regen api client for inframonitoring
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 10:51:35 +05:30
Nikhil Mantri
08f76aca78 Merge branch 'main' into infraM/v2_hosts_list_api 2026-04-23 09:51:01 +05:30
nikhilmantri0902
983d4fe4f2 Merge branch 'infraM/v2_hosts_list_api' into infraM/v2_pods_list_api 2026-04-22 15:37:21 +05:30
nikhilmantri0902
833af794c3 chore: make sort stable in case of tiebreaker by comparing composite group by keys 2026-04-22 15:26:28 +05:30
nikhilmantri0902
21b51d1fcc chore: cleanup and rename 2026-04-22 15:13:00 +05:30
nikhilmantri0902
56f22682c8 Merge branch 'infraM/v2_hosts_list_api' into infraM/v2_pods_list_api 2026-04-22 14:29:17 +05:30
nikhilmantri0902
9c8359940c chore: remove a defensive nil map check, the function ensure non-nil map when err nil 2026-04-22 11:59:01 +05:30
Nikhil Mantri
4050880275 Merge branch 'main' into infraM/v2_hosts_list_api 2026-04-22 11:35:57 +05:30
nikhilmantri0902
5e775f64f2 chore: added status unauthorized 2026-04-21 21:30:44 +05:30
nikhilmantri0902
0189f23f46 chore: removed internal server error 2026-04-21 21:30:01 +05:30
nikhilmantri0902
49a36d4e3d chore: removed pod metric temporalities 2026-04-21 21:24:49 +05:30
nikhilmantri0902
9407d658ab chore: merge base hosts v2 branch 2026-04-21 21:17:28 +05:30
nikhilmantri0902
5035712485 chore: added json tag required: true 2026-04-21 18:50:25 +05:30
nikhilmantri0902
bab17c3615 chore: comments resolve 2026-04-21 18:33:56 +05:30
Nikhil Mantri
37b44f4db9 Merge branch 'main' into infraM/v2_hosts_list_api 2026-04-21 17:40:06 +05:30
nikhilmantri0902
99dd6e5f1e chore: pods code restructuring 2026-04-21 17:03:13 +05:30
nikhilmantri0902
9c7131fa6a chore: merge base branch 2026-04-21 16:22:55 +05:30
Nikhil Mantri
ad889a2e1d Merge branch 'main' into infraM/v2_hosts_list_api 2026-04-21 13:48:53 +05:30
nikhilmantri0902
a4f6d0cbf5 chore: removed temporalities 2026-04-21 13:44:06 +05:30
nikhilmantri0902
589bed7c16 chore: comments correction 2026-04-21 12:50:51 +05:30
nikhilmantri0902
93843a1f48 chore: file structure further breakdown for clarity 2026-04-21 12:36:07 +05:30
nikhilmantri0902
88c43108fc chore: added types package 2026-04-20 18:52:43 +05:30
nikhilmantri0902
ed4cf540e8 chore: inframonitoring types renaming 2026-04-20 18:47:28 +05:30
nikhilmantri0902
9e2dfa9033 chore: rearrangement 2026-04-20 17:51:03 +05:30
nikhilmantri0902
d98d5d68ee chore: rename PodsList -> ListPods 2026-04-20 16:57:21 +05:30
nikhilmantri0902
2cb1c3b73b chore: rename HostsList -> ListHosts 2026-04-20 16:42:19 +05:30
nikhilmantri0902
ae7ca497ad chore: merged base hosts branch and reorganized code 2026-04-20 13:38:25 +05:30
Nikhil Mantri
a579916961 Merge branch 'main' into infraM/v2_hosts_list_api 2026-04-20 11:05:36 +05:30
Nikhil Mantri
4a16d56abf feat(infra-monitoring): v2 hosts list - return counts of active & inactive hosts for custom group by attributes (#10956)
* chore: add functionality for showing active and inactive counts in custom group by

* chore: bug fix

* chore: added subquery for active and total count

* chore: ignore empty string hosts in get active hosts

* fix: sinceUnixMilli for determining active hosts compute once per request

* chore: refactor code
2026-04-20 10:41:15 +05:30
Nikhil Mantri
642b5ac3f0 Merge branch 'main' into infraM/v2_hosts_list_api 2026-04-16 16:32:39 +05:30
Nikhil Mantri
a12112619c Merge branch 'main' into infraM/v2_hosts_list_api 2026-04-16 15:41:35 +05:30
nikhilmantri0902
014785f1bc chore: ignore empty string hosts in get active hosts 2026-04-16 13:17:15 +05:30
Nikhil Mantri
58ee797b10 Merge branch 'main' into infraM/v2_hosts_list_api 2026-04-15 14:18:29 +05:30
Nikhil Mantri
82d236742f Merge branch 'main' into infraM/v2_hosts_list_api 2026-04-15 11:21:33 +05:30
nikhilmantri0902
397e1ad5be chore: added TODOs and made filterByStatus a part of filter struct 2026-04-14 18:32:48 +05:30
nikhilmantri0902
8d6b25ca9b chore: resolved conflicts 2026-04-14 17:09:17 +05:30
nikhilmantri0902
5fa6bd8b8d Merge branch 'main' into infraM/v2_hosts_list_api 2026-04-13 11:02:14 +05:30
nikhilmantri0902
bd9977483b chore: improved description 2026-04-11 11:31:35 +05:30
nikhilmantri0902
50fbdfeeef chore: validate order by to validate function 2026-04-10 19:01:45 +05:30
nikhilmantri0902
e2b1b73e87 chore: improvements 2026-04-10 13:23:33 +05:30
nikhilmantri0902
cb9f3fd3e5 chore: rearrage 2026-04-10 00:39:23 +05:30
nikhilmantri0902
232acc343d chore: escape backtick to prevent sql injection 2026-04-10 00:01:01 +05:30
nikhilmantri0902
2025afdccc chore: endpoint modification openapi 2026-04-09 23:25:59 +05:30
nikhilmantri0902
d2f4d4af93 chore: endpoint correction 2026-04-09 23:21:57 +05:30
Nikhil Mantri
47ff7bbb8e Merge branch 'main' into infraM/v2_hosts_list_api 2026-04-09 23:20:39 +05:30
Nikhil Mantri
724071c5dc Merge branch 'main' into infraM/v2_hosts_list_api 2026-04-09 18:30:15 +05:30
nikhilmantri0902
4d24979358 chore: frontend fix 2026-04-09 18:26:42 +05:30
nikhilmantri0902
042943b10a chore: distributed samples table to local table change for get metadata 2026-04-09 18:24:45 +05:30
nikhilmantri0902
48a9be7ec8 chore: added required metrics check 2026-04-09 17:38:48 +05:30
nikhilmantri0902
a9504b2120 chore: added a TODO remark 2026-04-09 16:08:34 +05:30
nikhilmantri0902
8755887c4a chore: added better metrics existence check 2026-04-09 16:01:35 +05:30
Nikhil Mantri
4cb4662b3a Merge branch 'main' into infraM/v2_hosts_list_api 2026-04-09 15:14:25 +05:30
nikhilmantri0902
e6900dabc8 chore: warnings added passing from queryResponse warning to host lists response struct 2026-04-09 00:09:38 +05:30
nikhilmantri0902
c1ba389b63 chore: add type for response and files rearrange 2026-04-08 23:35:53 +05:30
nikhilmantri0902
3a1f40234f Merge branch 'main' into infraM/v2_hosts_list_api 2026-04-08 23:03:50 +05:30
Nikhil Mantri
2e4891fa63 Merge branch 'main' into infraM/v2_hosts_list_api 2026-04-08 16:07:57 +05:30
Nikhil Mantri
04ebc0bec7 Merge branch 'main' into infraM/v2_hosts_list_api 2026-04-08 11:08:10 +05:30
nikhilmantri0902
271f9b81ed Merge branch 'infraM/v2_hosts_list_api' into infraM/v2_pods_list_api 2026-04-07 21:55:47 +05:30
nikhilmantri0902
6fa815c294 chore: modified getMetadata query 2026-04-07 18:55:57 +05:30
nikhilmantri0902
63ec518efb chore: added hostName logic 2026-04-07 17:36:15 +05:30
nikhilmantri0902
c4ca20dd90 chore: return errors from getMetadata and lint fix 2026-04-07 17:01:13 +05:30
nikhilmantri0902
e56cc4222b chore: return errors from getMetadata and lint fix 2026-04-07 16:57:35 +05:30
nikhilmantri0902
07d2944d7c chore: yarn generate api 2026-04-07 16:44:06 +05:30
nikhilmantri0902
dea01ae36a chore: hostStatusNone added for clarity that this field can be left empty as well in payload 2026-04-07 16:32:25 +05:30
nikhilmantri0902
62ea5b54e2 Merge branch 'main' into infraM/v2_hosts_list_api 2026-04-07 14:09:48 +05:30
nikhilmantri0902
e549a7e42f chore: added pods list api updates 2026-04-07 13:58:10 +05:30
nikhilmantri0902
90e2ebb11f Merge branch 'infraM/v2_hosts_list_api' into infraM/v2_pods_list_api 2026-04-07 13:51:35 +05:30
nikhilmantri0902
61baa1be7a chore: code improvements 2026-04-07 13:49:00 +05:30
nikhilmantri0902
b946fa665f Merge branch 'infraM/v2_hosts_list_api' into infraM/v2_pods_list_api 2026-04-07 11:15:35 +05:30
nikhilmantri0902
2e049556e4 chore: unified composite key function 2026-04-07 11:15:03 +05:30
nikhilmantri0902
492a5e70d7 chore: added pods metrics temporality 2026-04-06 17:33:44 +05:30
nikhilmantri0902
ba1f2771e8 Merge branch 'infraM/v2_hosts_list_api' into infraM/v2_pods_list_api 2026-04-06 17:18:44 +05:30
nikhilmantri0902
7458fb4855 Merge branch 'main' into infraM/v2_hosts_list_api 2026-04-06 17:18:01 +05:30
nikhilmantri0902
5f55f3938b chore: added temporalities of metrics 2026-04-06 17:17:15 +05:30
nikhilmantri0902
3e8102485c Merge branch 'infraM/v2_hosts_list_api' into infraM/v2_pods_list_api 2026-04-04 20:52:50 +05:30
nikhilmantri0902
861c682ea5 chore: nil pointer dereference fix in req.Filter 2026-04-04 20:52:08 +05:30
nikhilmantri0902
c8e5895dff chore: nil pointer check 2026-04-04 20:45:04 +05:30
nikhilmantri0902
82d72e7edb chore: pods api meta start time 2026-04-04 17:18:04 +05:30
nikhilmantri0902
a3f8ecaaf1 chore: merged base branch 2026-04-04 16:47:10 +05:30
nikhilmantri0902
19aada656c chore: updated spec 2026-04-04 16:44:15 +05:30
nikhilmantri0902
b21bb4280f chore: updated openapi yml 2026-04-04 16:38:22 +05:30
nikhilmantri0902
bc0a4fdb5c chore: added pods list logic 2026-04-04 13:24:46 +05:30
nikhilmantri0902
37fb0e9254 Merge branch 'infraM/base_dependencies' into infraM/v2_hosts_list_api 2026-04-03 17:49:00 +05:30
nikhilmantri0902
aecfa1a174 chore: added validation on order by 2026-04-02 20:13:30 +05:30
nikhilmantri0902
b869d23d94 chore: moved funcs 2026-04-02 20:02:22 +05:30
nikhilmantri0902
6ee3d44f76 chore: removed isSendingK8sAgentsMetricsCode 2026-04-02 19:58:30 +05:30
nikhilmantri0902
462e554107 chore: yarn generate api 2026-04-02 14:49:15 +05:30
nikhilmantri0902
66afa73e6f chore: return status as a string 2026-04-02 14:39:02 +05:30
nikhilmantri0902
54c604bcf4 chore: added some unit tests 2026-04-02 14:20:27 +05:30
nikhilmantri0902
c1be02ba54 chore: added validate function 2026-04-02 14:14:34 +05:30
nikhilmantri0902
d3c7ba8f45 chore: disk usage 2026-04-02 14:01:18 +05:30
nikhilmantri0902
039c4a0496 fix: bug fix 2026-04-02 11:32:49 +05:30
nikhilmantri0902
51a94b6bbc chore: added logic for hosts v3 api 2026-04-02 02:52:28 +05:30
nikhilmantri0902
bbfbb94f52 chore: merged main 2026-04-01 00:45:40 +05:30
nikhilmantri0902
d1eb9ef16f chore: endpoint detail update 2026-03-31 16:16:31 +05:30
nikhilmantri0902
3db00f8bc3 chore: baseline setup 2026-03-31 15:27:18 +05:30
310 changed files with 12754 additions and 2315 deletions

56
.github/CODEOWNERS vendored
View File

@@ -52,49 +52,49 @@ go.mod @therealpandey
# Querier Owners
/pkg/querier/ @srikanthccv
/pkg/variables/ @srikanthccv
/pkg/types/querybuildertypes/ @srikanthccv
/pkg/types/telemetrytypes/ @srikanthccv
/pkg/querybuilder/ @srikanthccv
/pkg/telemetrylogs/ @srikanthccv
/pkg/telemetrymetadata/ @srikanthccv
/pkg/telemetrymetrics/ @srikanthccv
/pkg/telemetrytraces/ @srikanthccv
/pkg/querier/ @srikanthccv @therealpandey
/pkg/variables/ @srikanthccv @therealpandey
/pkg/types/querybuildertypes/ @srikanthccv @therealpandey
/pkg/types/telemetrytypes/ @srikanthccv @therealpandey
/pkg/querybuilder/ @srikanthccv @therealpandey
/pkg/telemetrylogs/ @srikanthccv @therealpandey
/pkg/telemetrymetadata/ @srikanthccv @therealpandey
/pkg/telemetrymetrics/ @srikanthccv @therealpandey
/pkg/telemetrytraces/ @srikanthccv @therealpandey
# Metrics
/pkg/types/metrictypes/ @srikanthccv
/pkg/types/metricsexplorertypes/ @srikanthccv
/pkg/modules/metricsexplorer/ @srikanthccv
/pkg/prometheus/ @srikanthccv
/pkg/types/metrictypes/ @srikanthccv @therealpandey
/pkg/types/metricsexplorertypes/ @srikanthccv @therealpandey
/pkg/modules/metricsexplorer/ @srikanthccv @therealpandey
/pkg/prometheus/ @srikanthccv @therealpandey
# APM
/pkg/types/servicetypes/ @srikanthccv
/pkg/types/apdextypes/ @srikanthccv
/pkg/modules/apdex/ @srikanthccv
/pkg/modules/services/ @srikanthccv
/pkg/types/servicetypes/ @srikanthccv @therealpandey
/pkg/types/apdextypes/ @srikanthccv @therealpandey
/pkg/modules/apdex/ @srikanthccv @therealpandey
/pkg/modules/services/ @srikanthccv @therealpandey
# Dashboard
/pkg/types/dashboardtypes/ @srikanthccv
/pkg/modules/dashboard/ @srikanthccv
/pkg/types/dashboardtypes/ @srikanthccv @therealpandey
/pkg/modules/dashboard/ @srikanthccv @therealpandey
# Rule/Alertmanager
/pkg/types/ruletypes/ @srikanthccv
/pkg/types/alertmanagertypes @srikanthccv
/pkg/alertmanager/ @srikanthccv
/pkg/ruler/ @srikanthccv
/pkg/modules/rulestatehistory/ @srikanthccv
/pkg/types/rulestatehistorytypes/ @srikanthccv
/pkg/types/ruletypes/ @srikanthccv @therealpandey
/pkg/types/alertmanagertypes @srikanthccv @therealpandey
/pkg/alertmanager/ @srikanthccv @therealpandey
/pkg/ruler/ @srikanthccv @therealpandey
/pkg/modules/rulestatehistory/ @srikanthccv @therealpandey
/pkg/types/rulestatehistorytypes/ @srikanthccv @therealpandey
# Correlation-adjacent
/pkg/contextlinks/ @srikanthccv
/pkg/types/parsertypes/ @srikanthccv
/pkg/queryparser/ @srikanthccv
/pkg/contextlinks/ @srikanthccv @therealpandey
/pkg/types/parsertypes/ @srikanthccv @therealpandey
/pkg/queryparser/ @srikanthccv @therealpandey
# AuthN / AuthZ Owners

View File

@@ -51,6 +51,7 @@ jobs:
- role
- rootuser
- serviceaccount
- querier_json_body
- ttl
sqlstore-provider:
- postgres
@@ -61,7 +62,7 @@ jobs:
- 25.5.6
- 25.12.5
schema-migrator-version:
- v0.142.0
- v0.144.3
postgres-version:
- 15
if: |

View File

@@ -167,7 +167,7 @@ func runServer(ctx context.Context, config signoz.Config, logger *slog.Logger) e
if err != nil {
return nil, err
}
azureCloudProviderModule := implcloudprovider.NewAzureCloudProvider()
azureCloudProviderModule := implcloudprovider.NewAzureCloudProvider(defStore)
cloudProvidersMap := map[cloudintegrationtypes.CloudProviderType]cloudintegration.CloudProviderModule{
cloudintegrationtypes.CloudProviderTypeAWS: awsCloudProviderModule,
cloudintegrationtypes.CloudProviderTypeAzure: azureCloudProviderModule,

File diff suppressed because it is too large Load Diff

View File

@@ -18,6 +18,7 @@ func NewAWSCloudProvider(defStore cloudintegrationtypes.ServiceDefinitionStore)
return &awscloudprovider{serviceDefinitions: defStore}, nil
}
// TODO: move URL construction logic to cloudintegrationtypes and add unit tests for it.
func (provider *awscloudprovider) GetConnectionArtifact(ctx context.Context, account *cloudintegrationtypes.Account, req *cloudintegrationtypes.GetConnectionArtifactRequest) (*cloudintegrationtypes.ConnectionArtifact, error) {
baseURL := fmt.Sprintf(cloudintegrationtypes.CloudFormationQuickCreateBaseURL.StringValue(), req.Config.AWS.DeploymentRegion)
u, _ := url.Parse(baseURL)

View File

@@ -2,27 +2,48 @@ package implcloudprovider
import (
"context"
"sort"
"github.com/SigNoz/signoz/pkg/modules/cloudintegration"
"github.com/SigNoz/signoz/pkg/types/cloudintegrationtypes"
)
type azurecloudprovider struct{}
type azurecloudprovider struct {
serviceDefinitions cloudintegrationtypes.ServiceDefinitionStore
}
func NewAzureCloudProvider() cloudintegration.CloudProviderModule {
return &azurecloudprovider{}
func NewAzureCloudProvider(defStore cloudintegrationtypes.ServiceDefinitionStore) cloudintegration.CloudProviderModule {
return &azurecloudprovider{
serviceDefinitions: defStore,
}
}
func (provider *azurecloudprovider) GetConnectionArtifact(ctx context.Context, account *cloudintegrationtypes.Account, req *cloudintegrationtypes.GetConnectionArtifactRequest) (*cloudintegrationtypes.ConnectionArtifact, error) {
panic("implement me")
connectionArtifact, err := cloudintegrationtypes.NewAzureConnectionArtifact(account.ID, req.Config.AgentVersion, req.Credentials, req.Config.Azure)
if err != nil {
return nil, err
}
return &cloudintegrationtypes.ConnectionArtifact{
Azure: connectionArtifact,
}, nil
}
func (provider *azurecloudprovider) ListServiceDefinitions(ctx context.Context) ([]*cloudintegrationtypes.ServiceDefinition, error) {
panic("implement me")
return provider.serviceDefinitions.List(ctx, cloudintegrationtypes.CloudProviderTypeAzure)
}
func (provider *azurecloudprovider) GetServiceDefinition(ctx context.Context, serviceID cloudintegrationtypes.ServiceID) (*cloudintegrationtypes.ServiceDefinition, error) {
panic("implement me")
serviceDef, err := provider.serviceDefinitions.Get(ctx, cloudintegrationtypes.CloudProviderTypeAzure, serviceID)
if err != nil {
return nil, err
}
// override cloud integration dashboard id.
for index, dashboard := range serviceDef.Assets.Dashboards {
serviceDef.Assets.Dashboards[index].ID = cloudintegrationtypes.GetCloudIntegrationDashboardID(cloudintegrationtypes.CloudProviderTypeAzure, serviceID.StringValue(), dashboard.ID)
}
return serviceDef, nil
}
func (provider *azurecloudprovider) BuildIntegrationConfig(
@@ -30,5 +51,56 @@ func (provider *azurecloudprovider) BuildIntegrationConfig(
account *cloudintegrationtypes.Account,
services []*cloudintegrationtypes.StorableCloudIntegrationService,
) (*cloudintegrationtypes.ProviderIntegrationConfig, error) {
panic("implement me")
sort.Slice(services, func(i, j int) bool {
return services[i].Type.StringValue() < services[j].Type.StringValue()
})
var strategies []*cloudintegrationtypes.AzureTelemetryCollectionStrategy
for _, storedSvc := range services {
svcCfg, err := cloudintegrationtypes.NewServiceConfigFromJSON(cloudintegrationtypes.CloudProviderTypeAzure, storedSvc.Config)
if err != nil {
return nil, err
}
svcDef, err := provider.GetServiceDefinition(ctx, storedSvc.Type)
if err != nil {
return nil, err
}
strategy := svcDef.TelemetryCollectionStrategy.Azure
if strategy == nil {
continue
}
logsEnabled := svcCfg.IsLogsEnabled(cloudintegrationtypes.CloudProviderTypeAzure)
metricsEnabled := svcCfg.IsMetricsEnabled(cloudintegrationtypes.CloudProviderTypeAzure)
if !logsEnabled && !metricsEnabled {
continue
}
entry := &cloudintegrationtypes.AzureTelemetryCollectionStrategy{
ResourceProvider: strategy.ResourceProvider,
ResourceType: strategy.ResourceType,
}
if metricsEnabled && strategy.Metrics != nil {
entry.Metrics = strategy.Metrics
}
if logsEnabled && strategy.Logs != nil {
entry.Logs = strategy.Logs
}
strategies = append(strategies, entry)
}
return &cloudintegrationtypes.ProviderIntegrationConfig{
Azure: cloudintegrationtypes.NewAzureIntegrationConfig(
account.Config.Azure.DeploymentRegion,
account.Config.Azure.ResourceGroups,
strategies,
),
}, nil
}

View File

@@ -429,9 +429,13 @@ func (module *module) Collect(ctx context.Context, orgID valuer.UUID) (map[strin
stats["cloudintegration.aws.connectedaccounts.count"] = awsAccountsCount
}
// NOTE: not adding stats for services for now.
// get connected accounts for Azure
azureAccountsCount, err := module.store.CountConnectedAccounts(ctx, orgID, cloudintegrationtypes.CloudProviderTypeAzure)
if err == nil {
stats["cloudintegration.azure.connectedaccounts.count"] = azureAccountsCount
}
// TODO: add more cloud providers when supported
// NOTE: not adding stats for services for now.
return stats, nil
}

5
frontend/knip.json Normal file
View File

@@ -0,0 +1,5 @@
{
"$schema": "https://unpkg.com/knip@5/schema.json",
"project": ["src/**/*.ts", "src/**/*.tsx"],
"ignore": ["src/api/generated/**/*.ts"]
}

View File

@@ -212,9 +212,9 @@
"msw": "1.3.2",
"npm-run-all": "latest",
"orval": "7.18.0",
"oxfmt": "0.46.0",
"oxlint": "1.61.0",
"oxlint-tsgolint": "0.21.1",
"oxfmt": "0.47.0",
"oxlint": "1.62.0",
"oxlint-tsgolint": "0.22.1",
"portfinder-sync": "^0.0.2",
"postcss": "8.5.6",
"postcss-scss": "4.0.9",
@@ -238,9 +238,12 @@
},
"lint-staged": {
"*.(js|jsx|ts|tsx)": [
"oxfmt --check",
"oxlint --quiet",
"oxlint --fix",
"oxfmt --write",
"sh scripts/typecheck-staged.sh"
],
"*.(scss|css)": [
"stylelint"
]
},
"resolutions": {

View File

@@ -104,7 +104,7 @@ describe('getFieldKeys API', () => {
const result = await getFieldKeys('traces');
// Verify the returned structure matches SuccessResponseV2 format
expect(result).toEqual({
expect(result).toStrictEqual({
httpStatusCode: 200,
data: mockSuccessResponse.data.data,
});

View File

@@ -199,7 +199,7 @@ describe('getFieldValues API', () => {
const result = await getFieldValues('traces', 'service.name');
// Verify the returned structure matches SuccessResponseV2 format
expect(result).toEqual({
expect(result).toStrictEqual({
httpStatusCode: 200,
data: expect.objectContaining({
values: expect.any(Object),

View File

@@ -12,8 +12,16 @@ import type {
} from 'react-query';
import type {
InframonitoringtypesPostableClustersDTO,
InframonitoringtypesPostableHostsDTO,
InframonitoringtypesPostableNamespacesDTO,
InframonitoringtypesPostableNodesDTO,
InframonitoringtypesPostablePodsDTO,
ListClusters200,
ListHosts200,
ListNamespaces200,
ListNodes200,
ListPods200,
RenderErrorResponseDTO,
} from '../sigNoz.schemas';
@@ -21,7 +29,91 @@ import { GeneratedAPIInstance } from '../../../generatedAPIInstance';
import type { ErrorType, BodyType } from '../../../generatedAPIInstance';
/**
* Returns a paginated list of hosts with key infrastructure metrics: CPU usage (%), memory usage (%), I/O wait (%), disk usage (%), and 15-minute load average. Each host includes its current status (active/inactive based on metrics reported in the last 10 minutes) and metadata attributes (e.g., os.type). Supports filtering via a filter expression, filtering by host status, custom groupBy to aggregate hosts by any attribute, ordering by any of the five metrics, and pagination via offset/limit. The response type is 'list' for the default host.name grouping or 'grouped_list' for custom groupBy keys. Also reports missing required metrics and whether the requested time range falls before the data retention boundary.
* Returns a paginated list of Kubernetes clusters with key aggregated metrics derived by summing per-node values within the group: CPU usage, CPU allocatable, memory working set, memory allocatable. Each row also reports per-group node counts bucketed by each node's latest k8s.node.condition_ready value (readyNodesCount, notReadyNodesCount) and per-group pod counts bucketed by each pod's latest k8s.pod.phase value (pendingPodCount, runningPodCount, succeededPodCount, failedPodCount, unknownPodCount). Each cluster includes metadata attributes (k8s.cluster.name). The response type is 'list' for the default k8s.cluster.name grouping or 'grouped_list' for custom groupBy keys; in both modes every row aggregates nodes and pods in the group. Supports filtering via a filter expression, custom groupBy, ordering by cpu / cpu_allocatable / memory / memory_allocatable, and pagination via offset/limit. Also reports missing required metrics and whether the requested time range falls before the data retention boundary. Numeric metric fields (clusterCPU, clusterCPUAllocatable, clusterMemory, clusterMemoryAllocatable) return -1 as a sentinel when no data is available for that field.
* @summary List Clusters for Infra Monitoring
*/
export const listClusters = (
inframonitoringtypesPostableClustersDTO: BodyType<InframonitoringtypesPostableClustersDTO>,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<ListClusters200>({
url: `/api/v2/infra_monitoring/clusters`,
method: 'POST',
headers: { 'Content-Type': 'application/json' },
data: inframonitoringtypesPostableClustersDTO,
signal,
});
};
export const getListClustersMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof listClusters>>,
TError,
{ data: BodyType<InframonitoringtypesPostableClustersDTO> },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof listClusters>>,
TError,
{ data: BodyType<InframonitoringtypesPostableClustersDTO> },
TContext
> => {
const mutationKey = ['listClusters'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof listClusters>>,
{ data: BodyType<InframonitoringtypesPostableClustersDTO> }
> = (props) => {
const { data } = props ?? {};
return listClusters(data);
};
return { mutationFn, ...mutationOptions };
};
export type ListClustersMutationResult = NonNullable<
Awaited<ReturnType<typeof listClusters>>
>;
export type ListClustersMutationBody =
BodyType<InframonitoringtypesPostableClustersDTO>;
export type ListClustersMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary List Clusters for Infra Monitoring
*/
export const useListClusters = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof listClusters>>,
TError,
{ data: BodyType<InframonitoringtypesPostableClustersDTO> },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof listClusters>>,
TError,
{ data: BodyType<InframonitoringtypesPostableClustersDTO> },
TContext
> => {
const mutationOptions = getListClustersMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* Returns a paginated list of hosts with key infrastructure metrics: CPU usage (%), memory usage (%), I/O wait (%), disk usage (%), and 15-minute load average. Each host includes its current status (active/inactive based on metrics reported in the last 10 minutes) and metadata attributes (e.g., os.type). Supports filtering via a filter expression, filtering by host status, custom groupBy to aggregate hosts by any attribute, ordering by any of the five metrics, and pagination via offset/limit. The response type is 'list' for the default host.name grouping or 'grouped_list' for custom groupBy keys. Also reports missing required metrics and whether the requested time range falls before the data retention boundary. Numeric metric fields (cpu, memory, wait, load15, diskUsage) return -1 as a sentinel when no data is available for that field.
* @summary List Hosts for Infra Monitoring
*/
export const listHosts = (
@@ -104,3 +196,255 @@ export const useListHosts = <
return useMutation(mutationOptions);
};
/**
* Returns a paginated list of Kubernetes namespaces with key aggregated pod metrics: CPU usage and memory working set (summed across pods in the group), plus per-group pod counts bucketed by each pod's latest k8s.pod.phase value in the window (pendingPodCount, runningPodCount, succeededPodCount, failedPodCount, unknownPodCount). Each namespace includes metadata attributes (k8s.namespace.name, k8s.cluster.name). The response type is 'list' for the default k8s.namespace.name grouping or 'grouped_list' for custom groupBy keys; in both modes every row aggregates pods in the group. Supports filtering via a filter expression, custom groupBy, ordering by cpu / memory, and pagination via offset/limit. Also reports missing required metrics and whether the requested time range falls before the data retention boundary. Numeric metric fields (namespaceCPU, namespaceMemory) return -1 as a sentinel when no data is available for that field.
* @summary List Namespaces for Infra Monitoring
*/
export const listNamespaces = (
inframonitoringtypesPostableNamespacesDTO: BodyType<InframonitoringtypesPostableNamespacesDTO>,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<ListNamespaces200>({
url: `/api/v2/infra_monitoring/namespaces`,
method: 'POST',
headers: { 'Content-Type': 'application/json' },
data: inframonitoringtypesPostableNamespacesDTO,
signal,
});
};
export const getListNamespacesMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof listNamespaces>>,
TError,
{ data: BodyType<InframonitoringtypesPostableNamespacesDTO> },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof listNamespaces>>,
TError,
{ data: BodyType<InframonitoringtypesPostableNamespacesDTO> },
TContext
> => {
const mutationKey = ['listNamespaces'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof listNamespaces>>,
{ data: BodyType<InframonitoringtypesPostableNamespacesDTO> }
> = (props) => {
const { data } = props ?? {};
return listNamespaces(data);
};
return { mutationFn, ...mutationOptions };
};
export type ListNamespacesMutationResult = NonNullable<
Awaited<ReturnType<typeof listNamespaces>>
>;
export type ListNamespacesMutationBody =
BodyType<InframonitoringtypesPostableNamespacesDTO>;
export type ListNamespacesMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary List Namespaces for Infra Monitoring
*/
export const useListNamespaces = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof listNamespaces>>,
TError,
{ data: BodyType<InframonitoringtypesPostableNamespacesDTO> },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof listNamespaces>>,
TError,
{ data: BodyType<InframonitoringtypesPostableNamespacesDTO> },
TContext
> => {
const mutationOptions = getListNamespacesMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* Returns a paginated list of Kubernetes nodes with key metrics: CPU usage, CPU allocatable, memory working set, memory allocatable, and per-group readyNodesCount / notReadyNodesCount derived from each node's latest k8s.node.condition_ready value in the window. Each node includes metadata attributes (k8s.node.uid, k8s.cluster.name). The response type is 'list' for the default k8s.node.name grouping (each row is one node with its current condition string: ready / not_ready / '') or 'grouped_list' for custom groupBy keys (each row aggregates nodes in the group with readyNodesCount and notReadyNodesCount; condition stays empty). Supports filtering via a filter expression, custom groupBy, ordering by cpu / cpu_allocatable / memory / memory_allocatable, and pagination via offset/limit. Also reports missing required metrics and whether the requested time range falls before the data retention boundary. Numeric metric fields (nodeCPU, nodeCPUAllocatable, nodeMemory, nodeMemoryAllocatable) return -1 as a sentinel when no data is available for that field.
* @summary List Nodes for Infra Monitoring
*/
export const listNodes = (
inframonitoringtypesPostableNodesDTO: BodyType<InframonitoringtypesPostableNodesDTO>,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<ListNodes200>({
url: `/api/v2/infra_monitoring/nodes`,
method: 'POST',
headers: { 'Content-Type': 'application/json' },
data: inframonitoringtypesPostableNodesDTO,
signal,
});
};
export const getListNodesMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof listNodes>>,
TError,
{ data: BodyType<InframonitoringtypesPostableNodesDTO> },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof listNodes>>,
TError,
{ data: BodyType<InframonitoringtypesPostableNodesDTO> },
TContext
> => {
const mutationKey = ['listNodes'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof listNodes>>,
{ data: BodyType<InframonitoringtypesPostableNodesDTO> }
> = (props) => {
const { data } = props ?? {};
return listNodes(data);
};
return { mutationFn, ...mutationOptions };
};
export type ListNodesMutationResult = NonNullable<
Awaited<ReturnType<typeof listNodes>>
>;
export type ListNodesMutationBody =
BodyType<InframonitoringtypesPostableNodesDTO>;
export type ListNodesMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary List Nodes for Infra Monitoring
*/
export const useListNodes = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof listNodes>>,
TError,
{ data: BodyType<InframonitoringtypesPostableNodesDTO> },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof listNodes>>,
TError,
{ data: BodyType<InframonitoringtypesPostableNodesDTO> },
TContext
> => {
const mutationOptions = getListNodesMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* Returns a paginated list of Kubernetes pods with key metrics: CPU usage, CPU request/limit utilization, memory working set, memory request/limit utilization, current pod phase (pending/running/succeeded/failed/unknown), and pod age (ms since start time). Each pod includes metadata attributes (namespace, node, workload owner such as deployment/statefulset/daemonset/job/cronjob, cluster). Supports filtering via a filter expression, custom groupBy to aggregate pods by any attribute, ordering by any of the six metrics (cpu, cpu_request, cpu_limit, memory, memory_request, memory_limit), and pagination via offset/limit. The response type is 'list' for the default k8s.pod.uid grouping (each row is one pod with its current phase) or 'grouped_list' for custom groupBy keys (each row aggregates pods in the group with per-phase counts: pendingPodCount, runningPodCount, succeededPodCount, failedPodCount, unknownPodCount derived from each pod's latest phase in the window). Also reports missing required metrics and whether the requested time range falls before the data retention boundary. Numeric metric fields (podCPU, podCPURequest, podCPULimit, podMemory, podMemoryRequest, podMemoryLimit, podAge) return -1 as a sentinel when no data is available for that field.
* @summary List Pods for Infra Monitoring
*/
export const listPods = (
inframonitoringtypesPostablePodsDTO: BodyType<InframonitoringtypesPostablePodsDTO>,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<ListPods200>({
url: `/api/v2/infra_monitoring/pods`,
method: 'POST',
headers: { 'Content-Type': 'application/json' },
data: inframonitoringtypesPostablePodsDTO,
signal,
});
};
export const getListPodsMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof listPods>>,
TError,
{ data: BodyType<InframonitoringtypesPostablePodsDTO> },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof listPods>>,
TError,
{ data: BodyType<InframonitoringtypesPostablePodsDTO> },
TContext
> => {
const mutationKey = ['listPods'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof listPods>>,
{ data: BodyType<InframonitoringtypesPostablePodsDTO> }
> = (props) => {
const { data } = props ?? {};
return listPods(data);
};
return { mutationFn, ...mutationOptions };
};
export type ListPodsMutationResult = NonNullable<
Awaited<ReturnType<typeof listPods>>
>;
export type ListPodsMutationBody =
BodyType<InframonitoringtypesPostablePodsDTO>;
export type ListPodsMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary List Pods for Infra Monitoring
*/
export const useListPods = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof listPods>>,
TError,
{ data: BodyType<InframonitoringtypesPostablePodsDTO> },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof listPods>>,
TError,
{ data: BodyType<InframonitoringtypesPostablePodsDTO> },
TContext
> => {
const mutationOptions = getListPodsMutationOptions(options);
return useMutation(mutationOptions);
};

View File

@@ -3158,6 +3158,92 @@ export interface GlobaltypesTokenizerConfigDTO {
enabled?: boolean;
}
/**
* @nullable
*/
export type InframonitoringtypesClusterRecordDTOMeta = {
[key: string]: unknown;
} | null;
export interface InframonitoringtypesClusterRecordDTO {
/**
* @type number
* @format double
*/
clusterCPU: number;
/**
* @type number
* @format double
*/
clusterCPUAllocatable: number;
/**
* @type number
* @format double
*/
clusterMemory: number;
/**
* @type number
* @format double
*/
clusterMemoryAllocatable: number;
/**
* @type string
*/
clusterName: string;
/**
* @type integer
*/
failedPodCount: number;
/**
* @type object
* @nullable true
*/
meta: InframonitoringtypesClusterRecordDTOMeta;
/**
* @type integer
*/
notReadyNodesCount: number;
/**
* @type integer
*/
pendingPodCount: number;
/**
* @type integer
*/
readyNodesCount: number;
/**
* @type integer
*/
runningPodCount: number;
/**
* @type integer
*/
succeededPodCount: number;
/**
* @type integer
*/
unknownPodCount: number;
}
export interface InframonitoringtypesClustersDTO {
/**
* @type boolean
*/
endTimeBeforeRetention: boolean;
/**
* @type array
* @nullable true
*/
records: InframonitoringtypesClusterRecordDTO[] | null;
requiredMetricsCheck: InframonitoringtypesRequiredMetricsCheckDTO;
/**
* @type integer
*/
total: number;
type: InframonitoringtypesResponseTypeDTO;
warning?: Querybuildertypesv5QueryWarnDataDTO;
}
export interface InframonitoringtypesHostFilterDTO {
/**
* @type string
@@ -3243,6 +3329,276 @@ export interface InframonitoringtypesHostsDTO {
warning?: Querybuildertypesv5QueryWarnDataDTO;
}
/**
* @nullable
*/
export type InframonitoringtypesNamespaceRecordDTOMeta = {
[key: string]: unknown;
} | null;
export interface InframonitoringtypesNamespaceRecordDTO {
/**
* @type integer
*/
failedPodCount: number;
/**
* @type object
* @nullable true
*/
meta: InframonitoringtypesNamespaceRecordDTOMeta;
/**
* @type number
* @format double
*/
namespaceCPU: number;
/**
* @type number
* @format double
*/
namespaceMemory: number;
/**
* @type string
*/
namespaceName: string;
/**
* @type integer
*/
pendingPodCount: number;
/**
* @type integer
*/
runningPodCount: number;
/**
* @type integer
*/
succeededPodCount: number;
/**
* @type integer
*/
unknownPodCount: number;
}
export interface InframonitoringtypesNamespacesDTO {
/**
* @type boolean
*/
endTimeBeforeRetention: boolean;
/**
* @type array
* @nullable true
*/
records: InframonitoringtypesNamespaceRecordDTO[] | null;
requiredMetricsCheck: InframonitoringtypesRequiredMetricsCheckDTO;
/**
* @type integer
*/
total: number;
type: InframonitoringtypesResponseTypeDTO;
warning?: Querybuildertypesv5QueryWarnDataDTO;
}
export enum InframonitoringtypesNodeConditionDTO {
ready = 'ready',
not_ready = 'not_ready',
'' = '',
}
/**
* @nullable
*/
export type InframonitoringtypesNodeRecordDTOMeta = {
[key: string]: unknown;
} | null;
export interface InframonitoringtypesNodeRecordDTO {
condition: InframonitoringtypesNodeConditionDTO;
/**
* @type object
* @nullable true
*/
meta: InframonitoringtypesNodeRecordDTOMeta;
/**
* @type number
* @format double
*/
nodeCPU: number;
/**
* @type number
* @format double
*/
nodeCPUAllocatable: number;
/**
* @type number
* @format double
*/
nodeMemory: number;
/**
* @type number
* @format double
*/
nodeMemoryAllocatable: number;
/**
* @type string
*/
nodeName: string;
/**
* @type integer
*/
notReadyNodesCount: number;
/**
* @type integer
*/
readyNodesCount: number;
}
export interface InframonitoringtypesNodesDTO {
/**
* @type boolean
*/
endTimeBeforeRetention: boolean;
/**
* @type array
* @nullable true
*/
records: InframonitoringtypesNodeRecordDTO[] | null;
requiredMetricsCheck: InframonitoringtypesRequiredMetricsCheckDTO;
/**
* @type integer
*/
total: number;
type: InframonitoringtypesResponseTypeDTO;
warning?: Querybuildertypesv5QueryWarnDataDTO;
}
export enum InframonitoringtypesPodPhaseDTO {
pending = 'pending',
running = 'running',
succeeded = 'succeeded',
failed = 'failed',
unknown = 'unknown',
'' = '',
}
/**
* @nullable
*/
export type InframonitoringtypesPodRecordDTOMeta = {
[key: string]: unknown;
} | null;
export interface InframonitoringtypesPodRecordDTO {
/**
* @type integer
*/
failedPodCount: number;
/**
* @type object
* @nullable true
*/
meta: InframonitoringtypesPodRecordDTOMeta;
/**
* @type integer
*/
pendingPodCount: number;
/**
* @type integer
* @format int64
*/
podAge: number;
/**
* @type number
* @format double
*/
podCPU: number;
/**
* @type number
* @format double
*/
podCPULimit: number;
/**
* @type number
* @format double
*/
podCPURequest: number;
/**
* @type number
* @format double
*/
podMemory: number;
/**
* @type number
* @format double
*/
podMemoryLimit: number;
/**
* @type number
* @format double
*/
podMemoryRequest: number;
podPhase: InframonitoringtypesPodPhaseDTO;
/**
* @type string
*/
podUID: string;
/**
* @type integer
*/
runningPodCount: number;
/**
* @type integer
*/
succeededPodCount: number;
/**
* @type integer
*/
unknownPodCount: number;
}
export interface InframonitoringtypesPodsDTO {
/**
* @type boolean
*/
endTimeBeforeRetention: boolean;
/**
* @type array
* @nullable true
*/
records: InframonitoringtypesPodRecordDTO[] | null;
requiredMetricsCheck: InframonitoringtypesRequiredMetricsCheckDTO;
/**
* @type integer
*/
total: number;
type: InframonitoringtypesResponseTypeDTO;
warning?: Querybuildertypesv5QueryWarnDataDTO;
}
export interface InframonitoringtypesPostableClustersDTO {
/**
* @type integer
* @format int64
*/
end: number;
filter?: Querybuildertypesv5FilterDTO;
/**
* @type array
* @nullable true
*/
groupBy?: Querybuildertypesv5GroupByKeyDTO[] | null;
/**
* @type integer
*/
limit: number;
/**
* @type integer
*/
offset?: number;
orderBy?: Querybuildertypesv5OrderByDTO;
/**
* @type integer
* @format int64
*/
start: number;
}
export interface InframonitoringtypesPostableHostsDTO {
/**
* @type integer
@@ -3271,6 +3627,90 @@ export interface InframonitoringtypesPostableHostsDTO {
start: number;
}
export interface InframonitoringtypesPostableNamespacesDTO {
/**
* @type integer
* @format int64
*/
end: number;
filter?: Querybuildertypesv5FilterDTO;
/**
* @type array
* @nullable true
*/
groupBy?: Querybuildertypesv5GroupByKeyDTO[] | null;
/**
* @type integer
*/
limit: number;
/**
* @type integer
*/
offset?: number;
orderBy?: Querybuildertypesv5OrderByDTO;
/**
* @type integer
* @format int64
*/
start: number;
}
export interface InframonitoringtypesPostableNodesDTO {
/**
* @type integer
* @format int64
*/
end: number;
filter?: Querybuildertypesv5FilterDTO;
/**
* @type array
* @nullable true
*/
groupBy?: Querybuildertypesv5GroupByKeyDTO[] | null;
/**
* @type integer
*/
limit: number;
/**
* @type integer
*/
offset?: number;
orderBy?: Querybuildertypesv5OrderByDTO;
/**
* @type integer
* @format int64
*/
start: number;
}
export interface InframonitoringtypesPostablePodsDTO {
/**
* @type integer
* @format int64
*/
end: number;
filter?: Querybuildertypesv5FilterDTO;
/**
* @type array
* @nullable true
*/
groupBy?: Querybuildertypesv5GroupByKeyDTO[] | null;
/**
* @type integer
*/
limit: number;
/**
* @type integer
*/
offset?: number;
orderBy?: Querybuildertypesv5OrderByDTO;
/**
* @type integer
* @format int64
*/
start: number;
}
export interface InframonitoringtypesRequiredMetricsCheckDTO {
/**
* @type array
@@ -3701,10 +4141,7 @@ export interface PromotetypesPromotePathDTO {
}
export interface PromotetypesWrappedIndexDTO {
/**
* @type string
*/
column_type?: string;
fieldDataType?: TelemetrytypesFieldDataTypeDTO;
/**
* @type integer
*/
@@ -5475,6 +5912,187 @@ export interface Sigv4SigV4ConfigDTO {
[key: string]: unknown;
}
export enum SpantypesFieldContextDTO {
attribute = 'attribute',
resource = 'resource',
}
export interface SpantypesGettableSpanMapperGroupsDTO {
/**
* @type array
*/
items: SpantypesSpanMapperGroupDTO[];
}
export interface SpantypesPostableSpanMapperDTO {
config: SpantypesSpanMapperConfigDTO;
/**
* @type boolean
*/
enabled?: boolean;
field_context: SpantypesFieldContextDTO;
/**
* @type string
*/
name: string;
}
export interface SpantypesPostableSpanMapperGroupDTO {
category: SpantypesSpanMapperGroupCategoryDTO;
condition: SpantypesSpanMapperGroupConditionDTO;
/**
* @type boolean
*/
enabled?: boolean;
/**
* @type string
*/
name: string;
}
export interface SpantypesSpanMapperDTO {
config: SpantypesSpanMapperConfigDTO;
/**
* @type string
* @format date-time
*/
createdAt?: Date;
/**
* @type string
*/
createdBy?: string;
/**
* @type boolean
*/
enabled: boolean;
field_context: SpantypesFieldContextDTO;
/**
* @type string
*/
group_id: string;
/**
* @type string
*/
id: string;
/**
* @type string
*/
name: string;
/**
* @type string
* @format date-time
*/
updatedAt?: Date;
/**
* @type string
*/
updatedBy?: string;
}
export interface SpantypesSpanMapperConfigDTO {
/**
* @type array
* @nullable true
*/
sources: SpantypesSpanMapperSourceDTO[] | null;
}
export interface SpantypesSpanMapperGroupDTO {
category: SpantypesSpanMapperGroupCategoryDTO;
condition: SpantypesSpanMapperGroupConditionDTO;
/**
* @type string
* @format date-time
*/
createdAt?: Date;
/**
* @type string
*/
createdBy?: string;
/**
* @type boolean
*/
enabled: boolean;
/**
* @type string
*/
id: string;
/**
* @type string
*/
name: string;
/**
* @type string
*/
orgId: string;
/**
* @type string
* @format date-time
*/
updatedAt?: Date;
/**
* @type string
*/
updatedBy?: string;
}
export interface SpantypesSpanMapperGroupCategoryDTO {
[key: string]: unknown;
}
export interface SpantypesSpanMapperGroupConditionDTO {
/**
* @type array
* @nullable true
*/
attributes: string[] | null;
/**
* @type array
* @nullable true
*/
resource: string[] | null;
}
export enum SpantypesSpanMapperOperationDTO {
move = 'move',
copy = 'copy',
}
export interface SpantypesSpanMapperSourceDTO {
context: SpantypesFieldContextDTO;
/**
* @type string
*/
key: string;
operation: SpantypesSpanMapperOperationDTO;
/**
* @type integer
*/
priority: number;
}
export interface SpantypesUpdatableSpanMapperDTO {
config?: SpantypesSpanMapperConfigDTO;
/**
* @type boolean
* @nullable true
*/
enabled?: boolean | null;
field_context?: SpantypesFieldContextDTO;
}
export interface SpantypesUpdatableSpanMapperGroupDTO {
condition?: SpantypesSpanMapperGroupConditionDTO;
/**
* @type boolean
* @nullable true
*/
enabled?: boolean | null;
/**
* @type string
* @nullable true
*/
name?: string | null;
}
export enum TelemetrytypesFieldContextDTO {
metric = 'metric',
log = 'log',
@@ -6925,6 +7543,71 @@ export type GetMyServiceAccount200 = {
status: string;
};
export type ListSpanMapperGroupsParams = {
/**
* @description undefined
*/
category?: SpantypesSpanMapperGroupCategoryDTO;
/**
* @type boolean
* @nullable true
* @description undefined
*/
enabled?: boolean | null;
};
export type ListSpanMapperGroups200 = {
data: SpantypesGettableSpanMapperGroupsDTO;
/**
* @type string
*/
status: string;
};
export type CreateSpanMapperGroup201 = {
data: SpantypesSpanMapperGroupDTO;
/**
* @type string
*/
status: string;
};
export type DeleteSpanMapperGroupPathParameters = {
groupId: string;
};
export type UpdateSpanMapperGroupPathParameters = {
groupId: string;
};
export type ListSpanMappersPathParameters = {
groupId: string;
};
export type ListSpanMappers200 = {
data: SpantypesGettableSpanMapperGroupsDTO;
/**
* @type string
*/
status: string;
};
export type CreateSpanMapperPathParameters = {
groupId: string;
};
export type CreateSpanMapper201 = {
data: SpantypesSpanMapperDTO;
/**
* @type string
*/
status: string;
};
export type DeleteSpanMapperPathParameters = {
groupId: string;
mapperId: string;
};
export type UpdateSpanMapperPathParameters = {
groupId: string;
mapperId: string;
};
export type ListUsersDeprecated200 = {
/**
* @type array
@@ -7099,6 +7782,14 @@ export type Healthz503 = {
status: string;
};
export type ListClusters200 = {
data: InframonitoringtypesClustersDTO;
/**
* @type string
*/
status: string;
};
export type ListHosts200 = {
data: InframonitoringtypesHostsDTO;
/**
@@ -7107,6 +7798,30 @@ export type ListHosts200 = {
status: string;
};
export type ListNamespaces200 = {
data: InframonitoringtypesNamespacesDTO;
/**
* @type string
*/
status: string;
};
export type ListNodes200 = {
data: InframonitoringtypesNodesDTO;
/**
* @type string
*/
status: string;
};
export type ListPods200 = {
data: InframonitoringtypesPodsDTO;
/**
* @type string
*/
status: string;
};
export type Livez200 = {
data: FactoryResponseDTO;
/**

View File

@@ -0,0 +1,787 @@
/**
* ! Do not edit manually
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'yarn generate:api'
* SigNoz
*/
import { useMutation, useQuery } from 'react-query';
import type {
InvalidateOptions,
MutationFunction,
QueryClient,
QueryFunction,
QueryKey,
UseMutationOptions,
UseMutationResult,
UseQueryOptions,
UseQueryResult,
} from 'react-query';
import type {
CreateSpanMapper201,
CreateSpanMapperGroup201,
CreateSpanMapperPathParameters,
DeleteSpanMapperGroupPathParameters,
DeleteSpanMapperPathParameters,
ListSpanMapperGroups200,
ListSpanMapperGroupsParams,
ListSpanMappers200,
ListSpanMappersPathParameters,
RenderErrorResponseDTO,
SpantypesPostableSpanMapperDTO,
SpantypesPostableSpanMapperGroupDTO,
SpantypesUpdatableSpanMapperDTO,
SpantypesUpdatableSpanMapperGroupDTO,
UpdateSpanMapperGroupPathParameters,
UpdateSpanMapperPathParameters,
} from '../sigNoz.schemas';
import { GeneratedAPIInstance } from '../../../generatedAPIInstance';
import type { ErrorType, BodyType } from '../../../generatedAPIInstance';
/**
* Returns all span attribute mapping groups for the authenticated org.
* @summary List span attribute mapping groups
*/
export const listSpanMapperGroups = (
params?: ListSpanMapperGroupsParams,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<ListSpanMapperGroups200>({
url: `/api/v1/span_mapper_groups`,
method: 'GET',
params,
signal,
});
};
export const getListSpanMapperGroupsQueryKey = (
params?: ListSpanMapperGroupsParams,
) => {
return [`/api/v1/span_mapper_groups`, ...(params ? [params] : [])] as const;
};
export const getListSpanMapperGroupsQueryOptions = <
TData = Awaited<ReturnType<typeof listSpanMapperGroups>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
params?: ListSpanMapperGroupsParams,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listSpanMapperGroups>>,
TError,
TData
>;
},
) => {
const { query: queryOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getListSpanMapperGroupsQueryKey(params);
const queryFn: QueryFunction<
Awaited<ReturnType<typeof listSpanMapperGroups>>
> = ({ signal }) => listSpanMapperGroups(params, signal);
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
Awaited<ReturnType<typeof listSpanMapperGroups>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type ListSpanMapperGroupsQueryResult = NonNullable<
Awaited<ReturnType<typeof listSpanMapperGroups>>
>;
export type ListSpanMapperGroupsQueryError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary List span attribute mapping groups
*/
export function useListSpanMapperGroups<
TData = Awaited<ReturnType<typeof listSpanMapperGroups>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
params?: ListSpanMapperGroupsParams,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listSpanMapperGroups>>,
TError,
TData
>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getListSpanMapperGroupsQueryOptions(params, options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
query.queryKey = queryOptions.queryKey;
return query;
}
/**
* @summary List span attribute mapping groups
*/
export const invalidateListSpanMapperGroups = async (
queryClient: QueryClient,
params?: ListSpanMapperGroupsParams,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getListSpanMapperGroupsQueryKey(params) },
options,
);
return queryClient;
};
/**
* Creates a new span attribute mapping group for the org.
* @summary Create a span attribute mapping group
*/
export const createSpanMapperGroup = (
spantypesPostableSpanMapperGroupDTO: BodyType<SpantypesPostableSpanMapperGroupDTO>,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<CreateSpanMapperGroup201>({
url: `/api/v1/span_mapper_groups`,
method: 'POST',
headers: { 'Content-Type': 'application/json' },
data: spantypesPostableSpanMapperGroupDTO,
signal,
});
};
export const getCreateSpanMapperGroupMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof createSpanMapperGroup>>,
TError,
{ data: BodyType<SpantypesPostableSpanMapperGroupDTO> },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof createSpanMapperGroup>>,
TError,
{ data: BodyType<SpantypesPostableSpanMapperGroupDTO> },
TContext
> => {
const mutationKey = ['createSpanMapperGroup'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof createSpanMapperGroup>>,
{ data: BodyType<SpantypesPostableSpanMapperGroupDTO> }
> = (props) => {
const { data } = props ?? {};
return createSpanMapperGroup(data);
};
return { mutationFn, ...mutationOptions };
};
export type CreateSpanMapperGroupMutationResult = NonNullable<
Awaited<ReturnType<typeof createSpanMapperGroup>>
>;
export type CreateSpanMapperGroupMutationBody =
BodyType<SpantypesPostableSpanMapperGroupDTO>;
export type CreateSpanMapperGroupMutationError =
ErrorType<RenderErrorResponseDTO>;
/**
* @summary Create a span attribute mapping group
*/
export const useCreateSpanMapperGroup = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof createSpanMapperGroup>>,
TError,
{ data: BodyType<SpantypesPostableSpanMapperGroupDTO> },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof createSpanMapperGroup>>,
TError,
{ data: BodyType<SpantypesPostableSpanMapperGroupDTO> },
TContext
> => {
const mutationOptions = getCreateSpanMapperGroupMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* Hard-deletes a mapping group and cascades to all its mappers.
* @summary Delete a span attribute mapping group
*/
export const deleteSpanMapperGroup = ({
groupId,
}: DeleteSpanMapperGroupPathParameters) => {
return GeneratedAPIInstance<void>({
url: `/api/v1/span_mapper_groups/${groupId}`,
method: 'DELETE',
});
};
export const getDeleteSpanMapperGroupMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteSpanMapperGroup>>,
TError,
{ pathParams: DeleteSpanMapperGroupPathParameters },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof deleteSpanMapperGroup>>,
TError,
{ pathParams: DeleteSpanMapperGroupPathParameters },
TContext
> => {
const mutationKey = ['deleteSpanMapperGroup'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof deleteSpanMapperGroup>>,
{ pathParams: DeleteSpanMapperGroupPathParameters }
> = (props) => {
const { pathParams } = props ?? {};
return deleteSpanMapperGroup(pathParams);
};
return { mutationFn, ...mutationOptions };
};
export type DeleteSpanMapperGroupMutationResult = NonNullable<
Awaited<ReturnType<typeof deleteSpanMapperGroup>>
>;
export type DeleteSpanMapperGroupMutationError =
ErrorType<RenderErrorResponseDTO>;
/**
* @summary Delete a span attribute mapping group
*/
export const useDeleteSpanMapperGroup = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteSpanMapperGroup>>,
TError,
{ pathParams: DeleteSpanMapperGroupPathParameters },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof deleteSpanMapperGroup>>,
TError,
{ pathParams: DeleteSpanMapperGroupPathParameters },
TContext
> => {
const mutationOptions = getDeleteSpanMapperGroupMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* Partially updates an existing mapping group's name, condition, or enabled state.
* @summary Update a span attribute mapping group
*/
export const updateSpanMapperGroup = (
{ groupId }: UpdateSpanMapperGroupPathParameters,
spantypesUpdatableSpanMapperGroupDTO: BodyType<SpantypesUpdatableSpanMapperGroupDTO>,
) => {
return GeneratedAPIInstance<void>({
url: `/api/v1/span_mapper_groups/${groupId}`,
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
data: spantypesUpdatableSpanMapperGroupDTO,
});
};
export const getUpdateSpanMapperGroupMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof updateSpanMapperGroup>>,
TError,
{
pathParams: UpdateSpanMapperGroupPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperGroupDTO>;
},
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof updateSpanMapperGroup>>,
TError,
{
pathParams: UpdateSpanMapperGroupPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperGroupDTO>;
},
TContext
> => {
const mutationKey = ['updateSpanMapperGroup'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof updateSpanMapperGroup>>,
{
pathParams: UpdateSpanMapperGroupPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperGroupDTO>;
}
> = (props) => {
const { pathParams, data } = props ?? {};
return updateSpanMapperGroup(pathParams, data);
};
return { mutationFn, ...mutationOptions };
};
export type UpdateSpanMapperGroupMutationResult = NonNullable<
Awaited<ReturnType<typeof updateSpanMapperGroup>>
>;
export type UpdateSpanMapperGroupMutationBody =
BodyType<SpantypesUpdatableSpanMapperGroupDTO>;
export type UpdateSpanMapperGroupMutationError =
ErrorType<RenderErrorResponseDTO>;
/**
* @summary Update a span attribute mapping group
*/
export const useUpdateSpanMapperGroup = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof updateSpanMapperGroup>>,
TError,
{
pathParams: UpdateSpanMapperGroupPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperGroupDTO>;
},
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof updateSpanMapperGroup>>,
TError,
{
pathParams: UpdateSpanMapperGroupPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperGroupDTO>;
},
TContext
> => {
const mutationOptions = getUpdateSpanMapperGroupMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* Returns all mappers belonging to a mapping group.
* @summary List span mappers for a group
*/
export const listSpanMappers = (
{ groupId }: ListSpanMappersPathParameters,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<ListSpanMappers200>({
url: `/api/v1/span_mapper_groups/${groupId}/span_mappers`,
method: 'GET',
signal,
});
};
export const getListSpanMappersQueryKey = ({
groupId,
}: ListSpanMappersPathParameters) => {
return [`/api/v1/span_mapper_groups/${groupId}/span_mappers`] as const;
};
export const getListSpanMappersQueryOptions = <
TData = Awaited<ReturnType<typeof listSpanMappers>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
{ groupId }: ListSpanMappersPathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listSpanMappers>>,
TError,
TData
>;
},
) => {
const { query: queryOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getListSpanMappersQueryKey({ groupId });
const queryFn: QueryFunction<Awaited<ReturnType<typeof listSpanMappers>>> = ({
signal,
}) => listSpanMappers({ groupId }, signal);
return {
queryKey,
queryFn,
enabled: !!groupId,
...queryOptions,
} as UseQueryOptions<
Awaited<ReturnType<typeof listSpanMappers>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type ListSpanMappersQueryResult = NonNullable<
Awaited<ReturnType<typeof listSpanMappers>>
>;
export type ListSpanMappersQueryError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary List span mappers for a group
*/
export function useListSpanMappers<
TData = Awaited<ReturnType<typeof listSpanMappers>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
{ groupId }: ListSpanMappersPathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listSpanMappers>>,
TError,
TData
>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getListSpanMappersQueryOptions({ groupId }, options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
query.queryKey = queryOptions.queryKey;
return query;
}
/**
* @summary List span mappers for a group
*/
export const invalidateListSpanMappers = async (
queryClient: QueryClient,
{ groupId }: ListSpanMappersPathParameters,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getListSpanMappersQueryKey({ groupId }) },
options,
);
return queryClient;
};
/**
* Adds a new mapper to the specified mapping group.
* @summary Create a span mapper
*/
export const createSpanMapper = (
{ groupId }: CreateSpanMapperPathParameters,
spantypesPostableSpanMapperDTO: BodyType<SpantypesPostableSpanMapperDTO>,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<CreateSpanMapper201>({
url: `/api/v1/span_mapper_groups/${groupId}/span_mappers`,
method: 'POST',
headers: { 'Content-Type': 'application/json' },
data: spantypesPostableSpanMapperDTO,
signal,
});
};
export const getCreateSpanMapperMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof createSpanMapper>>,
TError,
{
pathParams: CreateSpanMapperPathParameters;
data: BodyType<SpantypesPostableSpanMapperDTO>;
},
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof createSpanMapper>>,
TError,
{
pathParams: CreateSpanMapperPathParameters;
data: BodyType<SpantypesPostableSpanMapperDTO>;
},
TContext
> => {
const mutationKey = ['createSpanMapper'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof createSpanMapper>>,
{
pathParams: CreateSpanMapperPathParameters;
data: BodyType<SpantypesPostableSpanMapperDTO>;
}
> = (props) => {
const { pathParams, data } = props ?? {};
return createSpanMapper(pathParams, data);
};
return { mutationFn, ...mutationOptions };
};
export type CreateSpanMapperMutationResult = NonNullable<
Awaited<ReturnType<typeof createSpanMapper>>
>;
export type CreateSpanMapperMutationBody =
BodyType<SpantypesPostableSpanMapperDTO>;
export type CreateSpanMapperMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Create a span mapper
*/
export const useCreateSpanMapper = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof createSpanMapper>>,
TError,
{
pathParams: CreateSpanMapperPathParameters;
data: BodyType<SpantypesPostableSpanMapperDTO>;
},
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof createSpanMapper>>,
TError,
{
pathParams: CreateSpanMapperPathParameters;
data: BodyType<SpantypesPostableSpanMapperDTO>;
},
TContext
> => {
const mutationOptions = getCreateSpanMapperMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* Hard-deletes a mapper from a mapping group.
* @summary Delete a span mapper
*/
export const deleteSpanMapper = ({
groupId,
mapperId,
}: DeleteSpanMapperPathParameters) => {
return GeneratedAPIInstance<void>({
url: `/api/v1/span_mapper_groups/${groupId}/span_mappers/${mapperId}`,
method: 'DELETE',
});
};
export const getDeleteSpanMapperMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteSpanMapper>>,
TError,
{ pathParams: DeleteSpanMapperPathParameters },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof deleteSpanMapper>>,
TError,
{ pathParams: DeleteSpanMapperPathParameters },
TContext
> => {
const mutationKey = ['deleteSpanMapper'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof deleteSpanMapper>>,
{ pathParams: DeleteSpanMapperPathParameters }
> = (props) => {
const { pathParams } = props ?? {};
return deleteSpanMapper(pathParams);
};
return { mutationFn, ...mutationOptions };
};
export type DeleteSpanMapperMutationResult = NonNullable<
Awaited<ReturnType<typeof deleteSpanMapper>>
>;
export type DeleteSpanMapperMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Delete a span mapper
*/
export const useDeleteSpanMapper = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteSpanMapper>>,
TError,
{ pathParams: DeleteSpanMapperPathParameters },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof deleteSpanMapper>>,
TError,
{ pathParams: DeleteSpanMapperPathParameters },
TContext
> => {
const mutationOptions = getDeleteSpanMapperMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* Partially updates an existing mapper's field context, config, or enabled state.
* @summary Update a span mapper
*/
export const updateSpanMapper = (
{ groupId, mapperId }: UpdateSpanMapperPathParameters,
spantypesUpdatableSpanMapperDTO: BodyType<SpantypesUpdatableSpanMapperDTO>,
) => {
return GeneratedAPIInstance<void>({
url: `/api/v1/span_mapper_groups/${groupId}/span_mappers/${mapperId}`,
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
data: spantypesUpdatableSpanMapperDTO,
});
};
export const getUpdateSpanMapperMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof updateSpanMapper>>,
TError,
{
pathParams: UpdateSpanMapperPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperDTO>;
},
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof updateSpanMapper>>,
TError,
{
pathParams: UpdateSpanMapperPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperDTO>;
},
TContext
> => {
const mutationKey = ['updateSpanMapper'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof updateSpanMapper>>,
{
pathParams: UpdateSpanMapperPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperDTO>;
}
> = (props) => {
const { pathParams, data } = props ?? {};
return updateSpanMapper(pathParams, data);
};
return { mutationFn, ...mutationOptions };
};
export type UpdateSpanMapperMutationResult = NonNullable<
Awaited<ReturnType<typeof updateSpanMapper>>
>;
export type UpdateSpanMapperMutationBody =
BodyType<SpantypesUpdatableSpanMapperDTO>;
export type UpdateSpanMapperMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Update a span mapper
*/
export const useUpdateSpanMapper = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof updateSpanMapper>>,
TError,
{
pathParams: UpdateSpanMapperPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperDTO>;
},
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof updateSpanMapper>>,
TError,
{
pathParams: UpdateSpanMapperPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperDTO>;
},
TContext
> => {
const mutationOptions = getUpdateSpanMapperMutationOptions(options);
return useMutation(mutationOptions);
};

View File

@@ -76,10 +76,10 @@ describe('interceptorRejected', () => {
}
const mockAxiosFn = axios as unknown as jest.Mock;
expect(mockAxiosFn.mock.calls.length).toBe(1);
expect(mockAxiosFn.mock.calls).toHaveLength(1);
const retryCallConfig = mockAxiosFn.mock.calls[0][0];
expect(Array.isArray(JSON.parse(retryCallConfig.data))).toBe(true);
expect(JSON.parse(retryCallConfig.data)).toEqual(arrayPayload);
expect(JSON.parse(retryCallConfig.data)).toStrictEqual(arrayPayload);
});
it('should preserve object payload structure when retrying a 401 request', async () => {
@@ -112,9 +112,9 @@ describe('interceptorRejected', () => {
}
const mockAxiosFn = axios as unknown as jest.Mock;
expect(mockAxiosFn.mock.calls.length).toBe(1);
expect(mockAxiosFn.mock.calls).toHaveLength(1);
const retryCallConfig = mockAxiosFn.mock.calls[0][0];
expect(JSON.parse(retryCallConfig.data)).toEqual(objectPayload);
expect(JSON.parse(retryCallConfig.data)).toStrictEqual(objectPayload);
});
it('should handle undefined data gracefully when retrying', async () => {
@@ -145,7 +145,7 @@ describe('interceptorRejected', () => {
}
const mockAxiosFn = axios as unknown as jest.Mock;
expect(mockAxiosFn.mock.calls.length).toBe(1);
expect(mockAxiosFn.mock.calls).toHaveLength(1);
const retryCallConfig = mockAxiosFn.mock.calls[0][0];
expect(retryCallConfig.data).toBeUndefined();
});

View File

@@ -99,7 +99,7 @@ describe('convertV5ResponseToLegacy', () => {
const q = result.payload.data.result[0];
expect(q.queryName).toBe('A');
expect(q.legend).toBe('{{service.name}}');
expect(q.series?.[0]).toEqual(
expect(q.series?.[0]).toStrictEqual(
expect.objectContaining({
labels: { 'service.name': 'adservice' },
values: [
@@ -186,7 +186,7 @@ describe('convertV5ResponseToLegacy', () => {
expect(result.payload.data.resultType).toBe('scalar');
const [tableEntry] = result.payload.data.result;
expect(tableEntry.table?.columns).toEqual([
expect(tableEntry.table?.columns).toStrictEqual([
{
name: 'service.name',
queryName: 'A',
@@ -202,7 +202,7 @@ describe('convertV5ResponseToLegacy', () => {
},
{ name: 'F1', queryName: 'F1', isValueColumn: true, id: 'F1' },
]);
expect(tableEntry.table?.rows?.[0]).toEqual({
expect(tableEntry.table?.rows?.[0]).toStrictEqual({
data: {
'service.name': 'adservice',
'A.count()': 606,
@@ -257,7 +257,7 @@ describe('convertV5ResponseToLegacy', () => {
expect(result.payload.data.resultType).toBe('scalar');
const [tableEntry] = result.payload.data.result;
expect(tableEntry.table?.columns).toEqual([
expect(tableEntry.table?.columns).toStrictEqual([
{
name: 'service.name',
queryName: 'A',
@@ -267,7 +267,7 @@ describe('convertV5ResponseToLegacy', () => {
// Single aggregation: name resolves to legend, id resolves to queryName
{ name: '{{service.name}}', queryName: 'A', isValueColumn: true, id: 'A' },
]);
expect(tableEntry.table?.rows?.[0]).toEqual({
expect(tableEntry.table?.rows?.[0]).toStrictEqual({
data: {
'service.name': 'adservice',
A: 580,

View File

@@ -104,7 +104,7 @@ describe('prepareQueryRangePayloadV5', () => {
const result = prepareQueryRangePayloadV5(props);
expect(result).toEqual(
expect(result).toStrictEqual(
expect.objectContaining({
legendMap: { A: 'Legend A', F1: 'Formula Legend' },
queryPayload: expect.objectContaining({
@@ -154,7 +154,10 @@ describe('prepareQueryRangePayloadV5', () => {
);
// Legend map combines builder and formulas
expect(result.legendMap).toEqual({ A: 'Legend A', F1: 'Formula Legend' });
expect(result.legendMap).toStrictEqual({
A: 'Legend A',
F1: 'Formula Legend',
});
const payload: QueryRangePayloadV5 = result.queryPayload;
@@ -166,10 +169,10 @@ describe('prepareQueryRangePayloadV5', () => {
expect(payload.formatOptions?.fillGaps).toBe(true);
// Variables mapped as { key: { value } }
expect(payload.variables).toEqual({
svc: { value: 'api' },
count: { value: 5 },
flag: { value: true },
expect(payload.variables).toStrictEqual({
svc: { value: 'api', type: undefined },
count: { value: 5, type: undefined },
flag: { value: true, type: undefined },
});
// Queries include one builder_query and one builder_formula
@@ -226,7 +229,7 @@ describe('prepareQueryRangePayloadV5', () => {
const result = prepareQueryRangePayloadV5(props);
expect(result).toEqual(
expect(result).toStrictEqual(
expect.objectContaining({
legendMap: { A: 'LP' },
queryPayload: expect.objectContaining({
@@ -255,7 +258,7 @@ describe('prepareQueryRangePayloadV5', () => {
}),
);
expect(result.legendMap).toEqual({ A: 'LP' });
expect(result.legendMap).toStrictEqual({ A: 'LP' });
const payload: QueryRangePayloadV5 = result.queryPayload;
expect(payload.requestType).toBe('time_series');
@@ -296,7 +299,7 @@ describe('prepareQueryRangePayloadV5', () => {
const result = prepareQueryRangePayloadV5(props);
expect(result).toEqual(
expect(result).toStrictEqual(
expect.objectContaining({
legendMap: { Q: 'LC' },
queryPayload: expect.objectContaining({
@@ -324,7 +327,7 @@ describe('prepareQueryRangePayloadV5', () => {
}),
);
expect(result.legendMap).toEqual({ Q: 'LC' });
expect(result.legendMap).toStrictEqual({ Q: 'LC' });
const payload: QueryRangePayloadV5 = result.queryPayload;
expect(payload.requestType).toBe('scalar');
@@ -353,7 +356,7 @@ describe('prepareQueryRangePayloadV5', () => {
const result = prepareQueryRangePayloadV5(props);
expect(result).toEqual(
expect(result).toStrictEqual(
expect.objectContaining({
legendMap: {},
queryPayload: expect.objectContaining({
@@ -397,7 +400,7 @@ describe('prepareQueryRangePayloadV5', () => {
const result = prepareQueryRangePayloadV5(props);
expect(result).toEqual(
expect(result).toStrictEqual(
expect.objectContaining({
legendMap: { A: 'Legend A' },
queryPayload: expect.objectContaining({
@@ -471,7 +474,7 @@ describe('prepareQueryRangePayloadV5', () => {
const result = prepareQueryRangePayloadV5(props);
expect(result).toEqual(
expect(result).toStrictEqual(
expect.objectContaining({
legendMap: { A: 'Legend A' },
queryPayload: expect.objectContaining({
@@ -585,7 +588,7 @@ describe('prepareQueryRangePayloadV5', () => {
const result = prepareQueryRangePayloadV5(props);
expect(result).toEqual(
expect(result).toStrictEqual(
expect.objectContaining({
legendMap: { A: '{{service.name}}' },
queryPayload: expect.objectContaining({
@@ -684,7 +687,7 @@ describe('prepareQueryRangePayloadV5', () => {
const result = prepareQueryRangePayloadV5(props);
expect(result.legendMap).toEqual({ A: 'Legend A' });
expect(result.legendMap).toStrictEqual({ A: 'Legend A' });
expect(result.queryPayload.compositeQuery.queries).toHaveLength(1);
const builderQuery = result.queryPayload.compositeQuery.queries.find(
@@ -694,7 +697,7 @@ describe('prepareQueryRangePayloadV5', () => {
expect(logSpec.name).toBe('A');
expect(logSpec.signal).toBe('logs');
expect(logSpec.filter).toEqual({
expect(logSpec.filter).toStrictEqual({
expression:
"service.name = 'payment-service' AND http.status_code >= 400 AND message contains 'error'",
});
@@ -731,7 +734,9 @@ describe('prepareQueryRangePayloadV5', () => {
(q) => q.type === 'builder_query',
) as QueryEnvelope;
const logSpec = builderQuery.spec as LogBuilderQuery;
expect(logSpec.filter).toEqual({ expression: 'http.status_code >= 500' });
expect(logSpec.filter).toStrictEqual({
expression: 'http.status_code >= 500',
});
});
it('derives expression from filters when filter is undefined', () => {
@@ -775,7 +780,9 @@ describe('prepareQueryRangePayloadV5', () => {
(q) => q.type === 'builder_query',
) as QueryEnvelope;
const logSpec = builderQuery.spec as LogBuilderQuery;
expect(logSpec.filter).toEqual({ expression: "service.name = 'checkout'" });
expect(logSpec.filter).toStrictEqual({
expression: "service.name = 'checkout'",
});
});
it('prefers filter.expression over filters when both are present', () => {
@@ -819,7 +826,9 @@ describe('prepareQueryRangePayloadV5', () => {
(q) => q.type === 'builder_query',
) as QueryEnvelope;
const logSpec = builderQuery.spec as LogBuilderQuery;
expect(logSpec.filter).toEqual({ expression: "service.name = 'frontend'" });
expect(logSpec.filter).toStrictEqual({
expression: "service.name = 'frontend'",
});
});
it('returns empty expression when neither filter nor filters provided', () => {
@@ -853,7 +862,7 @@ describe('prepareQueryRangePayloadV5', () => {
(q) => q.type === 'builder_query',
) as QueryEnvelope;
const logSpec = builderQuery.spec as LogBuilderQuery;
expect(logSpec.filter).toEqual({ expression: '' });
expect(logSpec.filter).toStrictEqual({ expression: '' });
});
it('returns empty expression when filters provided with empty items', () => {
@@ -887,6 +896,6 @@ describe('prepareQueryRangePayloadV5', () => {
(q) => q.type === 'builder_query',
) as QueryEnvelope;
const logSpec = builderQuery.spec as LogBuilderQuery;
expect(logSpec.filter).toEqual({ expression: '' });
expect(logSpec.filter).toStrictEqual({ expression: '' });
});
});

View File

@@ -213,7 +213,7 @@ describe.each([
const callArgs = mockDownloadExportData.mock.calls[0][0];
const query = callArgs.body.compositeQuery.queries[0];
expect(query.spec.groupBy).toBeUndefined();
expect(query.spec.having).toEqual({ expression: '' });
expect(query.spec.having).toStrictEqual({ expression: '' });
});
});
@@ -238,7 +238,7 @@ describe.each([
expect(mockDownloadExportData).toHaveBeenCalledTimes(1);
const callArgs = mockDownloadExportData.mock.calls[0][0];
const query = callArgs.body.compositeQuery.queries[0];
expect(query.spec.selectFields).toEqual([
expect(query.spec.selectFields).toStrictEqual([
expect.objectContaining({
name: 'http.status',
fieldDataType: 'int64',

View File

@@ -6,39 +6,39 @@ jest.mock('react-dnd', () => ({
}));
describe('Utils testing of DraggableTableRow component', () => {
test('Should dropHandler return true', () => {
it('Should dropHandler return true', () => {
const monitor = {
isOver: jest.fn().mockReturnValueOnce(true),
} as never;
const dropDataTruthy = dropHandler(monitor);
expect(dropDataTruthy).toEqual({ isOver: true });
expect(dropDataTruthy).toStrictEqual({ isOver: true });
});
test('Should dropHandler return false', () => {
it('Should dropHandler return false', () => {
const monitor = {
isOver: jest.fn().mockReturnValueOnce(false),
} as never;
const dropDataFalsy = dropHandler(monitor);
expect(dropDataFalsy).toEqual({ isOver: false });
expect(dropDataFalsy).toStrictEqual({ isOver: false });
});
test('Should dragHandler return true', () => {
it('Should dragHandler return true', () => {
const monitor = {
isDragging: jest.fn().mockReturnValueOnce(true),
} as never;
const dragDataTruthy = dragHandler(monitor);
expect(dragDataTruthy).toEqual({ isDragging: true });
expect(dragDataTruthy).toStrictEqual({ isDragging: true });
});
test('Should dragHandler return false', () => {
it('Should dragHandler return false', () => {
const monitor = {
isDragging: jest.fn().mockReturnValueOnce(false),
} as never;
const dragDataFalsy = dragHandler(monitor);
expect(dragDataFalsy).toEqual({ isDragging: false });
expect(dragDataFalsy).toStrictEqual({ isDragging: false });
});
});

View File

@@ -361,9 +361,9 @@ describe('EditMemberDrawer', () => {
await user.click(screen.getByRole('button', { name: /delete member/i }));
expect(
await screen.findByText(/are you sure you want to delete/i),
).toBeInTheDocument();
await expect(
screen.findByText(/are you sure you want to delete/i),
).resolves.toBeInTheDocument();
const confirmBtns = screen.getAllByRole('button', { name: /delete member/i });
await user.click(confirmBtns[confirmBtns.length - 1]);
@@ -441,9 +441,9 @@ describe('EditMemberDrawer', () => {
await user.click(screen.getByRole('button', { name: /revoke invite/i }));
expect(
await screen.findByText(/Are you sure you want to revoke the invite/i),
).toBeInTheDocument();
await expect(
screen.findByText(/Are you sure you want to revoke the invite/i),
).resolves.toBeInTheDocument();
const confirmBtns = screen.getAllByRole('button', { name: /revoke invite/i });
await user.click(confirmBtns[confirmBtns.length - 1]);

View File

@@ -64,7 +64,7 @@ export const legend = (id: string, isLonger: boolean): Plugin<ChartType> => ({
// li.style.marginTop = '5px';
li.onclick = (): void => {
// @ts-ignore
// @ts-expect-error
const { type } = chart.config;
if (type === 'pie' || type === 'doughnut') {
// Pie and doughnut charts only have a single dataset and visibility is per item

View File

@@ -9,65 +9,65 @@ describe('xAxisConfig for Chart', () => {
const start = dayjs();
const end = start.add(10, 'millisecond');
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toEqual(
TIME_UNITS.millisecond,
);
expect(
convertTimeRange(start.valueOf(), end.valueOf()).unitName,
).toStrictEqual(TIME_UNITS.millisecond);
}
{
const start = dayjs();
const end = start.add(10, 'second');
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toEqual(
TIME_UNITS.second,
);
expect(
convertTimeRange(start.valueOf(), end.valueOf()).unitName,
).toStrictEqual(TIME_UNITS.second);
}
{
const start = dayjs();
const end = start.add(10, 'minute');
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toEqual(
TIME_UNITS.minute,
);
expect(
convertTimeRange(start.valueOf(), end.valueOf()).unitName,
).toStrictEqual(TIME_UNITS.minute);
}
{
const start = dayjs();
const end = start.add(10, 'hour');
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toEqual(
TIME_UNITS.hour,
);
expect(
convertTimeRange(start.valueOf(), end.valueOf()).unitName,
).toStrictEqual(TIME_UNITS.hour);
}
{
const start = dayjs();
const end = start.add(10, 'day');
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toEqual(
TIME_UNITS.day,
);
expect(
convertTimeRange(start.valueOf(), end.valueOf()).unitName,
).toStrictEqual(TIME_UNITS.day);
}
{
const start = dayjs();
const end = start.add(10, 'week');
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toEqual(
TIME_UNITS.week,
);
expect(
convertTimeRange(start.valueOf(), end.valueOf()).unitName,
).toStrictEqual(TIME_UNITS.week);
}
{
const start = dayjs();
const end = start.add(10, 'month');
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toEqual(
TIME_UNITS.month,
);
expect(
convertTimeRange(start.valueOf(), end.valueOf()).unitName,
).toStrictEqual(TIME_UNITS.month);
}
{
const start = dayjs();
const end = start.add(10, 'year');
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toEqual(
TIME_UNITS.year,
);
expect(
convertTimeRange(start.valueOf(), end.valueOf()).unitName,
).toStrictEqual(TIME_UNITS.year);
}
});
});

View File

@@ -7,7 +7,7 @@ const testFullPrecisionGetYAxisFormattedValue = (
): string => getYAxisFormattedValue(value, format, PrecisionOptionsEnum.FULL);
describe('getYAxisFormattedValue - none (full precision legacy assertions)', () => {
test('large integers and decimals', () => {
it('large integers and decimals', () => {
expect(testFullPrecisionGetYAxisFormattedValue('250034', 'none')).toBe(
'250034',
);
@@ -22,7 +22,7 @@ describe('getYAxisFormattedValue - none (full precision legacy assertions)', ()
);
});
test('preserves leading zeros after decimal until first non-zero', () => {
it('preserves leading zeros after decimal until first non-zero', () => {
expect(testFullPrecisionGetYAxisFormattedValue('1.0000234', 'none')).toBe(
'1.0000234',
);
@@ -31,7 +31,7 @@ describe('getYAxisFormattedValue - none (full precision legacy assertions)', ()
);
});
test('trims to three significant decimals and removes trailing zeros', () => {
it('trims to three significant decimals and removes trailing zeros', () => {
expect(
testFullPrecisionGetYAxisFormattedValue('0.000000250034', 'none'),
).toBe('0.000000250034');
@@ -55,7 +55,7 @@ describe('getYAxisFormattedValue - none (full precision legacy assertions)', ()
).toBe('0.00000025');
});
test('whole numbers normalize', () => {
it('whole numbers normalize', () => {
expect(testFullPrecisionGetYAxisFormattedValue('1000', 'none')).toBe('1000');
expect(testFullPrecisionGetYAxisFormattedValue('99.5458', 'none')).toBe(
'99.5458',
@@ -68,7 +68,7 @@ describe('getYAxisFormattedValue - none (full precision legacy assertions)', ()
);
});
test('strip redundant decimal zeros', () => {
it('strip redundant decimal zeros', () => {
expect(testFullPrecisionGetYAxisFormattedValue('1000.000', 'none')).toBe(
'1000',
);
@@ -78,7 +78,7 @@ describe('getYAxisFormattedValue - none (full precision legacy assertions)', ()
expect(testFullPrecisionGetYAxisFormattedValue('1.000', 'none')).toBe('1');
});
test('edge values', () => {
it('edge values', () => {
expect(testFullPrecisionGetYAxisFormattedValue('0', 'none')).toBe('0');
expect(testFullPrecisionGetYAxisFormattedValue('-0', 'none')).toBe('0');
expect(testFullPrecisionGetYAxisFormattedValue('Infinity', 'none')).toBe('∞');
@@ -92,7 +92,7 @@ describe('getYAxisFormattedValue - none (full precision legacy assertions)', ()
expect(testFullPrecisionGetYAxisFormattedValue('abc123', 'none')).toBe('NaN');
});
test('small decimals keep precision as-is', () => {
it('small decimals keep precision as-is', () => {
expect(testFullPrecisionGetYAxisFormattedValue('0.0001', 'none')).toBe(
'0.0001',
);
@@ -104,7 +104,7 @@ describe('getYAxisFormattedValue - none (full precision legacy assertions)', ()
);
});
test('simple decimals preserved', () => {
it('simple decimals preserved', () => {
expect(testFullPrecisionGetYAxisFormattedValue('0.1', 'none')).toBe('0.1');
expect(testFullPrecisionGetYAxisFormattedValue('0.2', 'none')).toBe('0.2');
expect(testFullPrecisionGetYAxisFormattedValue('0.3', 'none')).toBe('0.3');
@@ -115,7 +115,7 @@ describe('getYAxisFormattedValue - none (full precision legacy assertions)', ()
});
describe('getYAxisFormattedValue - units (full precision legacy assertions)', () => {
test('ms', () => {
it('ms', () => {
expect(testFullPrecisionGetYAxisFormattedValue('1500', 'ms')).toBe('1.5 s');
expect(testFullPrecisionGetYAxisFormattedValue('500', 'ms')).toBe('500 ms');
expect(testFullPrecisionGetYAxisFormattedValue('60000', 'ms')).toBe('1 min');
@@ -127,19 +127,19 @@ describe('getYAxisFormattedValue - units (full precision legacy assertions)', ()
);
});
test('s', () => {
it('s', () => {
expect(testFullPrecisionGetYAxisFormattedValue('90', 's')).toBe('1.5 mins');
expect(testFullPrecisionGetYAxisFormattedValue('30', 's')).toBe('30 s');
expect(testFullPrecisionGetYAxisFormattedValue('3600', 's')).toBe('1 hour');
});
test('m', () => {
it('m', () => {
expect(testFullPrecisionGetYAxisFormattedValue('90', 'm')).toBe('1.5 hours');
expect(testFullPrecisionGetYAxisFormattedValue('30', 'm')).toBe('30 min');
expect(testFullPrecisionGetYAxisFormattedValue('1440', 'm')).toBe('1 day');
});
test('bytes', () => {
it('bytes', () => {
expect(testFullPrecisionGetYAxisFormattedValue('1024', 'bytes')).toBe(
'1 KiB',
);
@@ -149,7 +149,7 @@ describe('getYAxisFormattedValue - units (full precision legacy assertions)', ()
);
});
test('mbytes', () => {
it('mbytes', () => {
expect(testFullPrecisionGetYAxisFormattedValue('1024', 'mbytes')).toBe(
'1 GiB',
);
@@ -161,7 +161,7 @@ describe('getYAxisFormattedValue - units (full precision legacy assertions)', ()
);
});
test('kbytes', () => {
it('kbytes', () => {
expect(testFullPrecisionGetYAxisFormattedValue('1024', 'kbytes')).toBe(
'1 MiB',
);
@@ -173,7 +173,7 @@ describe('getYAxisFormattedValue - units (full precision legacy assertions)', ()
);
});
test('short', () => {
it('short', () => {
expect(testFullPrecisionGetYAxisFormattedValue('1000', 'short')).toBe('1 K');
expect(testFullPrecisionGetYAxisFormattedValue('1500', 'short')).toBe(
'1.5 K',
@@ -201,7 +201,7 @@ describe('getYAxisFormattedValue - units (full precision legacy assertions)', ()
);
});
test('percent', () => {
it('percent', () => {
expect(testFullPrecisionGetYAxisFormattedValue('0.15', 'percent')).toBe(
'0.15%',
);
@@ -235,7 +235,7 @@ describe('getYAxisFormattedValue - units (full precision legacy assertions)', ()
).toBe('1.005555555595959%');
});
test('ratio', () => {
it('ratio', () => {
expect(testFullPrecisionGetYAxisFormattedValue('0.5', 'ratio')).toBe(
'0.5 ratio',
);
@@ -247,7 +247,7 @@ describe('getYAxisFormattedValue - units (full precision legacy assertions)', ()
);
});
test('temperature units', () => {
it('temperature units', () => {
expect(testFullPrecisionGetYAxisFormattedValue('25', 'celsius')).toBe(
'25 °C',
);
@@ -267,13 +267,13 @@ describe('getYAxisFormattedValue - units (full precision legacy assertions)', ()
);
});
test('ms edge cases', () => {
it('ms edge cases', () => {
expect(testFullPrecisionGetYAxisFormattedValue('0', 'ms')).toBe('0 ms');
expect(testFullPrecisionGetYAxisFormattedValue('-1500', 'ms')).toBe('-1.5 s');
expect(testFullPrecisionGetYAxisFormattedValue('Infinity', 'ms')).toBe('∞');
});
test('bytes edge cases', () => {
it('bytes edge cases', () => {
expect(testFullPrecisionGetYAxisFormattedValue('0', 'bytes')).toBe('0 B');
expect(testFullPrecisionGetYAxisFormattedValue('-1024', 'bytes')).toBe(
'-1 KiB',
@@ -282,7 +282,7 @@ describe('getYAxisFormattedValue - units (full precision legacy assertions)', ()
});
describe('getYAxisFormattedValue - precision option tests', () => {
test('precision 0 drops decimal part', () => {
it('precision 0 drops decimal part', () => {
expect(getYAxisFormattedValue('1.2345', 'none', 0)).toBe('1');
expect(getYAxisFormattedValue('0.9999', 'none', 0)).toBe('0');
expect(getYAxisFormattedValue('12345.6789', 'none', 0)).toBe('12345');
@@ -294,7 +294,7 @@ describe('getYAxisFormattedValue - precision option tests', () => {
// with unit
expect(getYAxisFormattedValue('4353.81', 'ms', 0)).toBe('4 s');
});
test('precision 1,2,3,4 decimals', () => {
it('precision 1,2,3,4 decimals', () => {
expect(getYAxisFormattedValue('1.2345', 'none', 1)).toBe('1.2');
expect(getYAxisFormattedValue('1.2345', 'none', 2)).toBe('1.23');
expect(getYAxisFormattedValue('1.2345', 'none', 3)).toBe('1.234');
@@ -345,7 +345,7 @@ describe('getYAxisFormattedValue - precision option tests', () => {
expect(getYAxisFormattedValue('0.123456', 'percent', 4)).toBe('0.1235%'); // approximation
});
test('precision full uses up to DEFAULT_SIGNIFICANT_DIGITS significant digits', () => {
it('precision full uses up to DEFAULT_SIGNIFICANT_DIGITS significant digits', () => {
expect(
getYAxisFormattedValue(
'0.00002625429914148441',

View File

@@ -90,11 +90,11 @@ describe('InviteMembersModal', () => {
screen.getByRole('button', { name: /invite team members/i }),
);
expect(
await screen.findByText(
await expect(
screen.findByText(
'Please enter valid emails and select roles for team members',
),
).toBeInTheDocument();
).resolves.toBeInTheDocument();
});
it('shows email-only message when email is invalid but role is selected', async () => {
@@ -112,9 +112,9 @@ describe('InviteMembersModal', () => {
screen.getByRole('button', { name: /invite team members/i }),
);
expect(
await screen.findByText('Please enter valid emails for team members'),
).toBeInTheDocument();
await expect(
screen.findByText('Please enter valid emails for team members'),
).resolves.toBeInTheDocument();
});
it('shows role-only message when email is valid but role is missing', async () => {
@@ -130,9 +130,9 @@ describe('InviteMembersModal', () => {
screen.getByRole('button', { name: /invite team members/i }),
);
expect(
await screen.findByText('Please select roles for team members'),
).toBeInTheDocument();
await expect(
screen.findByText('Please select roles for team members'),
).resolves.toBeInTheDocument();
});
});

View File

@@ -10,6 +10,7 @@ import cx from 'classnames';
import { LogType } from 'components/Logs/LogStateIndicator/LogStateIndicator';
import QuerySearch from 'components/QueryBuilderV2/QueryV2/QuerySearch/QuerySearch';
import { convertExpressionToFilters } from 'components/QueryBuilderV2/utils';
import { FeatureKeys } from 'constants/features';
import { LOCALSTORAGE } from 'constants/localStorage';
import { QueryParams } from 'constants/query';
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
@@ -46,6 +47,7 @@ import {
TextSelect,
X,
} from 'lucide-react';
import { useAppContext } from 'providers/App/App';
import { AppState } from 'store/reducers';
import { Query, TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { DataSource, StringOperators } from 'types/common/queryBuilder';
@@ -79,6 +81,10 @@ function LogDetailInner({
const [selectedView, setSelectedView] = useState<VIEWS>(selectedTab);
const [isFilterVisible, setIsFilterVisible] = useState<boolean>(false);
const { featureFlags } = useAppContext();
const isBodyJsonQueryEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.BODY_JSON_ENABLED)
?.active || false;
const [filters, setFilters] = useState<TagFilter | null>(null);
const [isEdit, setIsEdit] = useState<boolean>(false);
@@ -208,11 +214,29 @@ function LogDetailInner({
}
};
const logBody = useMemo(() => {
if (!isBodyJsonQueryEnabled) {
return log?.body || '';
}
try {
const json = JSON.parse(log?.body || '');
if (typeof json?.message === 'string' && json.message !== '') {
return json.message;
}
return log?.body || '';
} catch (error) {
return log?.body || '';
}
}, [isBodyJsonQueryEnabled, log?.body]);
const htmlBody = useMemo(
() => ({
__html: getSanitizedLogBody(log?.body || '', { shouldEscapeHtml: true }),
__html: getSanitizedLogBody(logBody || '', { shouldEscapeHtml: true }),
}),
[log?.body],
[logBody],
);
const handleJSONCopy = (): void => {
@@ -418,7 +442,7 @@ function LogDetailInner({
<div className="log-detail-drawer__log">
<Divider type="vertical" className={cx('log-type-indicator', logType)} />
<Tooltip
title={removeEscapeCharacters(log?.body)}
title={removeEscapeCharacters(logBody)}
placement="left"
mouseLeaveDelay={0}
>

View File

@@ -27,7 +27,7 @@ describe('getLogIndicatorType', () => {
expect(getLogIndicatorType(log)).toBe('TRACE');
});
it('severity_text should be used when severity_number is absent ', () => {
it('severity_text should be used when severity_number is absent', () => {
const log = {
date: '2024-02-29T12:34:46Z',
timestamp: 1646115296,

View File

@@ -75,7 +75,7 @@ function OptionsMenu({
};
const handleSearchValueChange = useDebouncedFn((event): void => {
// @ts-ignore
// @ts-expect-error
const value = event?.target?.value || '';
if (addColumn && addColumn?.onSearch) {

View File

@@ -50,7 +50,7 @@ function Code({
const match = /language-(\w+)/.exec(className || '');
return !inline && match ? (
<SyntaxHighlighter
// @ts-ignore
// @ts-expect-error
style={a11yDark}
language={match[1]}
PreTag="div"
@@ -115,7 +115,7 @@ function MarkdownRenderer({
className={className}
rehypePlugins={[rehypeRaw as any]}
components={{
// @ts-ignore
// @ts-expect-error
a: Link,
pre: ({ children }) =>
Pre({

View File

@@ -61,7 +61,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 1. CUSTOM VALUES SUPPORT =====
describe('Custom Values Support (CS)', () => {
test('CS-01: Custom values persist in selected state', async () => {
it('CS-01: Custom values persist in selected state', async () => {
const { rerender } = renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -87,7 +87,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
expect(screen.getByText('another-custom')).toBeInTheDocument();
});
test('CS-02: Partial matches create custom values', async () => {
it('CS-02: Partial matches create custom values', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -129,7 +129,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
expect(combobox).toBeInTheDocument();
});
test('CS-03: Exact match filtering behavior', async () => {
it('CS-03: Exact match filtering behavior', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -176,7 +176,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
test('CS-04: Search filtering with "end" pattern', async () => {
it('CS-04: Search filtering with "end" pattern', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -234,7 +234,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
test('CS-05: Comma-separated values behavior', async () => {
it('CS-05: Comma-separated values behavior', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -281,7 +281,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 2. SEARCH AND FILTERING =====
describe('Search and Filtering (SF)', () => {
test('SF-01: Selected values pushed to top', async () => {
it('SF-01: Selected values pushed to top', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -305,7 +305,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
test('SF-02: Filtering with search text', async () => {
it('SF-02: Filtering with search text', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -350,7 +350,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
test('SF-03: Highlighting search matches', async () => {
it('SF-03: Highlighting search matches', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -381,7 +381,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
test('SF-04: Search with no results', async () => {
it('SF-04: Search with no results', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -424,7 +424,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 3. KEYBOARD NAVIGATION =====
describe('Keyboard Navigation (KN)', () => {
test('KN-01: Arrow key navigation in dropdown', async () => {
it('KN-01: Arrow key navigation in dropdown', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -465,7 +465,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
test('KN-02: Tab navigation to dropdown', async () => {
it('KN-02: Tab navigation to dropdown', async () => {
renderWithVirtuoso(
<div>
<input data-testid="prev-input" />
@@ -515,7 +515,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
test('KN-03: Enter selection in dropdown', async () => {
it('KN-03: Enter selection in dropdown', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -540,7 +540,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
expect(mockOnChange).toHaveBeenCalledWith(['frontend'], ['frontend']);
});
test('KN-04: Chip deletion with keyboard', async () => {
it('KN-04: Chip deletion with keyboard', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -586,7 +586,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 5. UI/UX BEHAVIORS =====
describe('UI/UX Behaviors (UI)', () => {
test('UI-01: Loading state does not block interaction', async () => {
it('UI-01: Loading state does not block interaction', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} loading />,
);
@@ -603,7 +603,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
test('UI-02: Component remains editable in all states', async () => {
it('UI-02: Component remains editable in all states', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} loading />,
);
@@ -634,7 +634,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
expect(combobox).not.toBeDisabled();
});
test('UI-03: Toggle/Only labels in dropdown', async () => {
it('UI-03: Toggle/Only labels in dropdown', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -656,7 +656,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
test('UI-04: Should display values with loading info at bottom', async () => {
it('UI-04: Should display values with loading info at bottom', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} loading />,
);
@@ -677,7 +677,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
test('UI-05: Error state display in footer', async () => {
it('UI-05: Error state display in footer', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -696,7 +696,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
test('UI-06: No data state display', async () => {
it('UI-06: No data state display', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={[]}
@@ -716,7 +716,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 6. CLEAR ACTIONS =====
describe('Clear Actions (CA)', () => {
test('CA-01: Ctrl+A selects all chips', async () => {
it('CA-01: Ctrl+A selects all chips', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -760,7 +760,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
test('CA-02: Clear icon removes all selections', async () => {
it('CA-02: Clear icon removes all selections', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -777,7 +777,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
}
});
test('CA-03: Individual chip removal', async () => {
it('CA-03: Individual chip removal', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -790,7 +790,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
const removeButtons = document.querySelectorAll(
'.ant-select-selection-item-remove',
);
expect(removeButtons.length).toBe(2);
expect(removeButtons).toHaveLength(2);
await user.click(removeButtons[1] as Element);
@@ -804,7 +804,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 7. SAVE AND SELECTION TRIGGERS =====
describe('Save and Selection Triggers (ST)', () => {
test('ST-01: ESC triggers save action', async () => {
it('ST-01: ESC triggers save action', async () => {
const mockDropdownChange = jest.fn();
renderWithVirtuoso(
@@ -837,7 +837,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
test('ST-02: Mouse selection works', async () => {
it('ST-02: Mouse selection works', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -859,7 +859,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
);
});
test('ST-03: ENTER in input field creates custom value', async () => {
it('ST-03: ENTER in input field creates custom value', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -892,7 +892,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
test('ST-04: Search text persistence', async () => {
it('ST-04: Search text persistence', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -932,7 +932,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 8. SPECIAL OPTIONS AND STATES =====
describe('Special Options and States (SO)', () => {
test('SO-01: ALL option appears first and separated', async () => {
it('SO-01: ALL option appears first and separated', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -954,7 +954,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
test('SO-02: ALL selection behavior', async () => {
it('SO-02: ALL selection behavior', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -981,7 +981,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
);
});
test('SO-03: ALL tag display when all selected', () => {
it('SO-03: ALL tag display when all selected', () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -996,7 +996,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
expect(screen.queryByText('frontend')).not.toBeInTheDocument();
});
test('SO-04: Footer information display', async () => {
it('SO-04: Footer information display', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -1017,7 +1017,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== GROUPED OPTIONS SUPPORT =====
describe('Grouped Options Support', () => {
test('handles grouped options correctly', async () => {
it('handles grouped options correctly', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockGroupedOptions} onChange={mockOnChange} />,
);
@@ -1041,7 +1041,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== ACCESSIBILITY TESTS =====
describe('Accessibility', () => {
test('has proper ARIA attributes', async () => {
it('has proper ARIA attributes', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -1058,7 +1058,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
test('supports screen reader navigation', async () => {
it('supports screen reader navigation', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -1079,7 +1079,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 9. ADVANCED KEYBOARD NAVIGATION =====
describe('Advanced Keyboard Navigation (AKN)', () => {
test('AKN-01: Shift + Arrow + Del chip deletion', async () => {
it('AKN-01: Shift + Arrow + Del chip deletion', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -1137,7 +1137,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
expect(combobox).toHaveFocus();
});
test('AKN-03: Mouse out closes dropdown', async () => {
it('AKN-03: Mouse out closes dropdown', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -1164,7 +1164,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 10. ADVANCED FILTERING AND HIGHLIGHTING =====
describe('Advanced Filtering and Highlighting (AFH)', () => {
test('AFH-01: Highlighted values pushed to top', async () => {
it('AFH-01: Highlighted values pushed to top', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -1220,7 +1220,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
test('AFH-02: Distinction between selection Enter and save Enter', async () => {
it('AFH-02: Distinction between selection Enter and save Enter', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -1267,7 +1267,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 11. ADVANCED CLEAR ACTIONS =====
describe('Advanced Clear Actions (ACA)', () => {
test('ACA-01: Clear action waiting behavior', async () => {
it('ACA-01: Clear action waiting behavior', async () => {
const mockOnChangeWithDelay = jest.fn().mockImplementation(
() =>
new Promise<void>((resolve) => {
@@ -1300,7 +1300,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 12. ADVANCED UI STATES =====
describe('Advanced UI States (AUS)', () => {
test('AUS-01: No data with previous value selected', async () => {
it('AUS-01: No data with previous value selected', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={[]}
@@ -1322,7 +1322,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
expect(screen.getByText('previous-value')).toBeInTheDocument();
});
test('AUS-02: Always editable accessibility', async () => {
it('AUS-02: Always editable accessibility', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} loading />,
);
@@ -1338,7 +1338,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
expect(combobox).not.toBeDisabled();
});
test('AUS-03: Sufficient space for search value', async () => {
it('AUS-03: Sufficient space for search value', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -1372,7 +1372,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 13. REGEX AND CUSTOM VALUES =====
describe('Regex and Custom Values (RCV)', () => {
test('RCV-01: Regex pattern support', async () => {
it('RCV-01: Regex pattern support', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -1418,7 +1418,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
test('RCV-02: Custom values treated as normal dropdown values', async () => {
it('RCV-02: Custom values treated as normal dropdown values', async () => {
const customOptions = [
...mockOptions,
{ label: 'custom-value', value: 'custom-value', type: 'custom' as const },
@@ -1456,7 +1456,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 14. DROPDOWN PERSISTENCE =====
describe('Dropdown Persistence (DP)', () => {
test('DP-01: Dropdown stays open for non-save actions', async () => {
it('DP-01: Dropdown stays open for non-save actions', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);

View File

@@ -50,7 +50,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 1. CUSTOM VALUES SUPPORT =====
describe('Custom Values Support (CS)', () => {
test('CS-02: Partial matches create custom values', async () => {
it('CS-02: Partial matches create custom values', async () => {
render(
<CustomSelect
options={mockOptions}
@@ -110,7 +110,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
test('CS-03: Exact match behavior', async () => {
it('CS-03: Exact match behavior', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -161,7 +161,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 2. SEARCH AND FILTERING =====
describe('Search and Filtering (SF)', () => {
test('SF-01: Selected values pushed to top', async () => {
it('SF-01: Selected values pushed to top', async () => {
render(
<CustomSelect
options={mockOptions}
@@ -185,7 +185,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
test('SF-02: Real-time search filtering', async () => {
it('SF-02: Real-time search filtering', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -228,7 +228,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
test('SF-03: Search highlighting', async () => {
it('SF-03: Search highlighting', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -257,7 +257,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
test('SF-04: Search with partial matches', async () => {
it('SF-04: Search with partial matches', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -298,7 +298,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 3. KEYBOARD NAVIGATION =====
describe('Keyboard Navigation (KN)', () => {
test('KN-01: Arrow key navigation in dropdown', async () => {
it('KN-01: Arrow key navigation in dropdown', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -329,7 +329,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
test('KN-02: Tab navigation to dropdown', async () => {
it('KN-02: Tab navigation to dropdown', async () => {
render(
<div>
<input data-testid="prev-input" />
@@ -355,7 +355,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
test('KN-03: Enter selection in dropdown', async () => {
it('KN-03: Enter selection in dropdown', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -376,7 +376,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
test('KN-04: Space key selection', async () => {
it('KN-04: Space key selection', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -396,7 +396,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
test('KN-05: Tab navigation within dropdown', async () => {
it('KN-05: Tab navigation within dropdown', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -417,7 +417,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 4. UI/UX BEHAVIORS =====
describe('UI/UX Behaviors (UI)', () => {
test('UI-01: Loading state does not block interaction', async () => {
it('UI-01: Loading state does not block interaction', async () => {
render(
<CustomSelect options={mockOptions} onChange={mockOnChange} loading />,
);
@@ -429,7 +429,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
expect(combobox).toHaveFocus();
});
test('UI-02: Component remains editable in all states', () => {
it('UI-02: Component remains editable in all states', () => {
render(
<CustomSelect
options={mockOptions}
@@ -444,7 +444,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
expect(combobox).not.toBeDisabled();
});
test('UI-03: Loading state display in footer', async () => {
it('UI-03: Loading state display in footer', async () => {
render(
<CustomSelect options={mockOptions} onChange={mockOnChange} loading />,
);
@@ -458,7 +458,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
test('UI-04: Error state display in footer', async () => {
it('UI-04: Error state display in footer', async () => {
render(
<CustomSelect
options={mockOptions}
@@ -477,7 +477,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
test('UI-05: No data state display', async () => {
it('UI-05: No data state display', async () => {
render(
<CustomSelect
options={[]}
@@ -497,7 +497,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 6. SAVE AND SELECTION TRIGGERS =====
describe('Save and Selection Triggers (ST)', () => {
test('ST-01: Mouse selection works', async () => {
it('ST-01: Mouse selection works', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -520,7 +520,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 7. GROUPED OPTIONS SUPPORT =====
describe('Grouped Options Support', () => {
test('handles grouped options correctly', async () => {
it('handles grouped options correctly', async () => {
render(
<CustomSelect options={mockGroupedOptions} onChange={mockOnChange} />,
);
@@ -541,7 +541,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
test('grouped option selection works', async () => {
it('grouped option selection works', async () => {
render(
<CustomSelect options={mockGroupedOptions} onChange={mockOnChange} />,
);
@@ -566,7 +566,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 8. ACCESSIBILITY =====
describe('Accessibility', () => {
test('has proper ARIA attributes', async () => {
it('has proper ARIA attributes', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -580,7 +580,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
test('supports screen reader navigation', async () => {
it('supports screen reader navigation', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -596,7 +596,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
test('has proper focus management', async () => {
it('has proper focus management', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -617,7 +617,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 10. EDGE CASES =====
describe('Edge Cases', () => {
test('handles special characters in options', async () => {
it('handles special characters in options', async () => {
const specialOptions = [
{ label: 'Option with spaces', value: 'option-with-spaces' },
{ label: 'Option-with-dashes', value: 'option-with-dashes' },
@@ -638,7 +638,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
test('handles extremely long option labels', async () => {
it('handles extremely long option labels', async () => {
const longLabelOptions = [
{
label:
@@ -663,7 +663,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 11. ADVANCED KEYBOARD NAVIGATION =====
describe('Advanced Keyboard Navigation (AKN)', () => {
test('AKN-01: Mouse out closes dropdown', async () => {
it('AKN-01: Mouse out closes dropdown', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -684,7 +684,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
test('AKN-02: TAB navigation from input to dropdown', async () => {
it('AKN-02: TAB navigation from input to dropdown', async () => {
render(
<div>
<input data-testid="prev-input" />
@@ -722,7 +722,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 12. ADVANCED FILTERING AND HIGHLIGHTING =====
describe('Advanced Filtering and Highlighting (AFH)', () => {
test('AFH-01: Highlighted values pushed to top', async () => {
it('AFH-01: Highlighted values pushed to top', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -776,7 +776,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
test('AFH-02: Distinction between selection Enter and save Enter', async () => {
it('AFH-02: Distinction between selection Enter and save Enter', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -830,7 +830,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 13. ADVANCED CLEAR ACTIONS =====
describe('Advanced Clear Actions (ACA)', () => {
test('ACA-01: Clear action waiting behavior', async () => {
it('ACA-01: Clear action waiting behavior', async () => {
const mockOnChangeWithDelay = jest.fn().mockImplementation(
() =>
new Promise((resolve) => {
@@ -860,7 +860,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
expect(mockOnChangeWithDelay).toHaveBeenCalled();
});
test('ACA-02: Single select clear behavior like text input', async () => {
it('ACA-02: Single select clear behavior like text input', async () => {
render(
<CustomSelect
options={mockOptions}
@@ -883,7 +883,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 14. ADVANCED UI STATES =====
describe('Advanced UI States (AUS)', () => {
test('AUS-01: No data with previous value selected', async () => {
it('AUS-01: No data with previous value selected', async () => {
render(
<CustomSelect
options={[]}
@@ -905,7 +905,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
expect(screen.getAllByText('previous-value')).toHaveLength(2);
});
test('AUS-02: Always editable accessibility', async () => {
it('AUS-02: Always editable accessibility', async () => {
render(
<CustomSelect options={mockOptions} onChange={mockOnChange} loading />,
);
@@ -921,7 +921,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
expect(combobox).not.toBeDisabled();
});
test('AUS-03: Sufficient space for search value', async () => {
it('AUS-03: Sufficient space for search value', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -950,7 +950,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
test('AUS-04: No spinners blocking user interaction', async () => {
it('AUS-04: No spinners blocking user interaction', async () => {
render(
<CustomSelect options={mockOptions} onChange={mockOnChange} loading />,
);
@@ -976,7 +976,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 15. REGEX AND CUSTOM VALUES =====
describe('Regex and Custom Values (RCV)', () => {
test('RCV-01: Regex pattern support', async () => {
it('RCV-01: Regex pattern support', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -1019,7 +1019,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
test('RCV-02: Custom values treated as normal dropdown values', async () => {
it('RCV-02: Custom values treated as normal dropdown values', async () => {
const customOptions = [
...mockOptions,
{ label: 'custom-value', value: 'custom-value', type: 'custom' as const },
@@ -1051,7 +1051,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 16. DROPDOWN PERSISTENCE =====
describe('Dropdown Persistence (DP)', () => {
test('DP-01: Dropdown closes only on save actions', async () => {
it('DP-01: Dropdown closes only on save actions', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');

View File

@@ -86,7 +86,7 @@ describe('VariableItem Integration Tests', () => {
// ===== 1. INTEGRATION WITH CUSTOMSELECT =====
describe('CustomSelect Integration (VI)', () => {
test('VI-01: Single select variable integration', async () => {
it('VI-01: Single select variable integration', async () => {
const variable = createMockVariable({
multiSelect: false,
type: 'CUSTOM',
@@ -130,7 +130,7 @@ describe('VariableItem Integration Tests', () => {
// ===== 2. INTEGRATION WITH CUSTOMMULTISELECT =====
describe('CustomMultiSelect Integration (VI)', () => {
test('VI-02: Multi select variable integration', async () => {
it('VI-02: Multi select variable integration', async () => {
const variable = createMockVariable({
multiSelect: true,
type: 'CUSTOM',
@@ -174,7 +174,7 @@ describe('VariableItem Integration Tests', () => {
// ===== 3. TEXTBOX VARIABLE TYPE =====
describe('Textbox Variable Integration', () => {
test('VI-03: Textbox variable handling', async () => {
it('VI-03: Textbox variable handling', async () => {
const variable = createMockVariable({
type: 'TEXTBOX',
selectedValue: 'initial-value',
@@ -219,7 +219,7 @@ describe('VariableItem Integration Tests', () => {
// ===== 4. VALUE PERSISTENCE AND STATE MANAGEMENT =====
describe('Value Persistence and State Management', () => {
test('VI-04: All selected state handling', () => {
it('VI-04: All selected state handling', () => {
const variable = createMockVariable({
multiSelect: true,
type: 'CUSTOM',
@@ -243,7 +243,7 @@ describe('VariableItem Integration Tests', () => {
expect(screen.getByText('ALL')).toBeInTheDocument();
});
test('VI-05: Dropdown behavior with temporary selections', async () => {
it('VI-05: Dropdown behavior with temporary selections', async () => {
const variable = createMockVariable({
multiSelect: true,
type: 'CUSTOM',
@@ -277,7 +277,7 @@ describe('VariableItem Integration Tests', () => {
// ===== 6. ACCESSIBILITY AND USER EXPERIENCE =====
describe('Accessibility and User Experience', () => {
test('VI-06: Variable description tooltip', async () => {
it('VI-06: Variable description tooltip', async () => {
const variable = createMockVariable({
description: 'This variable controls the service selection',
type: 'CUSTOM',
@@ -310,7 +310,7 @@ describe('VariableItem Integration Tests', () => {
});
});
test('VI-07: Variable name display', () => {
it('VI-07: Variable name display', () => {
const variable = createMockVariable({
name: 'service_name',
type: 'CUSTOM',
@@ -331,7 +331,7 @@ describe('VariableItem Integration Tests', () => {
expect(screen.getByText('$service_name')).toBeInTheDocument();
});
test('VI-08: Max tag count behavior', async () => {
it('VI-08: Max tag count behavior', async () => {
const variable = createMockVariable({
multiSelect: true,
type: 'CUSTOM',
@@ -365,7 +365,7 @@ describe('VariableItem Integration Tests', () => {
// ===== 8. SEARCH INTERACTION TESTS =====
describe('Search Interaction Tests', () => {
test('VI-14: Search persistence across dropdown open/close', async () => {
it('VI-14: Search persistence across dropdown open/close', async () => {
const variable = createMockVariable({
type: 'CUSTOM',
customValue: 'option1,option2,option3',
@@ -417,7 +417,7 @@ describe('VariableItem Integration Tests', () => {
// ===== 9. ADVANCED KEYBOARD NAVIGATION =====
describe('Advanced Keyboard Navigation (VI)', () => {
test('VI-15: Shift + Arrow + Del chip deletion in multiselect', async () => {
it('VI-15: Shift + Arrow + Del chip deletion in multiselect', async () => {
const variable = createMockVariable({
type: 'CUSTOM',
customValue: 'option1,option2,option3',
@@ -461,7 +461,7 @@ describe('VariableItem Integration Tests', () => {
// ===== 11. ADVANCED UI STATES =====
describe('Advanced UI States (VI)', () => {
test('VI-19: No data with previous value selected in variable', async () => {
it('VI-19: No data with previous value selected in variable', async () => {
const variable = createMockVariable({
type: 'CUSTOM',
customValue: '',
@@ -499,7 +499,7 @@ describe('VariableItem Integration Tests', () => {
expect(combobox).toBeInTheDocument();
});
test('VI-20: Always editable accessibility in variable', async () => {
it('VI-20: Always editable accessibility in variable', async () => {
const variable = createMockVariable({
type: 'CUSTOM',
customValue: 'option1,option2',
@@ -530,7 +530,7 @@ describe('VariableItem Integration Tests', () => {
// ===== 13. DROPDOWN PERSISTENCE =====
describe('Dropdown Persistence (VI)', () => {
test('VI-24: Dropdown stays open for non-save actions in variable', async () => {
it('VI-24: Dropdown stays open for non-save actions in variable', async () => {
const variable = createMockVariable({
type: 'CUSTOM',
customValue: 'option1,option2,option3',

View File

@@ -44,7 +44,7 @@ describe('OverflowInputToolTip', () => {
jest.restoreAllMocks();
});
test('shows tooltip when content overflows and input is clamped at maxAutoWidth', async () => {
it('shows tooltip when content overflows and input is clamped at maxAutoWidth', async () => {
mockOverflow(150, 250); // clientWidth >= maxAutoWidth (150), scrollWidth > clientWidth
render(<OverflowInputToolTip value="Very long overflowing text" />);
@@ -64,7 +64,7 @@ describe('OverflowInputToolTip', () => {
).toBeInTheDocument();
});
test('does NOT show tooltip when content does not overflow', async () => {
it('does NOT show tooltip when content does not overflow', async () => {
mockOverflow(150, 100); // content fits (scrollWidth <= clientWidth)
render(<OverflowInputToolTip value="Short text" />);
@@ -76,7 +76,7 @@ describe('OverflowInputToolTip', () => {
});
});
test('does NOT show tooltip when content overflows but input is NOT at maxAutoWidth', async () => {
it('does NOT show tooltip when content overflows but input is NOT at maxAutoWidth', async () => {
mockOverflow(100, 250); // clientWidth < maxAutoWidth (150), scrollWidth > clientWidth
render(<OverflowInputToolTip value="Long but input not clamped" />);
@@ -88,7 +88,7 @@ describe('OverflowInputToolTip', () => {
});
});
test('uncontrolled input allows typing', async () => {
it('uncontrolled input allows typing', async () => {
render(<OverflowInputToolTip defaultValue="Init" />);
const input = screen.getByRole('textbox') as HTMLInputElement;
@@ -97,7 +97,7 @@ describe('OverflowInputToolTip', () => {
expect(input).toHaveValue('InitABC');
});
test('disabled input never shows tooltip even if overflowing', async () => {
it('disabled input never shows tooltip even if overflowing', async () => {
mockOverflow(150, 300);
render(<OverflowInputToolTip value="Overflowing!" disabled />);
@@ -109,7 +109,7 @@ describe('OverflowInputToolTip', () => {
});
});
test('renders mirror span and input correctly (structural assertions instead of snapshot)', () => {
it('renders mirror span and input correctly (structural assertions instead of snapshot)', () => {
const { container } = render(<OverflowInputToolTip value="Snapshot" />);
const mirror = container.querySelector('.overflow-input-mirror');
const input = container.querySelector('input') as HTMLInputElement | null;

View File

@@ -29,7 +29,7 @@ describe('traceOperatorContextUtils', () => {
null,
);
expect(context).toEqual({
expect(context).toStrictEqual({
tokenType: TraceOperatorGrammarLexer.IDENTIFIER,
text: 'test',
start: 0,
@@ -62,7 +62,7 @@ describe('traceOperatorContextUtils', () => {
false,
);
expect(context).toEqual({
expect(context).toStrictEqual({
tokenType: TraceOperatorGrammarLexer.IDENTIFIER,
text: 'test',
start: 0,
@@ -193,7 +193,7 @@ describe('traceOperatorContextUtils', () => {
it('should return default context for empty query', () => {
const result = getTraceOperatorContextAtCursor('', 0);
expect(result).toEqual({
expect(result).toStrictEqual({
tokenType: -1,
text: '',
start: 0,
@@ -211,7 +211,7 @@ describe('traceOperatorContextUtils', () => {
it('should return default context for null query', () => {
const result = getTraceOperatorContextAtCursor(null as any, 0);
expect(result).toEqual({
expect(result).toStrictEqual({
tokenType: -1,
text: '',
start: 0,
@@ -229,7 +229,7 @@ describe('traceOperatorContextUtils', () => {
it('should return default context for undefined query', () => {
const result = getTraceOperatorContextAtCursor(undefined as any, 0);
expect(result).toEqual({
expect(result).toStrictEqual({
tokenType: -1,
text: '',
start: 0,

View File

@@ -8,21 +8,21 @@ const makeTraceOperator = (expression: string): IBuilderTraceOperator =>
describe('getInvolvedQueriesInTraceOperator', () => {
it('returns empty array for empty input', () => {
const result = getInvolvedQueriesInTraceOperator([]);
expect(result).toEqual([]);
expect(result).toStrictEqual([]);
});
it('extracts identifiers from expression', () => {
const result = getInvolvedQueriesInTraceOperator([
makeTraceOperator('A => B'),
]);
expect(result).toEqual(['A', 'B']);
expect(result).toStrictEqual(['A', 'B']);
});
it('extracts identifiers from complex expression', () => {
const result = getInvolvedQueriesInTraceOperator([
makeTraceOperator('A => (NOT B || C)'),
]);
expect(result).toEqual(['A', 'B', 'C']);
expect(result).toStrictEqual(['A', 'B', 'C']);
});
it('filters out querynames from complex expression', () => {
@@ -31,7 +31,7 @@ describe('getInvolvedQueriesInTraceOperator', () => {
'(A1 && (NOT B2 || (C3 -> (D4 && E5)))) => ((F6 || G7) && (NOT (H8 -> I9)))',
),
]);
expect(result).toEqual([
expect(result).toStrictEqual([
'A1',
'B2',
'C3',

View File

@@ -85,7 +85,7 @@ describe('previousQuery.utils', () => {
saveAsPreviousQuery(key, sampleQuery);
const fromStore = getPreviousQueryFromKey(key);
expect(fromStore).toEqual(sampleQuery);
expect(fromStore).toStrictEqual(sampleQuery);
});
it('saveAsPreviousQuery merges multiple entries and removeKeyFromPreviousQuery deletes one', () => {

View File

@@ -22,18 +22,20 @@ describe('convertFiltersToExpression', () => {
it('should handle empty, null, and undefined inputs', () => {
// Test null and undefined
expect(convertFiltersToExpression(null as any)).toEqual({ expression: '' });
expect(convertFiltersToExpression(undefined as any)).toEqual({
expect(convertFiltersToExpression(null as any)).toStrictEqual({
expression: '',
});
expect(convertFiltersToExpression(undefined as any)).toStrictEqual({
expression: '',
});
// Test empty filters
expect(convertFiltersToExpression({ items: [], op: 'AND' })).toEqual({
expect(convertFiltersToExpression({ items: [], op: 'AND' })).toStrictEqual({
expression: '',
});
expect(
convertFiltersToExpression({ items: undefined, op: 'AND' } as any),
).toEqual({ expression: '' });
).toStrictEqual({ expression: '' });
});
it('should convert basic comparison operators with proper value formatting', () => {
@@ -92,7 +94,7 @@ describe('convertFiltersToExpression', () => {
};
const result = convertFiltersToExpression(filters);
expect(result).toEqual({
expect(result).toStrictEqual({
expression:
"service = 'api-gateway' AND status != 'error' AND duration > 100 AND count <= 50 AND is_active = true AND enabled = false AND count = 0 AND regex REGEXP '.*'",
});
@@ -124,7 +126,7 @@ describe('convertFiltersToExpression', () => {
};
const result = convertFiltersToExpression(filters);
expect(result).toEqual({
expect(result).toStrictEqual({
expression:
"message = 'user\\'s data' AND description = '' AND path = '/api/v1/users'",
});
@@ -162,7 +164,7 @@ describe('convertFiltersToExpression', () => {
};
const result = convertFiltersToExpression(filters);
expect(result).toEqual({
expect(result).toStrictEqual({
expression:
"service in ['api-gateway', 'user-service', 'auth-service'] AND status in ['success'] AND tags in [] AND name in ['John\\'s', 'Mary\\'s', 'Bob']",
});
@@ -224,7 +226,7 @@ describe('convertFiltersToExpression', () => {
};
const result = convertFiltersToExpression(filters);
expect(result).toEqual({
expect(result).toStrictEqual({
expression:
"service NOT IN ['api-gateway', 'user-service'] AND message NOT LIKE 'error' AND path NOT REGEXP '/api/.*' AND service NOT IN ['api-gateway'] AND user_id NOT EXISTS AND description NOT CONTAINS 'error' AND NOT has(tags, 'production') AND NOT hasAny(labels, ['env:prod', 'service:api'])",
});
@@ -268,7 +270,7 @@ describe('convertFiltersToExpression', () => {
};
const result = convertFiltersToExpression(filters);
expect(result).toEqual({
expect(result).toStrictEqual({
expression:
"user_id exists AND user_id exists AND has(tags, 'production') AND hasAny(tags, ['production', 'staging']) AND hasAll(tags, ['production', 'monitoring'])",
});
@@ -312,7 +314,7 @@ describe('convertFiltersToExpression', () => {
};
const result = convertFiltersToExpression(filters);
expect(result).toEqual({
expect(result).toStrictEqual({
expression:
"service = 'api-gateway' AND status = 'success' AND service in ['api-gateway']",
});
@@ -362,7 +364,7 @@ describe('convertFiltersToExpression', () => {
};
const result = convertFiltersToExpression(filters);
expect(result).toEqual({
expect(result).toStrictEqual({
expression:
"service in ['api-gateway', 'user-service'] AND user_id exists AND has(tags, 'production') AND duration > 100 AND status NOT IN ['error', 'timeout'] AND method = 'POST'",
});
@@ -412,7 +414,7 @@ describe('convertFiltersToExpression', () => {
};
const result = convertFiltersToExpression(filters);
expect(result).toEqual({
expect(result).toStrictEqual({
expression:
"count = 0 AND score > 100 AND limit >= 50 AND threshold < 1000 AND max_value <= 999 AND values in ['1', '2', '3', '4', '5']",
});
@@ -456,7 +458,7 @@ describe('convertFiltersToExpression', () => {
};
const result = convertFiltersToExpression(filters);
expect(result).toEqual({
expect(result).toStrictEqual({
expression:
"is_active = true AND is_deleted = false AND email = 'user@example.com' AND description = 'Contains \"quotes\" and \\'apostrophes\\'' AND path = '/api/v1/users/123?filter=true'",
});
@@ -506,7 +508,7 @@ describe('convertFiltersToExpression', () => {
};
const result = convertFiltersToExpression(filters);
expect(result).toEqual({
expect(result).toStrictEqual({
expression:
"has(tags, 'production') AND hasAny(labels, ['env:prod', 'service:api']) AND hasAll(metadata, ['version:1.0', 'team:backend']) AND services in ['api-gateway', 'user-service', 'auth-service', 'payment-service'] AND excluded_services NOT IN ['legacy-service', 'deprecated-service'] AND status_codes in ['200', '201', '400', '500']",
});
@@ -544,7 +546,7 @@ describe('convertFiltersToExpression', () => {
};
const result = convertFiltersToExpression(filters);
expect(result).toEqual({
expect(result).toStrictEqual({
expression:
"user_id NOT EXISTS AND description NOT CONTAINS 'error' AND NOT has(tags, 'production') AND NOT hasAny(labels, ['env:prod', 'service:api'])",
});
@@ -568,7 +570,7 @@ describe('convertFiltersToExpression', () => {
undefined,
);
expect(result.filters).toEqual(filters);
expect(result.filters).toStrictEqual(filters);
expect(result.filter.expression).toBe("service.name = 'test-service'");
});
@@ -583,7 +585,7 @@ describe('convertFiltersToExpression', () => {
undefined,
);
expect(result.filters).toEqual(filters);
expect(result.filters).toStrictEqual(filters);
expect(result.filter.expression).toBe('');
});
@@ -611,7 +613,7 @@ describe('convertFiltersToExpression', () => {
expect(result.filter).toBeDefined();
expect(result.filter.expression).toBe("service.name = 'updated-service'");
// Ensure parser can parse the existing query
expect(extractQueryPairs(existingQuery)).toEqual(
expect(extractQueryPairs(existingQuery)).toStrictEqual(
expect.arrayContaining([
expect.objectContaining({
key: 'service.name',
@@ -805,7 +807,7 @@ describe('convertAggregationToExpression', () => {
temporality: 'delta',
});
expect(result).toEqual([
expect(result).toStrictEqual([
{
metricName: 'test_metric',
timeAggregation: 'avg',
@@ -825,9 +827,11 @@ describe('convertAggregationToExpression', () => {
spaceAggregation: 'noop',
});
expect(result).toEqual([
expect(result).toStrictEqual([
{
metricName: 'test_metric',
reduceTo: undefined,
temporality: undefined,
timeAggregation: 'count',
spaceAggregation: 'count',
},
@@ -841,9 +845,11 @@ describe('convertAggregationToExpression', () => {
dataSource: DataSource.METRICS,
});
expect(result).toEqual([
expect(result).toStrictEqual([
{
metricName: '',
reduceTo: undefined,
temporality: undefined,
timeAggregation: 'sum',
spaceAggregation: 'sum',
},
@@ -858,7 +864,7 @@ describe('convertAggregationToExpression', () => {
alias: 'trace_alias',
});
expect(result).toEqual([
expect(result).toStrictEqual([
{
expression: 'count(test_metric)',
alias: 'trace_alias',
@@ -874,7 +880,7 @@ describe('convertAggregationToExpression', () => {
alias: 'log_alias',
});
expect(result).toEqual([
expect(result).toStrictEqual([
{
expression: 'avg(test_metric)',
alias: 'log_alias',
@@ -889,7 +895,7 @@ describe('convertAggregationToExpression', () => {
dataSource: DataSource.TRACES,
});
expect(result).toEqual([
expect(result).toStrictEqual([
{
expression: 'count()',
},
@@ -903,7 +909,7 @@ describe('convertAggregationToExpression', () => {
dataSource: DataSource.LOGS,
});
expect(result).toEqual([
expect(result).toStrictEqual([
{
expression: 'sum(test_metric)',
},
@@ -917,9 +923,11 @@ describe('convertAggregationToExpression', () => {
dataSource: DataSource.METRICS,
});
expect(result).toEqual([
expect(result).toStrictEqual([
{
metricName: 'test_metric',
reduceTo: undefined,
temporality: undefined,
timeAggregation: 'max',
spaceAggregation: 'max',
},
@@ -933,7 +941,7 @@ describe('convertAggregationToExpression', () => {
dataSource: DataSource.METRICS,
});
expect(result).toEqual([
expect(result).toStrictEqual([
{
metricName: 'test_metric',
timeAggregation: 'sum',
@@ -951,7 +959,7 @@ describe('convertAggregationToExpression', () => {
dataSource: DataSource.TRACES,
});
expect(result).toEqual([
expect(result).toStrictEqual([
{
expression: 'count()',
},
@@ -965,7 +973,7 @@ describe('convertAggregationToExpression', () => {
dataSource: DataSource.LOGS,
});
expect(result).toEqual([
expect(result).toStrictEqual([
{
expression: 'count()',
},

View File

@@ -471,6 +471,6 @@ describe('CheckboxFilter - User Flows', () => {
expect(filterForServiceName.key.key).toBe(SERVICE_NAME_KEY);
expect(filterForServiceName.op).toBe('in');
expect(filterForServiceName.value).toEqual(['mq-kafka', 'otel-demo']);
expect(filterForServiceName.value).toStrictEqual(['mq-kafka', 'otel-demo']);
});
});

View File

@@ -323,7 +323,9 @@ describe('Quick Filters with custom filters', () => {
const settingsButton = icon.closest('button') ?? icon;
await user.click(settingsButton);
expect(await screen.findByText('Edit quick filters')).toBeInTheDocument();
await expect(
screen.findByText('Edit quick filters'),
).resolves.toBeInTheDocument();
const addedSection = screen.getByText(ADDED_FILTERS_LABEL).parentElement!;
expect(addedSection).toContainElement(
@@ -454,7 +456,7 @@ describe('Quick Filters with custom filters', () => {
});
const requestBody = putHandler.mock.calls[0][0];
expect(requestBody.filters).toEqual(
expect(requestBody.filters).toStrictEqual(
expect.arrayContaining([
expect.not.objectContaining({ key: FILTER_OS_DESCRIPTION }),
]),
@@ -535,12 +537,16 @@ describe('Quick Filters refetch behavior', () => {
);
const { unmount } = render(<TestQuickFilters signal={SIGNAL} />);
expect(await screen.findByText(FILTER_SERVICE_NAME)).toBeInTheDocument();
await expect(
screen.findByText(FILTER_SERVICE_NAME),
).resolves.toBeInTheDocument();
unmount();
render(<TestQuickFilters signal={SIGNAL} />);
expect(await screen.findByText(FILTER_SERVICE_NAME)).toBeInTheDocument();
await expect(
screen.findByText(FILTER_SERVICE_NAME),
).resolves.toBeInTheDocument();
expect(getCalls).toBe(2);
});
@@ -578,7 +584,9 @@ describe('Quick Filters refetch behavior', () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
render(<TestQuickFilters signal={SIGNAL} />);
expect(await screen.findByText(FILTER_SERVICE_NAME)).toBeInTheDocument();
await expect(
screen.findByText(FILTER_SERVICE_NAME),
).resolves.toBeInTheDocument();
const icon = await screen.findByTestId(SETTINGS_ICON_TEST_ID);
const settingsButton = icon.closest('button') ?? icon;
@@ -628,7 +636,9 @@ describe('Quick Filters refetch behavior', () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
render(<TestQuickFilters signal={SIGNAL} />);
expect(await screen.findByText(FILTER_SERVICE_NAME)).toBeInTheDocument();
await expect(
screen.findByText(FILTER_SERVICE_NAME),
).resolves.toBeInTheDocument();
const icon = await screen.findByTestId(SETTINGS_ICON_TEST_ID);
const settingsButton = icon.closest('button') ?? icon;
@@ -657,6 +667,8 @@ describe('Quick Filters refetch behavior', () => {
render(<TestQuickFilters signal={SIGNAL} config={[]} />);
expect(await screen.findByText('No filters found')).toBeInTheDocument();
await expect(
screen.findByText('No filters found'),
).resolves.toBeInTheDocument();
});
});

View File

@@ -28,7 +28,7 @@ const testRoutes: RouteTabProps['routes'] = [
];
describe('RouteTab component', () => {
test('renders correctly', () => {
it('renders correctly', () => {
const history = createMemoryHistory();
render(
<Router history={history}>
@@ -39,7 +39,7 @@ describe('RouteTab component', () => {
expect(screen.getByRole('tab', { name: 'Tab2' })).toBeInTheDocument();
});
test('renders correct number of tabs', () => {
it('renders correct number of tabs', () => {
const history = createMemoryHistory();
render(
<Router history={history}>
@@ -47,10 +47,10 @@ describe('RouteTab component', () => {
</Router>,
);
const tabs = screen.getAllByRole('tab');
expect(tabs.length).toBe(testRoutes.length);
expect(tabs).toHaveLength(testRoutes.length);
});
test('sets provided activeKey as active tab', () => {
it('sets provided activeKey as active tab', () => {
const history = createMemoryHistory();
render(
<Router history={history}>
@@ -62,7 +62,7 @@ describe('RouteTab component', () => {
).toBeInTheDocument();
});
test('navigates to correct route on tab click', () => {
it('navigates to correct route on tab click', () => {
const history = createMemoryHistory();
render(
<Router history={history}>
@@ -74,7 +74,7 @@ describe('RouteTab component', () => {
expect(history.location.pathname).toBe('/tab2');
});
test('calls onChangeHandler on tab change', () => {
it('calls onChangeHandler on tab change', () => {
const onChangeHandler = jest.fn();
const history = createMemoryHistory();
render(

View File

@@ -70,9 +70,9 @@ describe('EditKeyModal (URL-controlled)', () => {
it('renders key data from prop when edit-key param is set', async () => {
renderModal();
expect(
await screen.findByDisplayValue('Original Key Name'),
).toBeInTheDocument();
await expect(
screen.findByDisplayValue('Original Key Name'),
).resolves.toBeInTheDocument();
expect(screen.getByRole('button', { name: /Save Changes/i })).toBeDisabled();
});
@@ -111,7 +111,7 @@ describe('EditKeyModal (URL-controlled)', () => {
const latestUrlUpdate =
onUrlUpdate.mock.calls[onUrlUpdate.mock.calls.length - 1]?.[0];
expect(latestUrlUpdate).toEqual(
expect(latestUrlUpdate).toStrictEqual(
expect.objectContaining({
queryString: expect.any(String),
}),
@@ -134,9 +134,9 @@ describe('EditKeyModal (URL-controlled)', () => {
await user.click(screen.getByRole('button', { name: /Revoke Key/i }));
// Same dialog, now showing revoke confirmation
expect(
await screen.findByRole('dialog', { name: /Revoke Original Key Name/i }),
).toBeInTheDocument();
await expect(
screen.findByRole('dialog', { name: /Revoke Original Key Name/i }),
).resolves.toBeInTheDocument();
expect(
screen.getByText(/Revoking this key will permanently invalidate it/i),
).toBeInTheDocument();

View File

@@ -104,7 +104,9 @@ describe('ServiceAccountDrawer', () => {
it('renders Overview tab by default: editable name input, locked email, Save disabled when not dirty', async () => {
renderDrawer();
expect(await screen.findByDisplayValue('CI Bot')).toBeInTheDocument();
await expect(
screen.findByDisplayValue('CI Bot'),
).resolves.toBeInTheDocument();
expect(screen.getByText('ci-bot@signoz.io')).toBeInTheDocument();
expect(screen.getByRole('button', { name: /Save Changes/i })).toBeDisabled();
});
@@ -272,11 +274,11 @@ describe('ServiceAccountDrawer', () => {
renderDrawer();
expect(
await screen.findByText(
await expect(
screen.findByText(
/An unexpected error occurred while fetching service account details/i,
),
).toBeInTheDocument();
).resolves.toBeInTheDocument();
});
});
@@ -349,11 +351,11 @@ describe('ServiceAccountDrawer save-error UX', () => {
await waitFor(() => expect(saveBtn).not.toBeDisabled());
await user.click(saveBtn);
expect(
await screen.findByText(/Name update.*name update failed/i, undefined, {
await expect(
screen.findByText(/Name update.*name update failed/i, undefined, {
timeout: 5000,
}),
).toBeInTheDocument();
).resolves.toBeInTheDocument();
});
it('role add failure shows SaveErrorItem with the role name context', async () => {
@@ -385,15 +387,11 @@ describe('ServiceAccountDrawer save-error UX', () => {
await waitFor(() => expect(saveBtn).not.toBeDisabled());
await user.click(saveBtn);
expect(
await screen.findByText(
/Role 'signoz-viewer'.*role assign failed/i,
undefined,
{
timeout: 5000,
},
),
).toBeInTheDocument();
await expect(
screen.findByText(/Role 'signoz-viewer'.*role assign failed/i, undefined, {
timeout: 5000,
}),
).resolves.toBeInTheDocument();
});
it('role add retries on 429 then succeeds without showing an error', async () => {

View File

@@ -63,7 +63,9 @@ describe('TanStackCustomTableRow', () => {
</tbody>
</table>,
);
expect(await screen.findByTestId('mocked-row-cells')).toBeInTheDocument();
await expect(
screen.findByTestId('mocked-row-cells'),
).resolves.toBeInTheDocument();
});
it('applies active class when isRowActive returns true', () => {

View File

@@ -183,7 +183,7 @@ describe('TanStackRowCells', () => {
</tbody>
</table>,
);
expect(await screen.findByText('expanded-r1')).toBeInTheDocument();
await expect(screen.findByText('expanded-r1')).resolves.toBeInTheDocument();
});
describe('new tab click', () => {

View File

@@ -36,7 +36,7 @@ describe('useColumnState', () => {
renderHook(() => useColumnState({ storageKey: TEST_KEY, columns }));
const state = useColumnStore.getState().tables[TEST_KEY];
expect(state.hiddenColumnIds).toEqual(['b']);
expect(state.hiddenColumnIds).toStrictEqual(['b']);
});
it('does not initialize without storageKey', () => {
@@ -61,7 +61,7 @@ describe('useColumnState', () => {
useColumnState({ storageKey: TEST_KEY, columns }),
);
expect(result.current.columnVisibility).toEqual({ b: false });
expect(result.current.columnVisibility).toStrictEqual({ b: false });
});
it('applies visibilityBehavior for grouped state', () => {
@@ -79,13 +79,15 @@ describe('useColumnState', () => {
const { result: notGrouped } = renderHook(() =>
useColumnState({ storageKey: TEST_KEY, columns, isGrouped: false }),
);
expect(notGrouped.current.columnVisibility).toEqual({ grouped: false });
expect(notGrouped.current.columnVisibility).toStrictEqual({
grouped: false,
});
// Grouped
const { result: grouped } = renderHook(() =>
useColumnState({ storageKey: TEST_KEY, columns, isGrouped: true }),
);
expect(grouped.current.columnVisibility).toEqual({ ungrouped: false });
expect(grouped.current.columnVisibility).toStrictEqual({ ungrouped: false });
});
it('combines store hidden + visibilityBehavior', () => {
@@ -103,7 +105,10 @@ describe('useColumnState', () => {
useColumnState({ storageKey: TEST_KEY, columns, isGrouped: true }),
);
expect(result.current.columnVisibility).toEqual({ a: false, b: false });
expect(result.current.columnVisibility).toStrictEqual({
a: false,
b: false,
});
});
});
@@ -119,7 +124,7 @@ describe('useColumnState', () => {
useColumnState({ storageKey: TEST_KEY, columns }),
);
expect(result.current.sortedColumns.map((c) => c.id)).toEqual([
expect(result.current.sortedColumns.map((c) => c.id)).toStrictEqual([
'a',
'b',
'c',
@@ -138,7 +143,7 @@ describe('useColumnState', () => {
useColumnState({ storageKey: TEST_KEY, columns }),
);
expect(result.current.sortedColumns.map((c) => c.id)).toEqual([
expect(result.current.sortedColumns.map((c) => c.id)).toStrictEqual([
'c',
'a',
'b',
@@ -157,7 +162,7 @@ describe('useColumnState', () => {
useColumnState({ storageKey: TEST_KEY, columns }),
);
expect(result.current.sortedColumns.map((c) => c.id)).toEqual([
expect(result.current.sortedColumns.map((c) => c.id)).toStrictEqual([
'pinned',
'b',
'a',
@@ -181,7 +186,7 @@ describe('useColumnState', () => {
result.current.hideColumn('a');
});
expect(result.current.columnVisibility).toEqual({ a: false });
expect(result.current.columnVisibility).toStrictEqual({ a: false });
});
it('showColumn shows a column', () => {
@@ -195,13 +200,13 @@ describe('useColumnState', () => {
useColumnState({ storageKey: TEST_KEY, columns }),
);
expect(result.current.columnVisibility).toEqual({ a: false });
expect(result.current.columnVisibility).toStrictEqual({ a: false });
act(() => {
result.current.showColumn('a');
});
expect(result.current.columnVisibility).toEqual({});
expect(result.current.columnVisibility).toStrictEqual({});
});
it('setColumnSizing updates sizing', () => {
@@ -219,7 +224,7 @@ describe('useColumnState', () => {
result.current.setColumnSizing({ a: 200 });
});
expect(result.current.columnSizing).toEqual({ a: 200 });
expect(result.current.columnSizing).toStrictEqual({ a: 200 });
});
it('setColumnOrder updates order from column array', () => {
@@ -237,7 +242,7 @@ describe('useColumnState', () => {
result.current.setColumnOrder([col('c'), col('a'), col('b')]);
});
expect(result.current.sortedColumns.map((c) => c.id)).toEqual([
expect(result.current.sortedColumns.map((c) => c.id)).toStrictEqual([
'c',
'a',
'b',

View File

@@ -29,9 +29,9 @@ describe('useColumnStore', () => {
});
const state = useColumnStore.getState().tables[TEST_KEY];
expect(state.hiddenColumnIds).toEqual(['b']);
expect(state.columnOrder).toEqual([]);
expect(state.columnSizing).toEqual({});
expect(state.hiddenColumnIds).toStrictEqual(['b']);
expect(state.columnOrder).toStrictEqual([]);
expect(state.columnSizing).toStrictEqual({});
});
it('does not reinitialize if already exists', () => {
@@ -124,7 +124,9 @@ describe('useColumnStore', () => {
.getState()
.setColumnSizing(TEST_KEY, { col1: 200, col2: 300 });
});
expect(useColumnStore.getState().tables[TEST_KEY].columnSizing).toEqual({
expect(
useColumnStore.getState().tables[TEST_KEY].columnSizing,
).toStrictEqual({
col1: 200,
col2: 300,
});
@@ -144,11 +146,9 @@ describe('useColumnStore', () => {
.getState()
.setColumnOrder(TEST_KEY, ['col2', 'col1', 'col3']);
});
expect(useColumnStore.getState().tables[TEST_KEY].columnOrder).toEqual([
'col2',
'col1',
'col3',
]);
expect(useColumnStore.getState().tables[TEST_KEY].columnOrder).toStrictEqual(
['col2', 'col1', 'col3'],
);
});
});
@@ -172,9 +172,9 @@ describe('useColumnStore', () => {
});
const state = useColumnStore.getState().tables[TEST_KEY];
expect(state.hiddenColumnIds).toEqual(['a']);
expect(state.columnOrder).toEqual([]);
expect(state.columnSizing).toEqual({});
expect(state.hiddenColumnIds).toStrictEqual(['a']);
expect(state.columnOrder).toStrictEqual([]);
expect(state.columnSizing).toStrictEqual({});
});
});
@@ -195,7 +195,7 @@ describe('useColumnStore', () => {
});
const state = useColumnStore.getState().tables[TEST_KEY];
expect(state.hiddenColumnIds).toEqual(['col1', 'col3']);
expect(state.hiddenColumnIds).toStrictEqual(['col1', 'col3']);
expect(state.hiddenColumnIds).not.toContain('col2');
});
@@ -216,7 +216,7 @@ describe('useColumnStore', () => {
});
const stateAfter = useColumnStore.getState().tables[TEST_KEY];
expect(stateAfter.hiddenColumnIds).toEqual(hiddenBefore);
expect(stateAfter.hiddenColumnIds).toStrictEqual(hiddenBefore);
});
it('does nothing for unknown storage key', () => {
@@ -242,7 +242,7 @@ describe('useColumnStore', () => {
});
const { result } = renderHook(() => useHiddenColumnIds(TEST_KEY));
expect(result.current).toEqual(['a']);
expect(result.current).toStrictEqual(['a']);
});
it('useHiddenColumnIds returns a stable snapshot for persisted state', () => {
@@ -270,7 +270,7 @@ describe('useColumnStore', () => {
});
const { result } = renderHook(() => useColumnSizing(TEST_KEY));
expect(result.current).toEqual({ col1: 150 });
expect(result.current).toStrictEqual({ col1: 150 });
});
it('useColumnOrder returns order', () => {
@@ -280,7 +280,7 @@ describe('useColumnStore', () => {
});
const { result } = renderHook(() => useColumnOrder(TEST_KEY));
expect(result.current).toEqual(['c', 'b', 'a']);
expect(result.current).toStrictEqual(['c', 'b', 'a']);
});
it('returns empty defaults for unknown storageKey', () => {
@@ -288,9 +288,9 @@ describe('useColumnStore', () => {
const { result: sizing } = renderHook(() => useColumnSizing('unknown'));
const { result: order } = renderHook(() => useColumnOrder('unknown'));
expect(hidden.current).toEqual([]);
expect(sizing.current).toEqual({});
expect(order.current).toEqual([]);
expect(hidden.current).toStrictEqual([]);
expect(sizing.current).toStrictEqual({});
expect(order.current).toStrictEqual([]);
});
});
});

View File

@@ -80,7 +80,10 @@ describe('useTableParams (local mode — enableQueryParams not set)', () => {
act(() => {
result.current.setOrderBy({ columnName: 'cpu', order: 'desc' });
});
expect(result.current.orderBy).toEqual({ columnName: 'cpu', order: 'desc' });
expect(result.current.orderBy).toStrictEqual({
columnName: 'cpu',
order: 'desc',
});
});
});
@@ -143,7 +146,10 @@ describe('useTableParams (URL mode — enableQueryParams set)', () => {
const orderBy = JSON.stringify({ columnName: 'name', order: 'desc' });
const wrapper = createNuqsWrapper({ order_by: orderBy });
const { result } = renderHook(() => useTableParams(true), { wrapper });
expect(result.current.orderBy).toEqual({ columnName: 'name', order: 'desc' });
expect(result.current.orderBy).toStrictEqual({
columnName: 'name',
order: 'desc',
});
});
it('updates URL when setPage is called', () => {
@@ -178,7 +184,7 @@ describe('useTableParams (URL mode — enableQueryParams set)', () => {
.filter(Boolean)
.pop();
expect(lastOrderBy).toBeDefined();
expect(JSON.parse(lastOrderBy!)).toEqual({
expect(JSON.parse(lastOrderBy!)).toStrictEqual({
columnName: 'value',
order: 'asc',
});
@@ -207,7 +213,7 @@ describe('useTableParams (URL mode — enableQueryParams set)', () => {
result.current.setExpanded({ 'row-1': true });
});
expect(result.current.expanded).toEqual({ 'row-1': true });
expect(result.current.expanded).toStrictEqual({ 'row-1': true });
});
it('toggles sort order correctly: null → asc → desc → null', () => {
@@ -222,13 +228,19 @@ describe('useTableParams (URL mode — enableQueryParams set)', () => {
act(() => {
result.current.setOrderBy({ columnName: 'id', order: 'asc' });
});
expect(result.current.orderBy).toEqual({ columnName: 'id', order: 'asc' });
expect(result.current.orderBy).toStrictEqual({
columnName: 'id',
order: 'asc',
});
// Second click: asc → desc
act(() => {
result.current.setOrderBy({ columnName: 'id', order: 'desc' });
});
expect(result.current.orderBy).toEqual({ columnName: 'id', order: 'desc' });
expect(result.current.orderBy).toStrictEqual({
columnName: 'id',
order: 'desc',
});
// Third click: desc → null
act(() => {

View File

@@ -8,7 +8,7 @@ import { formatUniversalUnit } from '../formatter';
describe('formatUniversalUnit', () => {
describe('Time', () => {
test.each([
it.each([
// Days
[31, UniversalYAxisUnit.DAYS, '4.43 weeks'],
[7, UniversalYAxisUnit.DAYS, '1 week'],
@@ -48,7 +48,7 @@ describe('formatUniversalUnit', () => {
});
describe('Data', () => {
test.each([
it.each([
// Bytes
[864, UniversalYAxisUnit.BYTES, '864 B'],
[1000, UniversalYAxisUnit.BYTES, '1 kB'],
@@ -91,7 +91,7 @@ describe('formatUniversalUnit', () => {
});
describe('Data rate', () => {
test.each([
it.each([
// Bytes/second
[864, UniversalYAxisUnit.BYTES_SECOND, '864 B/s'],
[1000, UniversalYAxisUnit.BYTES_SECOND, '1 kB/s'],
@@ -134,7 +134,7 @@ describe('formatUniversalUnit', () => {
});
describe('Bit', () => {
test.each([
it.each([
// Bits
[1, UniversalYAxisUnit.BITS, '1 b'],
[250, UniversalYAxisUnit.BITS, '250 b'],
@@ -186,7 +186,7 @@ describe('formatUniversalUnit', () => {
});
describe('Bit rate', () => {
test.each([
it.each([
// Bits/second
[512, UniversalYAxisUnit.BITS_SECOND, '512 b/s'],
[1000, UniversalYAxisUnit.BITS_SECOND, '1 kb/s'],
@@ -236,7 +236,7 @@ describe('formatUniversalUnit', () => {
});
describe('Count', () => {
test.each([
it.each([
[100, UniversalYAxisUnit.COUNT, '100'],
[875, UniversalYAxisUnit.COUNT, '875'],
[1000, UniversalYAxisUnit.COUNT, '1 K'],
@@ -256,7 +256,7 @@ describe('formatUniversalUnit', () => {
expect(formatUniversalUnit(value, unit)).toBe(expected);
});
test.each([
it.each([
[100, UniversalYAxisUnit.COUNT_SECOND, '100 c/s'],
[875, UniversalYAxisUnit.COUNT_SECOND, '875 c/s'],
[1000, UniversalYAxisUnit.COUNT_SECOND, '1K c/s'],
@@ -267,7 +267,7 @@ describe('formatUniversalUnit', () => {
expect(formatUniversalUnit(value, unit)).toBe(expected);
});
test.each([
it.each([
[100, UniversalYAxisUnit.COUNT_MINUTE, '100 c/m'],
[875, UniversalYAxisUnit.COUNT_MINUTE, '875 c/m'],
[1000, UniversalYAxisUnit.COUNT_MINUTE, '1K c/m'],
@@ -280,7 +280,7 @@ describe('formatUniversalUnit', () => {
});
describe('Operations units', () => {
test.each([
it.each([
[780, UniversalYAxisUnit.OPS_SECOND, '780 ops/s'],
[1000, UniversalYAxisUnit.OPS_SECOND, '1K ops/s'],
[520, UniversalYAxisUnit.OPS_MINUTE, '520 ops/m'],
@@ -297,7 +297,7 @@ describe('formatUniversalUnit', () => {
});
describe('Request units', () => {
test.each([
it.each([
[615, UniversalYAxisUnit.REQUESTS_SECOND, '615 req/s'],
[1000, UniversalYAxisUnit.REQUESTS_SECOND, '1K req/s'],
[480, UniversalYAxisUnit.REQUESTS_MINUTE, '480 req/m'],
@@ -311,7 +311,7 @@ describe('formatUniversalUnit', () => {
});
describe('Read/Write units', () => {
test.each([
it.each([
[505, UniversalYAxisUnit.READS_SECOND, '505 rd/s'],
[1000, UniversalYAxisUnit.READS_SECOND, '1K rd/s'],
[610, UniversalYAxisUnit.WRITES_SECOND, '610 wr/s'],
@@ -335,7 +335,7 @@ describe('formatUniversalUnit', () => {
});
describe('IO Operations units', () => {
test.each([
it.each([
[777, UniversalYAxisUnit.IOOPS_SECOND, '777 io/s'],
[1000, UniversalYAxisUnit.IOOPS_SECOND, '1K io/s'],
[2500, UniversalYAxisUnit.IOOPS_SECOND, '2.5K io/s'],
@@ -363,7 +363,7 @@ describe('formatUniversalUnit', () => {
});
describe('Time (additional)', () => {
test.each([
it.each([
[900, UniversalYAxisUnit.DURATION_MS, '900 milliseconds'],
[1000, UniversalYAxisUnit.DURATION_MS, '1 second'],
[1, UniversalYAxisUnit.DURATION_MS, '1 millisecond'],
@@ -388,7 +388,7 @@ describe('formatUniversalUnit', () => {
});
describe('Data (IEC/Binary)', () => {
test.each([
it.each([
// Bytes
[900, UniversalYAxisUnit.BYTES_IEC, '900 B'],
[1024, UniversalYAxisUnit.BYTES_IEC, '1 KiB'],
@@ -430,7 +430,7 @@ describe('formatUniversalUnit', () => {
});
describe('Data Rate (IEC/Binary)', () => {
test.each([
it.each([
// Kibibytes/second
[900, UniversalYAxisUnit.KIBIBYTES_SECOND, '900 KiB/s'],
[1024, UniversalYAxisUnit.KIBIBYTES_SECOND, '1 MiB/s'],
@@ -473,7 +473,7 @@ describe('formatUniversalUnit', () => {
});
describe('Bits (IEC)', () => {
test.each([
it.each([
[900, UniversalYAxisUnit.BITS_IEC, '900 b'],
[1024, UniversalYAxisUnit.BITS_IEC, '1 Kib'],
[1080, UniversalYAxisUnit.BITS_IEC, '1.05 Kib'],
@@ -483,7 +483,7 @@ describe('formatUniversalUnit', () => {
});
describe('Hash Rate', () => {
test.each([
it.each([
// Hashes/second
[412, UniversalYAxisUnit.HASH_RATE_HASHES_PER_SECOND, '412 H/s'],
[1000, UniversalYAxisUnit.HASH_RATE_HASHES_PER_SECOND, '1 kH/s'],
@@ -518,7 +518,7 @@ describe('formatUniversalUnit', () => {
});
describe('Miscellaneous', () => {
test.each([
it.each([
[742, UniversalYAxisUnit.MISC_STRING, '742'],
[688, UniversalYAxisUnit.MISC_SHORT, '688'],
[555, UniversalYAxisUnit.MISC_HUMIDITY, '555 %H'],
@@ -534,7 +534,7 @@ describe('formatUniversalUnit', () => {
});
describe('Acceleration', () => {
test.each([
it.each([
[
875,
UniversalYAxisUnit.ACCELERATION_METERS_PER_SECOND_SQUARED,
@@ -553,7 +553,7 @@ describe('formatUniversalUnit', () => {
});
describe('Angular', () => {
test.each([
it.each([
[415, UniversalYAxisUnit.ANGULAR_DEGREE, '415 °'],
[732, UniversalYAxisUnit.ANGULAR_RADIAN, '732 rad'],
[128, UniversalYAxisUnit.ANGULAR_GRADIAN, '128 grad'],
@@ -565,7 +565,7 @@ describe('formatUniversalUnit', () => {
});
describe('Area', () => {
test.each([
it.each([
[210, UniversalYAxisUnit.AREA_SQUARE_METERS, '210 m²'],
[152, UniversalYAxisUnit.AREA_SQUARE_FEET, '152 ft²'],
[64, UniversalYAxisUnit.AREA_SQUARE_MILES, '64 mi²'],
@@ -575,7 +575,7 @@ describe('formatUniversalUnit', () => {
});
describe('FLOPs', () => {
test.each([
it.each([
// FLOPS
[150, UniversalYAxisUnit.FLOPS_FLOPS, '150 FLOPS'],
[1000, UniversalYAxisUnit.FLOPS_FLOPS, '1 kFLOPS'],
@@ -613,7 +613,7 @@ describe('formatUniversalUnit', () => {
});
describe('Concentration', () => {
test.each([
it.each([
[415, UniversalYAxisUnit.CONCENTRATION_PPM, '415 ppm'],
[1000, UniversalYAxisUnit.CONCENTRATION_PPM, '1000 ppm'],
[732, UniversalYAxisUnit.CONCENTRATION_PPB, '732 ppb'],
@@ -650,7 +650,7 @@ describe('formatUniversalUnit', () => {
});
describe('Currency', () => {
test.each([
it.each([
[812, UniversalYAxisUnit.CURRENCY_USD, '$812'],
[645, UniversalYAxisUnit.CURRENCY_GBP, '£645'],
[731, UniversalYAxisUnit.CURRENCY_EUR, '€731'],
@@ -688,7 +688,7 @@ describe('formatUniversalUnit', () => {
});
describe('Power/Electrical', () => {
test.each([
it.each([
[715, UniversalYAxisUnit.POWER_WATT, '715 W'],
[1000, UniversalYAxisUnit.POWER_WATT, '1 kW'],
[1080, UniversalYAxisUnit.POWER_WATT, '1.08 kW'],
@@ -744,7 +744,7 @@ describe('formatUniversalUnit', () => {
});
describe('Flow', () => {
test.each([
it.each([
[512, UniversalYAxisUnit.FLOW_GALLONS_PER_MINUTE, '512 gpm'],
[1000, UniversalYAxisUnit.FLOW_GALLONS_PER_MINUTE, '1000 gpm'],
[678, UniversalYAxisUnit.FLOW_CUBIC_METERS_PER_SECOND, '678 cms'],
@@ -766,7 +766,7 @@ describe('formatUniversalUnit', () => {
});
describe('Force', () => {
test.each([
it.each([
[845, UniversalYAxisUnit.FORCE_NEWTON_METERS, '845 Nm'],
[1000, UniversalYAxisUnit.FORCE_NEWTON_METERS, '1 kNm'],
[1080, UniversalYAxisUnit.FORCE_NEWTON_METERS, '1.08 kNm'],
@@ -782,7 +782,7 @@ describe('formatUniversalUnit', () => {
});
describe('Mass', () => {
test.each([
it.each([
[120, UniversalYAxisUnit.MASS_MILLIGRAM, '120 mg'],
[120000, UniversalYAxisUnit.MASS_MILLIGRAM, '120 g'],
[987, UniversalYAxisUnit.MASS_GRAM, '987 g'],
@@ -796,7 +796,7 @@ describe('formatUniversalUnit', () => {
});
describe('Length', () => {
test.each([
it.each([
[88, UniversalYAxisUnit.LENGTH_MILLIMETER, '88 mm'],
[100, UniversalYAxisUnit.LENGTH_MILLIMETER, '100 mm'],
[1000, UniversalYAxisUnit.LENGTH_MILLIMETER, '1 m'],
@@ -812,7 +812,7 @@ describe('formatUniversalUnit', () => {
});
describe('Pressure', () => {
test.each([
it.each([
[45, UniversalYAxisUnit.PRESSURE_MILLIBAR, '45 mbar'],
[1013, UniversalYAxisUnit.PRESSURE_MILLIBAR, '1.01 bar'],
[27, UniversalYAxisUnit.PRESSURE_BAR, '27 bar'],
@@ -828,7 +828,7 @@ describe('formatUniversalUnit', () => {
});
describe('Radiation', () => {
test.each([
it.each([
[452, UniversalYAxisUnit.RADIATION_BECQUEREL, '452 Bq'],
[37, UniversalYAxisUnit.RADIATION_CURIE, '37 Ci'],
[128, UniversalYAxisUnit.RADIATION_GRAY, '128 Gy'],
@@ -849,7 +849,7 @@ describe('formatUniversalUnit', () => {
});
describe('Rotation Speed', () => {
test.each([
it.each([
[345, UniversalYAxisUnit.ROTATION_SPEED_REVOLUTIONS_PER_MINUTE, '345 rpm'],
[789, UniversalYAxisUnit.ROTATION_SPEED_HERTZ, '789 Hz'],
[789000, UniversalYAxisUnit.ROTATION_SPEED_HERTZ, '789 kHz'],
@@ -861,7 +861,7 @@ describe('formatUniversalUnit', () => {
});
describe('Temperature', () => {
test.each([
it.each([
[37, UniversalYAxisUnit.TEMPERATURE_CELSIUS, '37 °C'],
[451, UniversalYAxisUnit.TEMPERATURE_FAHRENHEIT, '451 °F'],
[310, UniversalYAxisUnit.TEMPERATURE_KELVIN, '310 K'],
@@ -871,7 +871,7 @@ describe('formatUniversalUnit', () => {
});
describe('Velocity', () => {
test.each([
it.each([
[900, UniversalYAxisUnit.VELOCITY_METERS_PER_SECOND, '900 m/s'],
[456, UniversalYAxisUnit.VELOCITY_KILOMETERS_PER_HOUR, '456 km/h'],
[789, UniversalYAxisUnit.VELOCITY_MILES_PER_HOUR, '789 mph'],
@@ -882,7 +882,7 @@ describe('formatUniversalUnit', () => {
});
describe('Volume', () => {
test.each([
it.each([
[1200, UniversalYAxisUnit.VOLUME_MILLILITER, '1.2 L'],
[9000000, UniversalYAxisUnit.VOLUME_MILLILITER, '9 kL'],
[9, UniversalYAxisUnit.VOLUME_LITER, '9 L'],

View File

@@ -16,8 +16,8 @@ describe('YAxisUnitSelector utils', () => {
it('returns null or self for unknown units', () => {
expect(mapMetricUnitToUniversalUnit('unknown_unit')).toBe('unknown_unit');
expect(mapMetricUnitToUniversalUnit('')).toBe(null);
expect(mapMetricUnitToUniversalUnit(undefined)).toBe(null);
expect(mapMetricUnitToUniversalUnit('')).toBeNull();
expect(mapMetricUnitToUniversalUnit(undefined)).toBeNull();
});
});
@@ -62,7 +62,7 @@ describe('YAxisUnitSelector utils', () => {
},
];
const mergedCategories = mergeCategories(categories1, categories2);
expect(mergedCategories).toEqual([
expect(mergedCategories).toStrictEqual([
{
name: YAxisCategoryNames.Data,
units: [

View File

@@ -149,7 +149,7 @@ describe('CmdKPalette', () => {
jest.clearAllMocks();
});
test('renders navigation and settings groups and items', () => {
it('renders navigation and settings groups and items', () => {
render(<CmdKPalette userRole="ADMIN" />);
expect(screen.getByText('Navigation')).toBeInTheDocument();
@@ -160,7 +160,7 @@ describe('CmdKPalette', () => {
expect(screen.getByText('Switch to Dark Mode')).toBeInTheDocument();
});
test('clicking a navigation item calls history.push with correct route', async () => {
it('clicking a navigation item calls history.push with correct route', async () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
render(<CmdKPalette userRole="ADMIN" />);
@@ -170,14 +170,14 @@ describe('CmdKPalette', () => {
expect(history.push).toHaveBeenCalledWith(ROUTES.HOME);
});
test('role-based filtering (basic smoke)', () => {
it('role-based filtering (basic smoke)', () => {
render(<CmdKPalette userRole="VIEWER" />);
// VIEWER still sees basic navigation items
expect(screen.getByText(HOME_LABEL)).toBeInTheDocument();
});
test('keyboard shortcut opens palette via setOpen', () => {
it('keyboard shortcut opens palette via setOpen', () => {
render(<CmdKPalette userRole="ADMIN" />);
const event = new KeyboardEvent('keydown', { key: 'k', ctrlKey: true });
@@ -186,7 +186,7 @@ describe('CmdKPalette', () => {
expect(mockSetOpen).toHaveBeenCalledWith(true);
});
test('items render with icons when provided', () => {
it('items render with icons when provided', () => {
render(<CmdKPalette userRole="ADMIN" />);
const iconHolders = document.querySelectorAll('.cmd-item-icon');
@@ -194,7 +194,7 @@ describe('CmdKPalette', () => {
expect(screen.getByText(HOME_LABEL)).toBeInTheDocument();
});
test('closing the palette via handleInvoke sets open to false', async () => {
it('closing the palette via handleInvoke sets open to false', async () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
render(<CmdKPalette userRole="ADMIN" />);

View File

@@ -9,4 +9,5 @@ export enum FeatureKeys {
ANOMALY_DETECTION = 'anomaly_detection',
ONBOARDING_V3 = 'onboarding_v3',
DOT_METRICS_ENABLED = 'dot_metrics_enabled',
BODY_JSON_ENABLED = 'body_json_enabled',
}

View File

@@ -34,13 +34,13 @@ describe('Alert Channels Settings List page', () => {
jest.useRealTimers();
});
describe('Should display the Alert Channels page properly', () => {
it('Should check if "The alerts will be sent to all the configured channels." is visible ', () => {
it('Should check if "The alerts will be sent to all the configured channels." is visible', () => {
expect(screen.getByText('sending_channels_note')).toBeInTheDocument();
});
it('Should check if "New Alert Channel" Button is visble ', () => {
it('Should check if "New Alert Channel" Button is visble', () => {
expect(screen.getByText('button_new_channel')).toBeInTheDocument();
});
it('Should check if the help icon is visible and displays "tooltip_notification_channels ', async () => {
it('Should check if the help icon is visible and displays "tooltip_notification_channels', async () => {
const helpIcon = screen.getByLabelText('question-circle');
fireEvent.mouseOver(helpIcon);

View File

@@ -38,7 +38,7 @@ describe('Alert Channels Settings List page (Normal User)', () => {
jest.useRealTimers();
});
describe('Should display the Alert Channels page properly', () => {
it('Should check if "The alerts will be sent to all the configured channels." is visible ', async () => {
it('Should check if "The alerts will be sent to all the configured channels." is visible', async () => {
await waitFor(() =>
expect(screen.getByText('sending_channels_note')).toBeInTheDocument(),
);
@@ -51,7 +51,7 @@ describe('Alert Channels Settings List page (Normal User)', () => {
await waitFor(() => expect(newAlertButton).toBeInTheDocument());
expect(newAlertButton).toBeDisabled();
});
it('Should check if the help icon is visible and displays "tooltip_notification_channels ', async () => {
it('Should check if the help icon is visible and displays "tooltip_notification_channels', async () => {
const helpIcon = screen.getByLabelText('question-circle');
fireEvent.mouseOver(helpIcon);

View File

@@ -44,7 +44,7 @@ describe('Create Alert Channel', () => {
afterEach(() => {
jest.clearAllMocks();
});
describe('Should check if the new alert channel is properly displayed with the cascading fields of slack channel ', () => {
describe('Should check if the new alert channel is properly displayed with the cascading fields of slack channel', () => {
beforeEach(() => {
render(<CreateAlertChannels preType={ChannelType.Slack} />);
});
@@ -54,13 +54,13 @@ describe('Create Alert Channel', () => {
it('Should check if the title is "New Notification Channels"', () => {
expect(screen.getByText('page_title_create')).toBeInTheDocument();
});
it('Should check if the name label and textbox are displayed properly ', () => {
it('Should check if the name label and textbox are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_channel_name',
testId: 'channel-name-textbox',
});
});
it('Should check if Send resolved alerts label and checkbox are displayed properly ', () => {
it('Should check if Send resolved alerts label and checkbox are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_send_resolved',
testId: 'field-send-resolved-checkbox',
@@ -76,13 +76,13 @@ describe('Create Alert Channel', () => {
it('Should check if the selected item in the type dropdown has text "Slack"', () => {
expect(screen.getByText('Slack')).toBeInTheDocument();
});
it('Should check if Webhook URL label and input are displayed properly ', () => {
it('Should check if Webhook URL label and input are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_webhook_url',
testId: 'webhook-url-textbox',
});
});
it('Should check if Recepient label, input, and help text are displayed properly ', () => {
it('Should check if Recepient label, input, and help text are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_slack_recipient',
testId: 'slack-channel-textbox',
@@ -90,7 +90,7 @@ describe('Create Alert Channel', () => {
});
});
it('Should check if Title label and text area are displayed properly ', () => {
it('Should check if Title label and text area are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_slack_title',
testId: 'title-textarea',
@@ -101,7 +101,7 @@ describe('Create Alert Channel', () => {
expect(titleTextArea).toHaveTextContent(slackTitleDefaultValue);
});
it('Should check if Description label and text area are displayed properly ', () => {
it('Should check if Description label and text area are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_slack_description',
testId: 'description-textarea',
@@ -177,13 +177,13 @@ describe('Create Alert Channel', () => {
it('Should check if the selected item in the type dropdown has text "Webhook"', () => {
expect(screen.getByText('Webhook')).toBeInTheDocument();
});
it('Should check if Webhook URL label and input are displayed properly ', () => {
it('Should check if Webhook URL label and input are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_webhook_url',
testId: 'webhook-url-textbox',
});
});
it('Should check if Webhook User Name label, input, and help text are displayed properly ', () => {
it('Should check if Webhook User Name label, input, and help text are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_webhook_username',
testId: 'webhook-username-textbox',
@@ -321,7 +321,7 @@ describe('Create Alert Channel', () => {
});
});
it('Should check if Message contains the default template ', () => {
it('Should check if Message contains the default template', () => {
const messageTextArea = screen.getByTestId('opsgenie-message-textarea');
expect(messageTextArea).toHaveValue(opsGenieMessageDefaultValue);
@@ -387,14 +387,14 @@ describe('Create Alert Channel', () => {
expect(screen.getByText('Microsoft Teams')).toBeInTheDocument();
});
it('Should check if Webhook URL label and input are displayed properly ', () => {
it('Should check if Webhook URL label and input are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_webhook_url',
testId: 'webhook-url-textbox',
});
});
it('Should check if Title label and text area are displayed properly ', () => {
it('Should check if Title label and text area are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_slack_title',
testId: 'title-textarea',
@@ -406,7 +406,7 @@ describe('Create Alert Channel', () => {
expect(titleTextArea).toHaveTextContent(slackTitleDefaultValue);
});
it('Should check if Description label and text area are displayed properly ', () => {
it('Should check if Description label and text area are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_slack_description',
testId: 'description-textarea',

View File

@@ -23,20 +23,20 @@ describe('Create Alert Channel (Normal User)', () => {
afterEach(() => {
jest.clearAllMocks();
});
describe('Should check if the new alert channel is properly displayed with the cascading fields of slack channel ', () => {
describe('Should check if the new alert channel is properly displayed with the cascading fields of slack channel', () => {
beforeEach(() => {
render(<CreateAlertChannels preType={ChannelType.Slack} />);
});
it('Should check if the title is "New Notification Channels"', () => {
expect(screen.getByText('page_title_create')).toBeInTheDocument();
});
it('Should check if the name label and textbox are displayed properly ', () => {
it('Should check if the name label and textbox are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_channel_name',
testId: 'channel-name-textbox',
});
});
it('Should check if Send resolved alerts label and checkbox are displayed properly ', () => {
it('Should check if Send resolved alerts label and checkbox are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_send_resolved',
testId: 'field-send-resolved-checkbox',
@@ -52,13 +52,13 @@ describe('Create Alert Channel (Normal User)', () => {
it('Should check if the selected item in the type dropdown has text "Slack"', () => {
expect(screen.getByText('Slack')).toBeInTheDocument();
});
it('Should check if Webhook URL label and input are displayed properly ', () => {
it('Should check if Webhook URL label and input are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_webhook_url',
testId: 'webhook-url-textbox',
});
});
it('Should check if Recepient label, input, and help text are displayed properly ', () => {
it('Should check if Recepient label, input, and help text are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_slack_recipient',
testId: 'slack-channel-textbox',
@@ -66,7 +66,7 @@ describe('Create Alert Channel (Normal User)', () => {
});
});
it('Should check if Title label and text area are displayed properly ', () => {
it('Should check if Title label and text area are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_slack_title',
testId: 'title-textarea',
@@ -77,7 +77,7 @@ describe('Create Alert Channel (Normal User)', () => {
expect(titleTextArea).toHaveTextContent(slackTitleDefaultValue);
});
it('Should check if Description label and text area are displayed properly ', () => {
it('Should check if Description label and text area are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_slack_description',
testId: 'description-textarea',
@@ -103,13 +103,13 @@ describe('Create Alert Channel (Normal User)', () => {
it('Should check if the selected item in the type dropdown has text "Webhook"', () => {
expect(screen.getByText('Webhook')).toBeInTheDocument();
});
it('Should check if Webhook URL label and input are displayed properly ', () => {
it('Should check if Webhook URL label and input are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_webhook_url',
testId: 'webhook-url-textbox',
});
});
it('Should check if Webhook User Name label, input, and help text are displayed properly ', () => {
it('Should check if Webhook User Name label, input, and help text are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_webhook_username',
testId: 'webhook-username-textbox',
@@ -247,7 +247,7 @@ describe('Create Alert Channel (Normal User)', () => {
});
});
it('Should check if Message contains the default template ', () => {
it('Should check if Message contains the default template', () => {
const messageTextArea = screen.getByTestId('opsgenie-message-textarea');
expect(messageTextArea).toHaveValue(opsGenieMessageDefaultValue);

View File

@@ -24,7 +24,7 @@ jest.mock('components/MarkdownRenderer/MarkdownRenderer', () => ({
MarkdownRenderer: jest.fn(() => <div>Mocked MarkdownRenderer</div>),
}));
describe('Should check if the edit alert channel is properly displayed ', () => {
describe('Should check if the edit alert channel is properly displayed', () => {
beforeEach(() => {
render(<EditAlertChannels initialValue={editAlertChannelInitialValue} />);
});
@@ -35,14 +35,14 @@ describe('Should check if the edit alert channel is properly displayed ', () =>
expect(screen.getByText('page_title_edit')).toBeInTheDocument();
});
it('Should check if the name label and textbox are displayed properly ', () => {
it('Should check if the name label and textbox are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_channel_name',
testId: 'channel-name-textbox',
value: 'Dummy-Channel',
});
});
it('Should check if Send resolved alerts label and checkbox are displayed properly and the checkbox is checked ', () => {
it('Should check if Send resolved alerts label and checkbox are displayed properly and the checkbox is checked', () => {
testLabelInputAndHelpValue({
labelText: 'field_send_resolved',
testId: 'field-send-resolved-checkbox',
@@ -61,7 +61,7 @@ describe('Should check if the edit alert channel is properly displayed ', () =>
expect(screen.getByText('Slack')).toBeInTheDocument();
});
it('Should check if Webhook URL label and input are displayed properly ', () => {
it('Should check if Webhook URL label and input are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_webhook_url',
testId: 'webhook-url-textbox',
@@ -70,7 +70,7 @@ describe('Should check if the edit alert channel is properly displayed ', () =>
});
});
it('Should check if Recepient label, input, and help text are displayed properly ', () => {
it('Should check if Recepient label, input, and help text are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_slack_recipient',
testId: 'slack-channel-textbox',
@@ -79,7 +79,7 @@ describe('Should check if the edit alert channel is properly displayed ', () =>
});
});
it('Should check if Title label and text area are displayed properly ', () => {
it('Should check if Title label and text area are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_slack_title',
testId: 'title-textarea',
@@ -92,7 +92,7 @@ describe('Should check if the edit alert channel is properly displayed ', () =>
expect(titleTextArea).toHaveTextContent(slackTitleDefaultValue);
});
it('Should check if Description label and text area are displayed properly ', () => {
it('Should check if Description label and text area are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_slack_description',
testId: 'description-textarea',

View File

@@ -12,7 +12,7 @@ import {
} from './utils';
describe('Error utils', () => {
test('Valid OrderBy Params', () => {
it('Valid OrderBy Params', () => {
expect(isOrderParams('serviceName')).toBe(true);
expect(isOrderParams('exceptionCount')).toBe(true);
expect(isOrderParams('lastSeen')).toBe(true);
@@ -20,24 +20,24 @@ describe('Error utils', () => {
expect(isOrderParams('exceptionType')).toBe(true);
});
test('Invalid OrderBy Params', () => {
it('Invalid OrderBy Params', () => {
expect(isOrderParams('invalid')).toBe(false);
expect(isOrderParams(null)).toBe(false);
expect(isOrderParams('')).toBe(false);
});
test('Valid Order', () => {
it('Valid Order', () => {
expect(isOrder('ascending')).toBe(true);
expect(isOrder('descending')).toBe(true);
});
test('Invalid Order', () => {
it('Invalid Order', () => {
expect(isOrder('invalid')).toBe(false);
expect(isOrder(null)).toBe(false);
expect(isOrder('')).toBe(false);
});
test('Default Order', () => {
it('Default Order', () => {
const OrderBy: OrderBy[] = [
'exceptionCount',
'exceptionType',
@@ -57,7 +57,7 @@ describe('Error utils', () => {
});
});
test('Limit', () => {
it('Limit', () => {
expect(getLimit(null)).toBe(10);
expect(getLimit('')).toBe(10);
expect(getLimit('0')).toBe(0);
@@ -68,7 +68,7 @@ describe('Error utils', () => {
expect(getLimit('101')).toBe(101);
});
test('Update Page Size', () => {
it('Update Page Size', () => {
expect(getUpdatePageSize(null)).toBe(10);
expect(getUpdatePageSize('')).toBe(10);
expect(getUpdatePageSize('0')).toBe(0);
@@ -79,7 +79,7 @@ describe('Error utils', () => {
expect(getUpdatePageSize('101')).toBe(101);
});
test('Order Params', () => {
it('Order Params', () => {
expect(getOrderParams(null)).toBe('serviceName');
expect(getOrderParams('')).toBe('serviceName');
expect(getOrderParams('serviceName')).toBe('serviceName');
@@ -89,7 +89,7 @@ describe('Error utils', () => {
expect(getOrderParams('exceptionType')).toBe('exceptionType');
});
test('OffSet', () => {
it('OffSet', () => {
expect(getOffSet(null)).toBe(0);
expect(getOffSet('')).toBe(0);
expect(getOffSet('0')).toBe(0);
@@ -100,7 +100,7 @@ describe('Error utils', () => {
expect(getOffSet('101')).toBe(101);
});
test('Order', () => {
it('Order', () => {
expect(getOrder(null)).toBe('ascending');
expect(getOrder('')).toBe('ascending');
expect(getOrder('ascending')).toBe('ascending');

View File

@@ -30,18 +30,18 @@ function UplotChart({
useEffect(() => {
if (plotInstance.current) {
// @ts-ignore
// @ts-expect-error
plotInstance.current.destroy();
}
if (data && data.length > 0) {
// @ts-ignore
// @ts-expect-error
plotInstance.current = new uPlot(options, data, chartRef.current);
}
return (): void => {
if (plotInstance.current) {
// @ts-ignore
// @ts-expect-error
plotInstance.current.destroy();
}
};
@@ -275,7 +275,7 @@ function AnomalyAlertEvaluationView({
};
const handleSearchValueChange = useDebouncedFn((event): void => {
// @ts-ignore
// @ts-expect-error
const value = event?.target?.value || '';
handleSearch(value);

View File

@@ -233,7 +233,7 @@ describe('DomainMetrics - V5 Query Payload Tests', () => {
// Wait for skeletons to disappear
await waitFor(() => {
const skeletons = document.querySelectorAll('.ant-skeleton-button');
expect(skeletons.length).toBe(0);
expect(skeletons).toHaveLength(0);
});
// Verify all metric labels are displayed
@@ -272,7 +272,7 @@ describe('DomainMetrics - V5 Query Payload Tests', () => {
await waitFor(() => {
const skeletons = document.querySelectorAll('.ant-skeleton-button');
expect(skeletons.length).toBe(0);
expect(skeletons).toHaveLength(0);
});
// When no data, all values should show "-"

View File

@@ -303,7 +303,7 @@ describe('EndPointMetrics - V5 Query Payload Tests', () => {
// Wait for skeletons to disappear
await waitFor(() => {
const skeletons = document.querySelectorAll('.ant-skeleton-button');
expect(skeletons.length).toBe(0);
expect(skeletons).toHaveLength(0);
});
// Verify all metric labels are displayed
@@ -342,7 +342,7 @@ describe('EndPointMetrics - V5 Query Payload Tests', () => {
await waitFor(() => {
const skeletons = document.querySelectorAll('.ant-skeleton-button');
expect(skeletons.length).toBe(0);
expect(skeletons).toHaveLength(0);
});
// When no data, all values should show "-"

View File

@@ -303,7 +303,7 @@ describe('API Monitoring Utils', () => {
const result = extractPortAndEndpoint(url);
// Assert
expect(result).toEqual({
expect(result).toStrictEqual({
port: '8080',
endpoint: '/api/endpoint?param=value',
});
@@ -317,7 +317,7 @@ describe('API Monitoring Utils', () => {
const result = extractPortAndEndpoint(url);
// Assert
expect(result).toEqual({
expect(result).toStrictEqual({
port: '-',
endpoint: '/api/endpoint',
});
@@ -331,7 +331,7 @@ describe('API Monitoring Utils', () => {
const result = extractPortAndEndpoint(nonUrl);
// Assert
expect(result).toEqual({
expect(result).toStrictEqual({
port: '-',
endpoint: nonUrl,
});
@@ -379,7 +379,7 @@ describe('API Monitoring Utils', () => {
const result = getFormattedEndPointDropDownData([]);
// Assert
expect(result).toEqual([]);
expect(result).toStrictEqual([]);
});
it('should handle undefined input', () => {
@@ -392,7 +392,7 @@ describe('API Monitoring Utils', () => {
// Assert
// If the implementation doesn't handle undefined, just check that it returns something predictable
// Based on the error, it seems the function returns undefined for undefined input
expect(result).toEqual([]);
expect(result).toStrictEqual([]);
});
it('should handle items without URL path', () => {
@@ -460,7 +460,7 @@ describe('API Monitoring Utils', () => {
// Assert
expect(result).toBeDefined();
expect(result.length).toBe(2);
expect(result).toHaveLength(2);
// Check first item
expect(result[0].statusCode).toBe('200');
@@ -493,7 +493,7 @@ describe('API Monitoring Utils', () => {
// Assert
expect(result).toBeDefined();
expect(result.length).toBe(1);
expect(result).toHaveLength(1);
expect(result[0].statusCode).toBe('-');
expect(result[0].count).toBe('-');
expect(result[0].p99Latency).toBe('-');
@@ -506,7 +506,7 @@ describe('API Monitoring Utils', () => {
// Assert
expect(result).toBeDefined();
expect(result).toEqual([]);
expect(result).toStrictEqual([]);
});
it('should handle undefined input', () => {
@@ -518,7 +518,7 @@ describe('API Monitoring Utils', () => {
// Assert
expect(result).toBeDefined();
expect(result).toEqual([]);
expect(result).toStrictEqual([]);
});
it('should handle mixed status code formats and preserve order', () => {
@@ -555,7 +555,7 @@ describe('API Monitoring Utils', () => {
// Assert
expect(result).toBeDefined();
expect(result.length).toBe(3);
expect(result).toHaveLength(3);
// Check order preservation - should maintain the same order as input
expect(result[0].statusCode).toBe('404');
@@ -675,7 +675,7 @@ describe('API Monitoring Utils', () => {
// Assert
expect(result).toBeDefined();
expect(result.data.result).toEqual([]);
expect(result.data.result).toStrictEqual([]);
});
it('should handle empty result array', () => {
@@ -695,7 +695,7 @@ describe('API Monitoring Utils', () => {
// Assert
expect(result).toBeDefined();
expect(result.data.result).toEqual([]);
expect(result.data.result).toStrictEqual([]);
});
});
@@ -779,7 +779,7 @@ describe('API Monitoring Utils', () => {
// Assert
expect(result).toBeDefined();
expect(result.length).toBe(2);
expect(result).toHaveLength(2);
// Should have two filters, one for >= start code and one for <= end code
const startRangeFilter = result.find((item) => item.op === '>=');
@@ -811,7 +811,7 @@ describe('API Monitoring Utils', () => {
// Assert
expect(result).toBeDefined();
expect(result.length).toBe(2);
expect(result).toHaveLength(2);
const startRangeFilter = result.find((item) => item.op === '>=');
const endRangeFilter = result.find((item) => item.op === '<=');
@@ -832,7 +832,7 @@ describe('API Monitoring Utils', () => {
// Assert
expect(result).toBeDefined();
expect(result).toEqual([]);
expect(result).toStrictEqual([]);
});
it('should handle empty metric object', () => {
@@ -841,7 +841,7 @@ describe('API Monitoring Utils', () => {
// Assert
expect(result).toBeDefined();
expect(result).toEqual([]);
expect(result).toStrictEqual([]);
});
it('should handle metric without response_status_code', () => {
@@ -855,7 +855,7 @@ describe('API Monitoring Utils', () => {
// Assert
expect(result).toBeDefined();
expect(result).toEqual([]);
expect(result).toStrictEqual([]);
});
it('should handle unsupported status code range', () => {
@@ -869,7 +869,7 @@ describe('API Monitoring Utils', () => {
// Assert
expect(result).toBeDefined();
expect(result.length).toBe(2);
expect(result).toHaveLength(2);
// Should still have two filters
const startRangeFilter = result.find((item) => item.op === '>=');

View File

@@ -61,25 +61,29 @@ describe('AllEndpointsWidget - V5 Migration Validation', () => {
// Query A: count()
expect(queryA.aggregations).toBeDefined();
expect(Array.isArray(queryA.aggregations)).toBe(true);
expect(queryA.aggregations).toEqual([{ expression: 'count()' }]);
expect(queryA.aggregations).toStrictEqual([{ expression: 'count()' }]);
expect(queryA).not.toHaveProperty('aggregateAttribute');
// Query B: p99(duration_nano)
expect(queryB.aggregations).toBeDefined();
expect(Array.isArray(queryB.aggregations)).toBe(true);
expect(queryB.aggregations).toEqual([{ expression: 'p99(duration_nano)' }]);
expect(queryB.aggregations).toStrictEqual([
{ expression: 'p99(duration_nano)' },
]);
expect(queryB).not.toHaveProperty('aggregateAttribute');
// Query C: max(timestamp)
expect(queryC.aggregations).toBeDefined();
expect(Array.isArray(queryC.aggregations)).toBe(true);
expect(queryC.aggregations).toEqual([{ expression: 'max(timestamp)' }]);
expect(queryC.aggregations).toStrictEqual([
{ expression: 'max(timestamp)' },
]);
expect(queryC).not.toHaveProperty('aggregateAttribute');
// Query D: count() (disabled, for errors)
expect(queryD.aggregations).toBeDefined();
expect(Array.isArray(queryD.aggregations)).toBe(true);
expect(queryD.aggregations).toEqual([{ expression: 'count()' }]);
expect(queryD.aggregations).toStrictEqual([{ expression: 'count()' }]);
expect(queryD).not.toHaveProperty('aggregateAttribute');
});

View File

@@ -60,7 +60,7 @@ describe('EndpointDropdown - V5 Migration Validation', () => {
// V5 Aggregation format: aggregations array (not aggregateAttribute)
expect(queryA.aggregations).toBeDefined();
expect(Array.isArray(queryA.aggregations)).toBe(true);
expect(queryA.aggregations?.[0]).toEqual({
expect(queryA.aggregations?.[0]).toStrictEqual({
expression: 'count()',
});
expect(queryA).not.toHaveProperty('aggregateAttribute');

View File

@@ -19,7 +19,7 @@ describe('API Monitoring Query Params', () => {
describe('getApiMonitoringParams', () => {
it('returns default params when no query param exists', () => {
const search = '';
expect(getApiMonitoringParams(search)).toEqual(DEFAULT_PARAMS);
expect(getApiMonitoringParams(search)).toStrictEqual(DEFAULT_PARAMS);
});
it('parses URL query params correctly', () => {
@@ -52,7 +52,7 @@ describe('API Monitoring Query Params', () => {
urlParams.set('apiMonitoringParams', 'invalid-json');
const search = `?${urlParams.toString()}`;
expect(getApiMonitoringParams(search)).toEqual(DEFAULT_PARAMS);
expect(getApiMonitoringParams(search)).toStrictEqual(DEFAULT_PARAMS);
});
});

View File

@@ -20,7 +20,7 @@ window.ResizeObserver =
describe('BillingContainer', () => {
jest.setTimeout(30000);
test('Component should render', async () => {
it('Component should render', async () => {
render(<BillingContainer />);
const dataInjection = screen.getByRole('columnheader', {
@@ -61,7 +61,7 @@ describe('BillingContainer', () => {
jest.useRealTimers();
});
test('OnTrail', async () => {
it('OnTrail', async () => {
// Pin "now" so trial end (20 Oct 2023) is tomorrow => "1 days_remaining"
render(
@@ -73,17 +73,19 @@ describe('BillingContainer', () => {
// If the component schedules any setTimeout on mount, flush them:
jest.runOnlyPendingTimers();
expect(await screen.findByText('Free Trial')).toBeInTheDocument();
expect(await screen.findByText('billing')).toBeInTheDocument();
expect(await screen.findByText(/\$0/i)).toBeInTheDocument();
await expect(screen.findByText('Free Trial')).resolves.toBeInTheDocument();
await expect(screen.findByText('billing')).resolves.toBeInTheDocument();
await expect(screen.findByText(/\$0/i)).resolves.toBeInTheDocument();
expect(
await screen.findByText(
await expect(
screen.findByText(
/You are in free trial period. Your free trial will end on 20 Oct 2023/i,
),
).toBeInTheDocument();
).resolves.toBeInTheDocument();
expect(await screen.findByText(/1 days_remaining/i)).toBeInTheDocument();
await expect(
screen.findByText(/1 days_remaining/i),
).resolves.toBeInTheDocument();
const upgradeButtons = await screen.findAllByRole('button', {
name: /upgrade_plan/i,
@@ -91,13 +93,15 @@ describe('BillingContainer', () => {
expect(upgradeButtons).toHaveLength(2);
expect(upgradeButtons[1]).toBeInTheDocument();
expect(await screen.findByText(/checkout_plans/i)).toBeInTheDocument();
expect(
await screen.findByRole('link', { name: /here/i }),
).toBeInTheDocument();
await expect(
screen.findByText(/checkout_plans/i),
).resolves.toBeInTheDocument();
await expect(
screen.findByRole('link', { name: /here/i }),
).resolves.toBeInTheDocument();
});
test('OnTrail but trialConvertedToSubscription', async () => {
it('OnTrail but trialConvertedToSubscription', async () => {
await act(async () => {
render(
<BillingContainer />,
@@ -137,7 +141,7 @@ describe('BillingContainer', () => {
});
});
test('Not on ontrail', async () => {
it('Not on ontrail', async () => {
const { findByText } = render(
<BillingContainer />,
{},

View File

@@ -242,7 +242,7 @@ describe('utils', () => {
);
expect(rrulestr).toHaveBeenCalledWith(FREQ_DAILY);
expect(result).toEqual([
expect(result).toStrictEqual([
new Date(MOCK_DATE_STRING),
new Date('2024-01-16T10:30:00Z'),
new Date('2024-01-17T10:30:00Z'),
@@ -300,7 +300,7 @@ describe('utils', () => {
expect(result).toBeDefined();
expect(Array.isArray(result)).toBe(true);
expect(result?.map((res) => formatDate(res))).toEqual([
expect(result?.map((res) => formatDate(res))).toStrictEqual([
'15-01-2024 10:30:00',
'01-02-2024 10:30:00',
'15-02-2024 10:30:00',
@@ -319,7 +319,7 @@ describe('utils', () => {
expect(result).toBeDefined();
expect(Array.isArray(result)).toBe(true);
expect(result?.map((res) => formatDate(res))).toEqual([
expect(result?.map((res) => formatDate(res))).toStrictEqual([
'15-01-2024 12:30:00',
'19-01-2024 12:30:00',
'22-01-2024 12:30:00',
@@ -339,7 +339,7 @@ describe('utils', () => {
expect(result).toBeDefined();
expect(Array.isArray(result)).toBe(true);
// today included (15-01-2024 00:30:00)
expect(result?.map((res) => formatDate(res))).toEqual([
expect(result?.map((res) => formatDate(res))).toStrictEqual([
'15-01-2024 10:30:00',
'19-01-2024 10:30:00',
'22-01-2024 10:30:00',
@@ -359,7 +359,7 @@ describe('utils', () => {
expect(result).toBeDefined();
expect(Array.isArray(result)).toBe(true);
// today excluded (15-01-2024 00:30:00)
expect(result?.map((res) => formatDate(res))).toEqual([
expect(result?.map((res) => formatDate(res))).toStrictEqual([
'19-01-2024 00:00:00',
'22-01-2024 00:00:00',
'26-01-2024 00:00:00',
@@ -379,7 +379,7 @@ describe('utils', () => {
expect(result).toBeDefined();
expect(Array.isArray(result)).toBe(true);
// today excluded (15-01-2024 00:30:00)
expect(result?.map((res) => formatDate(res))).toEqual([
expect(result?.map((res) => formatDate(res))).toStrictEqual([
'19-01-2024 00:30:00',
'22-01-2024 00:30:00',
'26-01-2024 00:30:00',
@@ -398,7 +398,7 @@ describe('utils', () => {
expect(result).toBeDefined();
expect(Array.isArray(result)).toBe(true);
// today included (15-01-2024 10:30:00)
expect(result?.map((res) => formatDate(res))).toEqual([
expect(result?.map((res) => formatDate(res))).toStrictEqual([
'15-01-2024 10:30:00',
'15-02-2024 10:30:00',
'15-03-2024 10:30:00',
@@ -417,7 +417,7 @@ describe('utils', () => {
expect(result).toBeDefined();
expect(Array.isArray(result)).toBe(true);
// today excluded (15-01-2024 10:30:00)
expect(result?.map((res) => formatDate(res))).toEqual([
expect(result?.map((res) => formatDate(res))).toStrictEqual([
'15-02-2024 00:00:00',
'15-03-2024 00:00:00',
'15-04-2024 00:00:00',
@@ -436,7 +436,7 @@ describe('utils', () => {
expect(result).toBeDefined();
expect(Array.isArray(result)).toBe(true);
// today excluded (15-01-2024 10:30:00)
expect(result?.map((res) => formatDate(res))).toEqual([
expect(result?.map((res) => formatDate(res))).toStrictEqual([
'15-02-2024 00:30:00',
'15-03-2024 00:30:00',
'15-04-2024 00:30:00',
@@ -455,7 +455,7 @@ describe('utils', () => {
expect(result).toBeDefined();
expect(Array.isArray(result)).toBe(true);
expect(result?.map((res) => formatDate(res))).toEqual([
expect(result?.map((res) => formatDate(res))).toStrictEqual([
'29-01-2024 10:30:00',
'29-02-2024 10:30:00',
'29-03-2024 10:30:00',
@@ -474,7 +474,7 @@ describe('utils', () => {
expect(result).toBeDefined();
expect(Array.isArray(result)).toBe(true);
expect(result?.map((res) => formatDate(res))).toEqual([
expect(result?.map((res) => formatDate(res))).toStrictEqual([
'31-01-2024 10:30:00',
'31-03-2024 10:30:00',
'31-05-2024 10:30:00',
@@ -511,7 +511,7 @@ describe('utils', () => {
5,
);
expect(result?.map((res) => formatDate(res))).toEqual([
expect(result?.map((res) => formatDate(res))).toStrictEqual([
'29-01-2023 10:30:00',
'29-03-2023 10:30:00',
'29-04-2023 10:30:00',
@@ -529,7 +529,7 @@ describe('utils', () => {
);
expect(result).toBeDefined();
expect(Array.isArray(result)).toBe(true);
expect(result?.map((res) => formatDate(res))).toEqual([
expect(result?.map((res) => formatDate(res))).toStrictEqual([
'15-01-2024 10:40:00',
'16-01-2024 10:40:00',
'17-01-2024 10:40:00',
@@ -547,7 +547,7 @@ describe('utils', () => {
);
expect(result).toBeDefined();
expect(Array.isArray(result)).toBe(true);
expect(result?.map((res) => formatDate(res))).toEqual([
expect(result?.map((res) => formatDate(res))).toStrictEqual([
'16-01-2024 00:00:00',
'17-01-2024 00:00:00',
'18-01-2024 00:00:00',
@@ -565,7 +565,7 @@ describe('utils', () => {
);
expect(result).toBeDefined();
expect(Array.isArray(result)).toBe(true);
expect(result?.map((res) => formatDate(res))).toEqual([
expect(result?.map((res) => formatDate(res))).toStrictEqual([
'16-01-2024 00:30:00',
'17-01-2024 00:30:00',
'18-01-2024 00:30:00',
@@ -583,7 +583,7 @@ describe('utils', () => {
);
expect(result).toBeDefined();
expect(Array.isArray(result)).toBe(true);
expect(result?.map((res) => formatDate(res))).toEqual([
expect(result?.map((res) => formatDate(res))).toStrictEqual([
'15-01-2024 10:30:00',
'16-01-2024 10:30:00',
'17-01-2024 10:30:00',
@@ -621,7 +621,7 @@ describe('utils', () => {
);
expect(result).toBeDefined();
expect(Array.isArray(result)).toBe(true);
expect(result?.map((res) => formatDate(res))).toEqual([
expect(result?.map((res) => formatDate(res))).toStrictEqual([
'31-01-2024 10:30:00',
'01-02-2024 10:30:00',
'02-02-2024 10:30:00',

View File

@@ -333,7 +333,7 @@ describe('QuerySection', () => {
const result = mockUseQueryBuilder.redirectWithQueryBuilderData.mock.calls[0];
expect(result[0]).toEqual({
expect(result[0]).toStrictEqual({
id: MOCK_UUID,
queryType: EQueryType.QUERY_BUILDER,
unit: undefined,
@@ -351,7 +351,7 @@ describe('QuerySection', () => {
clickhouse_sql: [initialClickHouseData],
});
expect(result[1]).toEqual({
expect(result[1]).toStrictEqual({
[QueryParams.alertType]: AlertTypes.METRICS_BASED_ALERT,
[QueryParams.ruleType]: AlertDetectionTypes.THRESHOLD_ALERT,
});
@@ -371,7 +371,7 @@ describe('QuerySection', () => {
const [queryArg] =
mockUseQueryBuilder.redirectWithQueryBuilderData.mock.calls[0];
expect(queryArg).toEqual({
expect(queryArg).toStrictEqual({
...mockUseQueryBuilder.currentQuery,
queryType: EQueryType.PROM,
});
@@ -425,7 +425,7 @@ describe('QuerySection', () => {
const [queryArg] =
mockUseQueryBuilder.redirectWithQueryBuilderData.mock.calls[0];
expect(queryArg).toEqual({
expect(queryArg).toStrictEqual({
...mockCurrentQueryWithPromQL,
queryType: EQueryType.QUERY_BUILDER,
});
@@ -479,7 +479,7 @@ describe('QuerySection', () => {
const [queryArg] =
mockUseQueryBuilder.redirectWithQueryBuilderData.mock.calls[0];
expect(queryArg).toEqual({
expect(queryArg).toStrictEqual({
...mockCurrentQueryWithClickhouseSQL,
queryType: EQueryType.QUERY_BUILDER,
});

View File

@@ -54,7 +54,7 @@ describe('CreateAlertV2 Context Utils', () => {
type: 'SET_ALERT_NAME',
payload: 'Test Alert',
});
expect(result).toEqual({
expect(result).toStrictEqual({
...INITIAL_ALERT_STATE,
name: 'Test Alert',
});
@@ -66,7 +66,7 @@ describe('CreateAlertV2 Context Utils', () => {
type: 'SET_ALERT_LABELS',
payload: labels,
});
expect(result).toEqual({
expect(result).toStrictEqual({
...INITIAL_ALERT_STATE,
labels,
});
@@ -77,7 +77,7 @@ describe('CreateAlertV2 Context Utils', () => {
type: 'SET_Y_AXIS_UNIT',
payload: 'ms',
});
expect(result).toEqual({
expect(result).toStrictEqual({
...INITIAL_ALERT_STATE,
yAxisUnit: 'ms',
});
@@ -90,7 +90,7 @@ describe('CreateAlertV2 Context Utils', () => {
yAxisUnit: 'ms',
};
const result = alertCreationReducer(modifiedState, { type: 'RESET' });
expect(result).toEqual(INITIAL_ALERT_STATE);
expect(result).toStrictEqual(INITIAL_ALERT_STATE);
});
it(TEST_SET_INITIAL_STATE_FROM_PAYLOAD, () => {
@@ -103,7 +103,7 @@ describe('CreateAlertV2 Context Utils', () => {
type: 'SET_INITIAL_STATE',
payload: newState,
});
expect(result).toEqual(newState);
expect(result).toStrictEqual(newState);
});
it(TEST_RETURN_STATE_FOR_UNKNOWN_ACTION, () => {
@@ -112,7 +112,7 @@ describe('CreateAlertV2 Context Utils', () => {
{ type: UNKNOWN_ACTION_TYPE } as any,
);
expect(result).toEqual(INITIAL_ALERT_STATE);
expect(result).toStrictEqual(INITIAL_ALERT_STATE);
});
});
@@ -211,7 +211,7 @@ describe('CreateAlertV2 Context Utils', () => {
type: 'SET_SELECTED_QUERY',
payload: 'B',
});
expect(result).toEqual({
expect(result).toStrictEqual({
...INITIAL_ALERT_THRESHOLD_STATE,
selectedQuery: 'B',
});
@@ -222,7 +222,7 @@ describe('CreateAlertV2 Context Utils', () => {
type: 'SET_OPERATOR',
payload: AlertThresholdOperator.IS_BELOW,
});
expect(result).toEqual({
expect(result).toStrictEqual({
...INITIAL_ALERT_THRESHOLD_STATE,
operator: AlertThresholdOperator.IS_BELOW,
});
@@ -233,7 +233,7 @@ describe('CreateAlertV2 Context Utils', () => {
type: 'SET_MATCH_TYPE',
payload: AlertThresholdMatchType.ALL_THE_TIME,
});
expect(result).toEqual({
expect(result).toStrictEqual({
...INITIAL_ALERT_THRESHOLD_STATE,
matchType: AlertThresholdMatchType.ALL_THE_TIME,
});
@@ -255,7 +255,7 @@ describe('CreateAlertV2 Context Utils', () => {
type: 'SET_THRESHOLDS',
payload: newThresholds,
});
expect(result).toEqual({
expect(result).toStrictEqual({
...INITIAL_ALERT_THRESHOLD_STATE,
thresholds: newThresholds,
});
@@ -272,7 +272,7 @@ describe('CreateAlertV2 Context Utils', () => {
thresholds: [],
};
const result = alertThresholdReducer(modifiedState, { type: 'RESET' });
expect(result).toEqual(INITIAL_ALERT_THRESHOLD_STATE);
expect(result).toStrictEqual(INITIAL_ALERT_THRESHOLD_STATE);
});
it(TEST_SET_INITIAL_STATE_FROM_PAYLOAD, () => {
@@ -289,7 +289,7 @@ describe('CreateAlertV2 Context Utils', () => {
type: 'SET_INITIAL_STATE',
payload: newState,
});
expect(result).toEqual(newState);
expect(result).toStrictEqual(newState);
});
it(TEST_RETURN_STATE_FOR_UNKNOWN_ACTION, () => {
@@ -298,7 +298,7 @@ describe('CreateAlertV2 Context Utils', () => {
{ type: UNKNOWN_ACTION_TYPE } as any,
);
expect(result).toEqual(INITIAL_ALERT_THRESHOLD_STATE);
expect(result).toStrictEqual(INITIAL_ALERT_THRESHOLD_STATE);
});
});
@@ -308,7 +308,7 @@ describe('CreateAlertV2 Context Utils', () => {
type: 'SET_SEND_NOTIFICATION_IF_DATA_IS_MISSING',
payload: { toleranceLimit: 21, timeUnit: UniversalYAxisUnit.HOURS },
});
expect(result).toEqual({
expect(result).toStrictEqual({
...INITIAL_ADVANCED_OPTIONS_STATE,
sendNotificationIfDataIsMissing: {
...INITIAL_ADVANCED_OPTIONS_STATE.sendNotificationIfDataIsMissing,
@@ -323,7 +323,7 @@ describe('CreateAlertV2 Context Utils', () => {
type: 'TOGGLE_SEND_NOTIFICATION_IF_DATA_IS_MISSING',
payload: true,
});
expect(result).toEqual({
expect(result).toStrictEqual({
...INITIAL_ADVANCED_OPTIONS_STATE,
sendNotificationIfDataIsMissing: {
...INITIAL_ADVANCED_OPTIONS_STATE.sendNotificationIfDataIsMissing,
@@ -337,7 +337,7 @@ describe('CreateAlertV2 Context Utils', () => {
type: 'SET_ENFORCE_MINIMUM_DATAPOINTS',
payload: { minimumDatapoints: 10 },
});
expect(result).toEqual({
expect(result).toStrictEqual({
...INITIAL_ADVANCED_OPTIONS_STATE,
enforceMinimumDatapoints: {
...INITIAL_ADVANCED_OPTIONS_STATE.enforceMinimumDatapoints,
@@ -351,7 +351,7 @@ describe('CreateAlertV2 Context Utils', () => {
type: 'TOGGLE_ENFORCE_MINIMUM_DATAPOINTS',
payload: true,
});
expect(result).toEqual({
expect(result).toStrictEqual({
...INITIAL_ADVANCED_OPTIONS_STATE,
enforceMinimumDatapoints: {
...INITIAL_ADVANCED_OPTIONS_STATE.enforceMinimumDatapoints,
@@ -365,7 +365,7 @@ describe('CreateAlertV2 Context Utils', () => {
type: 'SET_DELAY_EVALUATION',
payload: { delay: 10, timeUnit: UniversalYAxisUnit.HOURS },
});
expect(result).toEqual({
expect(result).toStrictEqual({
...INITIAL_ADVANCED_OPTIONS_STATE,
delayEvaluation: { delay: 10, timeUnit: UniversalYAxisUnit.HOURS },
});
@@ -386,7 +386,7 @@ describe('CreateAlertV2 Context Utils', () => {
type: 'SET_EVALUATION_CADENCE',
payload: newCadence,
});
expect(result).toEqual({
expect(result).toStrictEqual({
...INITIAL_ADVANCED_OPTIONS_STATE,
evaluationCadence: {
...INITIAL_ADVANCED_OPTIONS_STATE.evaluationCadence,
@@ -400,7 +400,7 @@ describe('CreateAlertV2 Context Utils', () => {
type: 'SET_EVALUATION_CADENCE_MODE',
payload: 'custom',
});
expect(result).toEqual({
expect(result).toStrictEqual({
...INITIAL_ADVANCED_OPTIONS_STATE,
evaluationCadence: {
...INITIAL_ADVANCED_OPTIONS_STATE.evaluationCadence,
@@ -415,7 +415,7 @@ describe('CreateAlertV2 Context Utils', () => {
delayEvaluation: { delay: 10, timeUnit: UniversalYAxisUnit.HOURS },
};
const result = advancedOptionsReducer(modifiedState, { type: 'RESET' });
expect(result).toEqual(INITIAL_ADVANCED_OPTIONS_STATE);
expect(result).toStrictEqual(INITIAL_ADVANCED_OPTIONS_STATE);
});
it(TEST_SET_INITIAL_STATE_FROM_PAYLOAD, () => {
@@ -431,7 +431,7 @@ describe('CreateAlertV2 Context Utils', () => {
type: 'SET_INITIAL_STATE',
payload: newState,
});
expect(result).toEqual(newState);
expect(result).toStrictEqual(newState);
});
it(TEST_RETURN_STATE_FOR_UNKNOWN_ACTION, () => {
@@ -440,7 +440,7 @@ describe('CreateAlertV2 Context Utils', () => {
{ type: UNKNOWN_ACTION_TYPE } as any,
);
expect(result).toEqual(INITIAL_ADVANCED_OPTIONS_STATE);
expect(result).toStrictEqual(INITIAL_ADVANCED_OPTIONS_STATE);
});
});
@@ -455,7 +455,7 @@ describe('CreateAlertV2 Context Utils', () => {
type: 'SET_WINDOW_TYPE',
payload: 'rolling',
});
expect(result).toEqual({
expect(result).toStrictEqual({
windowType: 'rolling',
timeframe: INITIAL_EVALUATION_WINDOW_STATE.timeframe,
startingAt: INITIAL_EVALUATION_WINDOW_STATE.startingAt,
@@ -467,7 +467,7 @@ describe('CreateAlertV2 Context Utils', () => {
type: 'SET_WINDOW_TYPE',
payload: 'cumulative',
});
expect(result).toEqual({
expect(result).toStrictEqual({
windowType: 'cumulative',
timeframe: 'currentHour',
startingAt: INITIAL_EVALUATION_WINDOW_STATE.startingAt,
@@ -479,7 +479,7 @@ describe('CreateAlertV2 Context Utils', () => {
type: 'SET_TIMEFRAME',
payload: '10m0s',
});
expect(result).toEqual({
expect(result).toStrictEqual({
...INITIAL_EVALUATION_WINDOW_STATE,
timeframe: '10m0s',
});
@@ -496,7 +496,7 @@ describe('CreateAlertV2 Context Utils', () => {
type: 'SET_STARTING_AT',
payload: newStartingAt,
});
expect(result).toEqual({
expect(result).toStrictEqual({
...INITIAL_EVALUATION_WINDOW_STATE,
startingAt: newStartingAt,
});
@@ -514,7 +514,7 @@ describe('CreateAlertV2 Context Utils', () => {
},
};
const result = evaluationWindowReducer(modifiedState, { type: 'RESET' });
expect(result).toEqual(INITIAL_EVALUATION_WINDOW_STATE);
expect(result).toStrictEqual(INITIAL_EVALUATION_WINDOW_STATE);
});
it(TEST_SET_INITIAL_STATE_FROM_PAYLOAD, () => {
@@ -532,7 +532,7 @@ describe('CreateAlertV2 Context Utils', () => {
type: 'SET_INITIAL_STATE',
payload: newState,
});
expect(result).toEqual(newState);
expect(result).toStrictEqual(newState);
});
it(TEST_RETURN_STATE_FOR_UNKNOWN_ACTION, () => {
@@ -541,7 +541,7 @@ describe('CreateAlertV2 Context Utils', () => {
{ type: UNKNOWN_ACTION_TYPE } as any,
);
expect(result).toEqual(INITIAL_EVALUATION_WINDOW_STATE);
expect(result).toStrictEqual(INITIAL_EVALUATION_WINDOW_STATE);
});
});
@@ -555,7 +555,7 @@ describe('CreateAlertV2 Context Utils', () => {
payload: notifications,
},
);
expect(result).toEqual({
expect(result).toStrictEqual({
...INITIAL_NOTIFICATION_SETTINGS_STATE,
multipleNotifications: notifications,
});
@@ -570,7 +570,7 @@ describe('CreateAlertV2 Context Utils', () => {
type: 'SET_MULTIPLE_NOTIFICATIONS',
payload: null,
});
expect(result).toEqual({
expect(result).toStrictEqual({
...modifiedState,
multipleNotifications: null,
});
@@ -590,7 +590,7 @@ describe('CreateAlertV2 Context Utils', () => {
payload: reNotification,
},
);
expect(result).toEqual({
expect(result).toStrictEqual({
...INITIAL_NOTIFICATION_SETTINGS_STATE,
reNotification,
});
@@ -605,7 +605,7 @@ describe('CreateAlertV2 Context Utils', () => {
payload: description,
},
);
expect(result).toEqual({
expect(result).toStrictEqual({
...INITIAL_NOTIFICATION_SETTINGS_STATE,
description,
});
@@ -619,7 +619,7 @@ describe('CreateAlertV2 Context Utils', () => {
payload: true,
},
);
expect(result).toEqual({
expect(result).toStrictEqual({
...INITIAL_NOTIFICATION_SETTINGS_STATE,
routingPolicies: true,
});
@@ -640,7 +640,7 @@ describe('CreateAlertV2 Context Utils', () => {
const result = notificationSettingsReducer(modifiedState, {
type: 'RESET',
});
expect(result).toEqual(INITIAL_NOTIFICATION_SETTINGS_STATE);
expect(result).toStrictEqual(INITIAL_NOTIFICATION_SETTINGS_STATE);
});
it(TEST_SET_INITIAL_STATE_FROM_PAYLOAD, () => {
@@ -662,7 +662,7 @@ describe('CreateAlertV2 Context Utils', () => {
payload: newState,
},
);
expect(result).toEqual(newState);
expect(result).toStrictEqual(newState);
});
it(TEST_RETURN_STATE_FOR_UNKNOWN_ACTION, () => {
@@ -671,7 +671,7 @@ describe('CreateAlertV2 Context Utils', () => {
{ type: UNKNOWN_ACTION_TYPE } as any,
);
expect(result).toEqual(INITIAL_NOTIFICATION_SETTINGS_STATE);
expect(result).toStrictEqual(INITIAL_NOTIFICATION_SETTINGS_STATE);
});
});
});

View File

@@ -113,7 +113,7 @@ describe('CustomDomainSettings', () => {
await user.click(screen.getByRole('button', { name: /apply changes/i }));
await waitFor(() => {
expect(capturedBody).toEqual({ name: 'myteam' });
expect(capturedBody).toStrictEqual({ name: 'myteam' });
});
});
@@ -143,9 +143,9 @@ describe('CustomDomainSettings', () => {
await user.type(input, 'myteam');
await user.click(screen.getByRole('button', { name: /apply changes/i }));
expect(
await screen.findByRole('button', { name: /contact support/i }),
).toBeInTheDocument();
await expect(
screen.findByRole('button', { name: /contact support/i }),
).resolves.toBeInTheDocument();
});
it('shows validation error when subdomain is less than 3 characters', async () => {
@@ -255,7 +255,7 @@ describe('CustomDomainSettings', () => {
},
});
expect(await screen.findByText('My Org Name')).toBeInTheDocument();
await expect(screen.findByText('My Org Name')).resolves.toBeInTheDocument();
});
it('falls back to customDomainSubdomain when org displayName is missing', async () => {
@@ -269,7 +269,7 @@ describe('CustomDomainSettings', () => {
appContextOverrides: { org: [] },
});
expect(await screen.findByText('custom-host')).toBeInTheDocument();
await expect(screen.findByText('custom-host')).resolves.toBeInTheDocument();
});
it('falls back to activeHost.name when neither org name nor custom domain exists', async () => {
@@ -294,7 +294,9 @@ describe('CustomDomainSettings', () => {
});
// 'accepted-starfish' is the default host's name
expect(await screen.findByText('accepted-starfish')).toBeInTheDocument();
await expect(
screen.findByText('accepted-starfish'),
).resolves.toBeInTheDocument();
});
it('does not render the card name row if workspaceName is totally falsy', async () => {

View File

@@ -155,7 +155,7 @@ describe('VariableItem Component', () => {
jest.clearAllMocks();
});
test('renders without crashing', () => {
it('renders without crashing', () => {
renderVariableItem();
expect(screen.getByText(TEXT.ALL_VARIABLES)).toBeInTheDocument();
@@ -165,7 +165,7 @@ describe('VariableItem Component', () => {
});
describe('Variable Name Validation', () => {
test('shows error when variable name already exists', () => {
it('shows error when variable name already exists', () => {
// Set validateName to return false (name exists)
const mockValidateName = jest.fn().mockReturnValue(false);
@@ -181,7 +181,7 @@ describe('VariableItem Component', () => {
// We won't check for button disabled state as it might be inconsistent in tests
});
test('allows save when current variable name is used', () => {
it('allows save when current variable name is used', () => {
// Mock validate to return false for all other names but true for own name
const mockValidateName = jest
.fn()
@@ -197,7 +197,7 @@ describe('VariableItem Component', () => {
expect(screen.queryByText(TEXT.VARIABLE_EXISTS)).not.toBeInTheDocument();
});
test('shows error when variable name contains whitespace', () => {
it('shows error when variable name contains whitespace', () => {
renderVariableItem({ ...basicVariableData, name: '' });
// Enter a name with whitespace
@@ -212,7 +212,7 @@ describe('VariableItem Component', () => {
expect(saveButton).toBeDisabled();
});
test('allows variable name without whitespace', () => {
it('allows variable name without whitespace', () => {
renderVariableItem({ ...basicVariableData, name: '' });
// Enter a valid name without whitespace
@@ -223,7 +223,7 @@ describe('VariableItem Component', () => {
expect(screen.queryByText(TEXT.VARIABLE_WHITESPACE)).not.toBeInTheDocument();
});
test('validates whitespace in auto-generated name for dynamic variables', () => {
it('validates whitespace in auto-generated name for dynamic variables', () => {
// Create a dynamic variable with empty name
const dynamicVariable: IDashboardVariable = {
...basicVariableData,
@@ -241,7 +241,7 @@ describe('VariableItem Component', () => {
});
describe('Dynamic Variable Attribute Key Validation', () => {
test('shows error when attribute key already exists', async () => {
it('shows error when attribute key already exists', async () => {
// Mock validateAttributeKey to return false (attribute key exists)
const mockValidateAttributeKey = jest.fn().mockReturnValue(false);
@@ -277,7 +277,7 @@ describe('VariableItem Component', () => {
expect(saveButton).toBeDisabled();
});
test('allows saving when attribute key is unique', async () => {
it('allows saving when attribute key is unique', async () => {
// Mock validateAttributeKey to return true (attribute key is unique)
const mockValidateAttributeKey = jest.fn().mockReturnValue(true);
@@ -315,7 +315,7 @@ describe('VariableItem Component', () => {
expect(saveButton).not.toBeDisabled();
});
test('allows same attribute key for current variable being edited', async () => {
it('allows same attribute key for current variable being edited', async () => {
// Mock validateAttributeKey to return true for same variable
const mockValidateAttributeKey = jest.fn().mockImplementation(
(attributeKey, currentVariableId) =>
@@ -348,7 +348,7 @@ describe('VariableItem Component', () => {
});
});
test('does not validate attribute key for non-dynamic variables', async () => {
it('does not validate attribute key for non-dynamic variables', async () => {
// Mock validateAttributeKey to return false (would show error for dynamic)
const mockValidateAttributeKey = jest.fn().mockReturnValue(false);
@@ -377,7 +377,7 @@ describe('VariableItem Component', () => {
});
describe('Variable Type Switching', () => {
test('switches to CUSTOM variable type correctly', () => {
it('switches to CUSTOM variable type correctly', () => {
renderVariableItem();
// Find the Query button
@@ -401,7 +401,7 @@ describe('VariableItem Component', () => {
expect(screen.getByText(TEXT.OPTIONS)).toBeInTheDocument();
});
test('switches to TEXTBOX variable type correctly', () => {
it('switches to TEXTBOX variable type correctly', () => {
renderVariableItem();
// Find and click Textbox button
@@ -424,7 +424,7 @@ describe('VariableItem Component', () => {
});
describe('MultiSelect and ALL Option', () => {
test('enables ALL option only when multiSelect is enabled', async () => {
it('enables ALL option only when multiSelect is enabled', async () => {
renderVariableItem();
// Initially, ALL option should not be visible
@@ -457,7 +457,7 @@ describe('VariableItem Component', () => {
});
});
test('disables ALL option when multiSelect is disabled', async () => {
it('disables ALL option when multiSelect is disabled', async () => {
// Create variable with multiSelect and showALLOption both enabled
const variable: IDashboardVariable = {
...basicVariableData,
@@ -501,7 +501,7 @@ describe('VariableItem Component', () => {
});
describe('Cancel and Navigation', () => {
test('calls onCancel when clicking All Variables button', () => {
it('calls onCancel when clicking All Variables button', () => {
renderVariableItem();
// Click All variables button
@@ -511,7 +511,7 @@ describe('VariableItem Component', () => {
expect(onCancel).toHaveBeenCalledTimes(1);
});
test('calls onCancel when clicking Discard button', () => {
it('calls onCancel when clicking Discard button', () => {
renderVariableItem();
// Click Discard button
@@ -550,7 +550,7 @@ describe('VariableItem Component', () => {
};
// Test for cyclic dependency detection
test('detects circular dependency and shows error message', async () => {
it('detects circular dependency and shows error message', async () => {
// Create variables with circular dependency
const variable1 = createVariable(
TEST_VAR_IDS.VAR1,
@@ -577,7 +577,7 @@ describe('VariableItem Component', () => {
});
// Test for saving with no circular dependency
test('allows saving when no circular dependency exists', async () => {
it('allows saving when no circular dependency exists', async () => {
// Create variables without circular dependency
const variable1 = createVariable(
TEST_VAR_IDS.VAR1,
@@ -608,7 +608,7 @@ describe('VariableItem Component', () => {
});
// Test with multiple variable formats in query
test('detects circular dependency with different variable formats', async () => {
it('detects circular dependency with different variable formats', async () => {
// Create variables with circular dependency using different formats
const variable1 = createVariable(
TEST_VAR_IDS.VAR1,
@@ -645,7 +645,7 @@ describe('VariableItem Component', () => {
});
describe('Textbox Variable Default Value Handling', () => {
test('saves textbox variable with defaultValue and selectedValue set to textboxValue', async () => {
it('saves textbox variable with defaultValue and selectedValue set to textboxValue', async () => {
const user = userEvent.setup();
const textboxVariable: IDashboardVariable = {
id: TEST_VAR_IDS.VAR1,
@@ -676,7 +676,7 @@ describe('VariableItem Component', () => {
);
});
test('saves textbox variable with empty values when textboxValue is empty', async () => {
it('saves textbox variable with empty values when textboxValue is empty', async () => {
const user = userEvent.setup();
const textboxVariable: IDashboardVariable = {
id: TEST_VAR_IDS.VAR1,
@@ -707,7 +707,7 @@ describe('VariableItem Component', () => {
);
});
test('updates textbox defaultValue and selectedValue when user changes textboxValue input', async () => {
it('updates textbox defaultValue and selectedValue when user changes textboxValue input', async () => {
const user = userEvent.setup();
const textboxVariable: IDashboardVariable = {
id: TEST_VAR_IDS.VAR1,
@@ -745,7 +745,7 @@ describe('VariableItem Component', () => {
);
});
test('non-textbox variables use variableDefaultValue instead of textboxValue', async () => {
it('non-textbox variables use variableDefaultValue instead of textboxValue', async () => {
const user = userEvent.setup();
const queryVariable: IDashboardVariable = {
id: TEST_VAR_IDS.VAR1,
@@ -780,7 +780,7 @@ describe('VariableItem Component', () => {
expect(savedVariable.defaultValue).not.toBe('should-not-be-used');
});
test('switching to textbox type sets defaultValue and selectedValue correctly on save', async () => {
it('switching to textbox type sets defaultValue and selectedValue correctly on save', async () => {
const user = userEvent.setup();
// Start with a QUERY variable
const queryVariable: IDashboardVariable = {

View File

@@ -38,7 +38,7 @@ function TableRow({ children, ...props }: RowProps): JSX.Element {
transition,
isDragging,
} = useSortable({
// @ts-ignore
// @ts-expect-error
id: props['data-row-key'],
});
@@ -148,7 +148,7 @@ function VariablesSettings({
});
if (name) {
// @ts-ignore
// @ts-expect-error
variableNamesMap[name] = name;
}
@@ -391,7 +391,7 @@ function VariablesSettings({
const variableName = updatedVariables[index].name;
if (variableName) {
// @ts-ignore
// @ts-expect-error
reArrangedVariables[variableName] = {
...updatedVariables[index],
order: index,

View File

@@ -109,11 +109,13 @@ describe('PublicDashboardSetting', () => {
).toBeInTheDocument();
});
expect(
await screen.findByRole('checkbox', { name: /enable time range/i }),
).toBeInTheDocument();
await expect(
screen.findByRole('checkbox', { name: /enable time range/i }),
).resolves.toBeInTheDocument();
expect(await screen.findByText(/default time range/i)).toBeInTheDocument();
await expect(
screen.findByText(/default time range/i),
).resolves.toBeInTheDocument();
expect(screen.getByText(/Last 30 minutes/i)).toBeInTheDocument();
@@ -123,9 +125,9 @@ describe('PublicDashboardSetting', () => {
).toBeInTheDocument();
});
expect(
await screen.findByRole('button', { name: /publish dashboard/i }),
).toBeInTheDocument();
await expect(
screen.findByRole('button', { name: /publish dashboard/i }),
).resolves.toBeInTheDocument();
});
});
@@ -149,9 +151,9 @@ describe('PublicDashboardSetting', () => {
).toBeInTheDocument();
});
expect(
await screen.findByRole('checkbox', { name: /enable time range/i }),
).toBeChecked();
await expect(
screen.findByRole('checkbox', { name: /enable time range/i }),
).resolves.toBeChecked();
await waitFor(() => {
expect(screen.getByText(/default time range/i)).toBeInTheDocument();
@@ -163,13 +165,13 @@ describe('PublicDashboardSetting', () => {
expect(screen.getByText(/Public Dashboard URL/i)).toBeInTheDocument();
});
expect(
await screen.findByRole('button', { name: /update published dashboard/i }),
).toBeInTheDocument();
await expect(
screen.findByRole('button', { name: /update published dashboard/i }),
).resolves.toBeInTheDocument();
expect(
await screen.findByRole('button', { name: /unpublish dashboard/i }),
).toBeInTheDocument();
await expect(
screen.findByRole('button', { name: /unpublish dashboard/i }),
).resolves.toBeInTheDocument();
});
});
@@ -249,7 +251,7 @@ describe('PublicDashboardSetting', () => {
rest.post(publicDashboardURL, async (req, res, ctx) => {
const body = await req.json();
createApiCalled = true;
expect(body).toEqual({
expect(body).toStrictEqual({
timeRangeEnabled: true,
defaultTimeRange: DEFAULT_TIME_RANGE,
});
@@ -318,7 +320,7 @@ describe('PublicDashboardSetting', () => {
await waitFor(() => {
expect(updateApiCalled).toBe(true);
expect(capturedRequestBody).toEqual({
expect(capturedRequestBody).toStrictEqual({
timeRangeEnabled: true,
defaultTimeRange: DEFAULT_TIME_RANGE,
});

View File

@@ -40,7 +40,7 @@ describe('VariableItem', () => {
useEffectSpy.mockRestore();
});
test('renders component with default props', () => {
it('renders component with default props', () => {
render(
<MockQueryClientProvider>
<VariableItem
@@ -54,7 +54,7 @@ describe('VariableItem', () => {
expect(screen.getByText('$testVariable')).toBeInTheDocument();
});
test('renders Input when the variable type is TEXTBOX', () => {
it('renders Input when the variable type is TEXTBOX', () => {
render(
<MockQueryClientProvider>
<VariableItem
@@ -69,7 +69,7 @@ describe('VariableItem', () => {
).toBeInTheDocument();
});
test('calls onValueUpdate when Input value changes and blurs', async () => {
it('calls onValueUpdate when Input value changes and blurs', async () => {
render(
<MockQueryClientProvider>
<VariableItem
@@ -102,7 +102,7 @@ describe('VariableItem', () => {
});
});
test('renders a Select element when variable type is CUSTOM', () => {
it('renders a Select element when variable type is CUSTOM', () => {
render(
<MockQueryClientProvider>
<VariableItem
@@ -117,7 +117,7 @@ describe('VariableItem', () => {
expect(screen.getByTestId('variable-select')).toBeInTheDocument();
});
test('renders a Select element with all selected', async () => {
it('renders a Select element with all selected', async () => {
const customVariableData = {
...mockCustomVariableData,
allSelected: true,
@@ -138,7 +138,7 @@ describe('VariableItem', () => {
expect(screen.getByText('ALL')).toBeInTheDocument();
});
test('calls useEffect when the component mounts', () => {
it('calls useEffect when the component mounts', () => {
render(
<MockQueryClientProvider>
<VariableItem

View File

@@ -272,7 +272,7 @@ describe('DashboardVariableSelection', () => {
);
});
expect(callOrder).toEqual([
expect(callOrder).toStrictEqual([
'updateDashboardVariablesStore',
'enqueueDescendantsOfVariable',
]);

View File

@@ -32,7 +32,7 @@ describe('VariableItem Default Value Selection Behavior', () => {
});
describe('Single Select Variables', () => {
test('should keep previous selection value', async () => {
it('should keep previous selection value', async () => {
const variable: IDashboardVariable = {
id: TEST_VARIABLE_ID,
name: TEST_VARIABLE_NAME,
@@ -51,10 +51,10 @@ describe('VariableItem Default Value Selection Behavior', () => {
expect(screen.getByTestId(VARIABLE_SELECT_TESTID)).toBeInTheDocument();
});
expect(await screen.findByText('option1')).toBeInTheDocument();
await expect(screen.findByText('option1')).resolves.toBeInTheDocument();
});
test('should auto-select first option when no previous and no default', async () => {
it('should auto-select first option when no previous and no default', async () => {
const variable: IDashboardVariable = {
id: TEST_VARIABLE_ID,
name: TEST_VARIABLE_NAME,
@@ -74,12 +74,12 @@ describe('VariableItem Default Value Selection Behavior', () => {
});
// With the new variable select strategy, the first option is auto-selected
expect(await screen.findByText('option1')).toBeInTheDocument();
await expect(screen.findByText('option1')).resolves.toBeInTheDocument();
});
});
describe('Multi Select Variables with ALL enabled', () => {
test('should show ALL when all options are selected', async () => {
it('should show ALL when all options are selected', async () => {
const variable: IDashboardVariable = {
id: TEST_VARIABLE_ID,
name: TEST_VARIABLE_NAME,
@@ -99,12 +99,12 @@ describe('VariableItem Default Value Selection Behavior', () => {
expect(screen.getByTestId(VARIABLE_SELECT_TESTID)).toBeInTheDocument();
});
expect(await screen.findByText('ALL')).toBeInTheDocument();
await expect(screen.findByText('ALL')).resolves.toBeInTheDocument();
});
});
describe('Multi Select Variables with ALL disabled', () => {
test('should show placeholder when no selection', async () => {
it('should show placeholder when no selection', async () => {
const variable: IDashboardVariable = {
id: TEST_VARIABLE_ID,
name: TEST_VARIABLE_NAME,
@@ -123,7 +123,7 @@ describe('VariableItem Default Value Selection Behavior', () => {
expect(screen.getByTestId(VARIABLE_SELECT_TESTID)).toBeInTheDocument();
});
expect(await screen.findByText('Select value')).toBeInTheDocument();
await expect(screen.findByText('Select value')).resolves.toBeInTheDocument();
});
});
});

View File

@@ -47,7 +47,7 @@ describe('dashboardVariables - utilities and processors', () => {
},
];
test.each(testCases)(
it.each(testCases)(
'should update variable node when $scenario',
({ nodeToUpdate, expected }) => {
const updatedVariables: string[] = [];
@@ -57,7 +57,7 @@ describe('dashboardVariables - utilities and processors', () => {
onUpdateVariableNode(nodeToUpdate, graph, topologicalOrder, callback);
expect(updatedVariables).toEqual(expected);
expect(updatedVariables).toStrictEqual(expected);
},
);
@@ -66,7 +66,7 @@ describe('dashboardVariables - utilities and processors', () => {
onUpdateVariableNode('http_status_code', graph, [], (node) =>
updatedVariables.push(node),
);
expect(updatedVariables).toEqual([]);
expect(updatedVariables).toStrictEqual([]);
});
});
@@ -87,11 +87,11 @@ describe('dashboardVariables - utilities and processors', () => {
environment: [],
};
expect(buildParentDependencyGraph(graph)).toEqual(expected);
expect(buildParentDependencyGraph(graph)).toStrictEqual(expected);
});
it('should handle empty graph', () => {
expect(buildParentDependencyGraph({})).toEqual({});
expect(buildParentDependencyGraph({})).toStrictEqual({});
});
});
@@ -142,13 +142,13 @@ describe('dashboardVariables - utilities and processors', () => {
},
};
expect(buildDependencyGraph(graph)).toEqual(expected);
expect(buildDependencyGraph(graph)).toStrictEqual(expected);
});
it('should return empty transitiveDescendants for an empty graph', () => {
const result = buildDependencyGraph({});
expect(result.transitiveDescendants).toEqual({});
expect(result.order).toEqual([]);
expect(result.transitiveDescendants).toStrictEqual({});
expect(result.order).toStrictEqual([]);
expect(result.hasCycle).toBe(false);
});
@@ -159,7 +159,7 @@ describe('dashboardVariables - utilities and processors', () => {
c: [],
};
const result = buildDependencyGraph(linearGraph);
expect(result.transitiveDescendants).toEqual({
expect(result.transitiveDescendants).toStrictEqual({
a: ['b', 'c'],
b: ['c'],
c: [],
@@ -174,13 +174,13 @@ describe('dashboardVariables - utilities and processors', () => {
d: [],
};
const result = buildDependencyGraph(diamondGraph);
expect(result.transitiveDescendants.a).toEqual(
expect(result.transitiveDescendants.a).toStrictEqual(
expect.arrayContaining(['b', 'c', 'd']),
);
expect(result.transitiveDescendants.a).toHaveLength(3);
expect(result.transitiveDescendants.b).toEqual(['d']);
expect(result.transitiveDescendants.c).toEqual(['d']);
expect(result.transitiveDescendants.d).toEqual([]);
expect(result.transitiveDescendants.b).toStrictEqual(['d']);
expect(result.transitiveDescendants.c).toStrictEqual(['d']);
expect(result.transitiveDescendants.d).toStrictEqual([]);
});
it('should handle disconnected components in transitiveDescendants', () => {
@@ -191,10 +191,10 @@ describe('dashboardVariables - utilities and processors', () => {
y: [],
};
const result = buildDependencyGraph(disconnectedGraph);
expect(result.transitiveDescendants.a).toEqual(['b']);
expect(result.transitiveDescendants.b).toEqual([]);
expect(result.transitiveDescendants.x).toEqual(['y']);
expect(result.transitiveDescendants.y).toEqual([]);
expect(result.transitiveDescendants.a).toStrictEqual(['b']);
expect(result.transitiveDescendants.b).toStrictEqual([]);
expect(result.transitiveDescendants.x).toStrictEqual(['y']);
expect(result.transitiveDescendants.y).toStrictEqual([]);
});
it('should return empty transitiveDescendants for all leaf nodes', () => {
@@ -204,7 +204,7 @@ describe('dashboardVariables - utilities and processors', () => {
c: [],
};
const result = buildDependencyGraph(leafOnlyGraph);
expect(result.transitiveDescendants).toEqual({
expect(result.transitiveDescendants).toStrictEqual({
a: [],
b: [],
c: [],
@@ -225,11 +225,11 @@ describe('dashboardVariables - utilities and processors', () => {
environment: [],
};
expect(buildDependencies(variables)).toEqual(expected);
expect(buildDependencies(variables)).toStrictEqual(expected);
});
it('should handle empty variables array', () => {
expect(buildDependencies([])).toEqual({});
expect(buildDependencies([])).toStrictEqual({});
});
});
});

View File

@@ -36,7 +36,7 @@ export const convertVariablesToDbFormat = (
variblesArr.reduce((result, obj: IDashboardVariable) => {
const { id } = obj;
// @ts-ignore
// @ts-expect-error
result[id] = obj;
return result;
}, {});

View File

@@ -81,7 +81,7 @@ describe('onUpdateVariableNode', () => {
onUpdateVariableNode('deployment', graph, topologicalOrder, callback);
expect(visited).toEqual(['deployment', 'namespace', 'service', 'pod']);
expect(visited).toStrictEqual(['deployment', 'namespace', 'service', 'pod']);
});
it('should call callback starting from a middle node', () => {
@@ -92,7 +92,7 @@ describe('onUpdateVariableNode', () => {
onUpdateVariableNode('namespace', graph, topologicalOrder, callback);
expect(visited).toEqual(['namespace', 'service', 'pod']);
expect(visited).toStrictEqual(['namespace', 'service', 'pod']);
});
it('should only call callback for the leaf node when updating leaf', () => {
@@ -103,7 +103,7 @@ describe('onUpdateVariableNode', () => {
onUpdateVariableNode('pod', graph, topologicalOrder, callback);
expect(visited).toEqual(['pod']);
expect(visited).toStrictEqual(['pod']);
});
it('should handle CUSTOM variable not in topologicalOrder by updating its children', () => {
@@ -116,7 +116,7 @@ describe('onUpdateVariableNode', () => {
onUpdateVariableNode('customVar', graph, topologicalOrder, callback);
// Should process namespace and its descendants (service, pod)
expect(visited).toEqual(['namespace', 'service', 'pod']);
expect(visited).toStrictEqual(['namespace', 'service', 'pod']);
});
it('should handle node not in graph gracefully', () => {
@@ -128,7 +128,7 @@ describe('onUpdateVariableNode', () => {
onUpdateVariableNode('unknownNode', graph, topologicalOrder, callback);
// Should not call callback for any node since unknownNode has no children
expect(visited).toEqual([]);
expect(visited).toStrictEqual([]);
});
it('should handle empty graph', () => {
@@ -140,7 +140,7 @@ describe('onUpdateVariableNode', () => {
onUpdateVariableNode('deployment', {}, topologicalOrder, callback);
// deployment is in topologicalOrder, so callback is called for it
expect(visited).toEqual(['deployment']);
expect(visited).toStrictEqual(['deployment']);
});
it('should handle empty topologicalOrder', () => {
@@ -151,7 +151,7 @@ describe('onUpdateVariableNode', () => {
onUpdateVariableNode('deployment', graph, [], callback);
expect(visited).toEqual([]);
expect(visited).toStrictEqual([]);
});
it('should handle CUSTOM variable with multiple children', () => {
@@ -173,7 +173,7 @@ describe('onUpdateVariableNode', () => {
);
// Should process namespace, service, and pod (descendants)
expect(visited).toEqual(['namespace', 'service', 'pod']);
expect(visited).toStrictEqual(['namespace', 'service', 'pod']);
});
});
@@ -200,11 +200,15 @@ function makeDynamicVar(
describe('mergeUniqueStrings', () => {
it('should merge two arrays and deduplicate', () => {
expect(mergeUniqueStrings(['a', 'b'], ['b', 'c'])).toEqual(['a', 'b', 'c']);
expect(mergeUniqueStrings(['a', 'b'], ['b', 'c'])).toStrictEqual([
'a',
'b',
'c',
]);
});
it('should convert numbers and booleans to strings', () => {
expect(mergeUniqueStrings([1, true, 'hello'], [2, false])).toEqual([
expect(mergeUniqueStrings([1, true, 'hello'], [2, false])).toStrictEqual([
'1',
'true',
'hello',
@@ -214,15 +218,15 @@ describe('mergeUniqueStrings', () => {
});
it('should deduplicate when number and its string form both appear', () => {
expect(mergeUniqueStrings([42], ['42'])).toEqual(['42']);
expect(mergeUniqueStrings([42], ['42'])).toStrictEqual(['42']);
});
it('should handle a single array', () => {
expect(mergeUniqueStrings(['x', 'y', 'x'])).toEqual(['x', 'y']);
expect(mergeUniqueStrings(['x', 'y', 'x'])).toStrictEqual(['x', 'y']);
});
it('should handle three or more arrays', () => {
expect(mergeUniqueStrings(['a'], ['b'], ['c'], ['a', 'c'])).toEqual([
expect(mergeUniqueStrings(['a'], ['b'], ['c'], ['a', 'c'])).toStrictEqual([
'a',
'b',
'c',
@@ -230,15 +234,19 @@ describe('mergeUniqueStrings', () => {
});
it('should return empty array when no arrays are provided', () => {
expect(mergeUniqueStrings()).toEqual([]);
expect(mergeUniqueStrings()).toStrictEqual([]);
});
it('should return empty array when all input arrays are empty', () => {
expect(mergeUniqueStrings([], [], [])).toEqual([]);
expect(mergeUniqueStrings([], [], [])).toStrictEqual([]);
});
it('should preserve order of first occurrence', () => {
expect(mergeUniqueStrings(['c', 'a'], ['b', 'a'])).toEqual(['c', 'a', 'b']);
expect(mergeUniqueStrings(['c', 'a'], ['b', 'a'])).toStrictEqual([
'c',
'a',
'b',
]);
});
});

View File

@@ -424,7 +424,7 @@ describe('Panel Management Tests', () => {
);
// Should return dashboard unchanged
expect(updatedDashboard).toEqual(dashboard);
expect(updatedDashboard).toStrictEqual(dashboard);
});
it('should handle undefined dashboard gracefully', () => {

View File

@@ -33,6 +33,7 @@ export default function ChartWrapper({
children,
layoutChildren,
yAxisUnit,
groupBy,
customTooltip,
pinnedTooltipElement,
'data-testid': testId,
@@ -68,8 +69,9 @@ export default function ChartWrapper({
const syncMetadata = useMemo(
() => ({
yAxisUnit,
groupBy,
}),
[yAxisUnit],
[yAxisUnit, groupBy],
);
return (

View File

@@ -6,6 +6,7 @@ import {
DashboardCursorSync,
TooltipClickData,
} from 'lib/uPlotV2/plugins/TooltipPlugin/types';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
interface BaseChartProps {
width: number;
@@ -38,6 +39,7 @@ interface UPlotBasedChartProps {
interface UPlotChartDataProps {
yAxisUnit?: string;
decimalPrecision?: PrecisionOption;
groupBy?: BaseAutocompleteData[];
}
export interface TimeSeriesChartProps

View File

@@ -13,7 +13,7 @@ describe('stackUtils', () => {
[4, 5, 6],
];
const { data: result } = stack(data, neverOmit);
expect(result[0]).toEqual([100, 200, 300]);
expect(result[0]).toStrictEqual([100, 200, 300]);
});
it('stacks value series cumulatively (last = raw, first = total)', () => {
@@ -26,9 +26,9 @@ describe('stackUtils', () => {
];
const { data: result } = stack(data, neverOmit);
// result[1] = s1+s2+s3, result[2] = s2+s3, result[3] = s3
expect(result[1]).toEqual([12, 15, 18]); // 1+4+7, 2+5+8, 3+6+9
expect(result[2]).toEqual([11, 13, 15]); // 4+7, 5+8, 6+9
expect(result[3]).toEqual([7, 8, 9]);
expect(result[1]).toStrictEqual([12, 15, 18]); // 1+4+7, 2+5+8, 3+6+9
expect(result[2]).toStrictEqual([11, 13, 15]); // 4+7, 5+8, 6+9
expect(result[3]).toStrictEqual([7, 8, 9]);
});
it('treats null values as 0 when stacking', () => {
@@ -38,8 +38,8 @@ describe('stackUtils', () => {
[null, 10],
];
const { data: result } = stack(data, neverOmit);
expect(result[1]).toEqual([1, 10]); // total
expect(result[2]).toEqual([0, 10]); // last series with null→0
expect(result[1]).toStrictEqual([1, 10]); // total
expect(result[2]).toStrictEqual([0, 10]); // last series with null→0
});
it('copies omitted series as-is without accumulating', () => {
@@ -53,9 +53,9 @@ describe('stackUtils', () => {
const omitSeries2 = (i: number): boolean => i === 2;
const { data: result } = stack(data, omitSeries2);
// series 3 raw: [1, 2]; series 2 omitted: [100, 200] as-is; series 1 stacked with s3: [11, 22]
expect(result[1]).toEqual([11, 22]); // 10+1, 20+2
expect(result[2]).toEqual([100, 200]); // copied, not stacked
expect(result[3]).toEqual([1, 2]);
expect(result[1]).toStrictEqual([11, 22]); // 10+1, 20+2
expect(result[2]).toStrictEqual([100, 200]); // copied, not stacked
expect(result[3]).toStrictEqual([1, 2]);
});
it('returns bands between consecutive visible series when none omitted', () => {
@@ -66,7 +66,7 @@ describe('stackUtils', () => {
[5, 6],
];
const { bands } = stack(data, neverOmit);
expect(bands).toEqual([{ series: [1, 2] }, { series: [2, 3] }]);
expect(bands).toStrictEqual([{ series: [1, 2] }, { series: [2, 3] }]);
});
it('returns bands only between visible series when some are omitted', () => {
@@ -74,7 +74,7 @@ describe('stackUtils', () => {
const data: AlignedData = [[0], [1], [2], [3], [4]];
const omitSeries2 = (i: number): boolean => i === 2;
const { bands } = stack(data, omitSeries2);
expect(bands).toEqual([{ series: [1, 3] }, { series: [3, 4] }]);
expect(bands).toStrictEqual([{ series: [1, 3] }, { series: [3, 4] }]);
});
it('returns empty bands when only one value series', () => {
@@ -83,30 +83,30 @@ describe('stackUtils', () => {
[1, 2],
];
const { bands } = stack(data, neverOmit);
expect(bands).toEqual([]);
expect(bands).toStrictEqual([]);
});
});
describe('getInitialStackedBands', () => {
it('returns one band between each consecutive pair for seriesCount 3', () => {
expect(getInitialStackedBands(3)).toEqual([
expect(getInitialStackedBands(3)).toStrictEqual([
{ series: [1, 2] },
{ series: [2, 3] },
]);
});
it('returns empty array for seriesCount 0 or 1', () => {
expect(getInitialStackedBands(0)).toEqual([]);
expect(getInitialStackedBands(1)).toEqual([]);
expect(getInitialStackedBands(0)).toStrictEqual([]);
expect(getInitialStackedBands(1)).toStrictEqual([]);
});
it('returns single band for seriesCount 2', () => {
expect(getInitialStackedBands(2)).toEqual([{ series: [1, 2] }]);
expect(getInitialStackedBands(2)).toStrictEqual([{ series: [1, 2] }]);
});
it('returns bands [1,2], [2,3], ..., [n-1, n] for seriesCount n', () => {
const bands = getInitialStackedBands(5);
expect(bands).toEqual([
expect(bands).toStrictEqual([
{ series: [1, 2] },
{ series: [2, 3] },
{ series: [3, 4] },

View File

@@ -119,9 +119,9 @@ describe('useBarChartStacking', () => {
}),
);
// Still returns stacked data (computed in useMemo); no hooks registered
expect(result.current[0]).toEqual([0, 1]);
expect(result.current[1]).toEqual([5, 7]); // stacked
expect(result.current[2]).toEqual([4, 5]);
expect(result.current[0]).toStrictEqual([0, 1]);
expect(result.current[1]).toStrictEqual([5, 7]); // stacked
expect(result.current[2]).toStrictEqual([4, 5]);
});
it('returns stacked data when isStackedBarChart is true and multiple value series', () => {
@@ -138,10 +138,10 @@ describe('useBarChartStacking', () => {
config: null,
}),
);
expect(result.current[0]).toEqual([0, 1, 2]);
expect(result.current[1]).toEqual([12, 15, 18]); // s1+s2+s3
expect(result.current[2]).toEqual([11, 13, 15]); // s2+s3
expect(result.current[3]).toEqual([7, 8, 9]);
expect(result.current[0]).toStrictEqual([0, 1, 2]);
expect(result.current[1]).toStrictEqual([12, 15, 18]); // s1+s2+s3
expect(result.current[2]).toStrictEqual([11, 13, 15]); // s2+s3
expect(result.current[3]).toStrictEqual([7, 8, 9]);
});
it('returns data as-is when only one value series (no stacking needed)', () => {
@@ -156,7 +156,7 @@ describe('useBarChartStacking', () => {
config: null,
}),
);
expect(result.current).toEqual(data);
expect(result.current).toStrictEqual(data);
});
it('registers setData and setSeries hooks when isStackedBarChart and config provided', () => {

View File

@@ -113,6 +113,10 @@ function BarPanel(props: PanelWrapperProps): JSX.Element {
uPlotRef.current = plot;
}, []);
const groupBy = useMemo(() => {
return widget.query.builder.queryData[0].groupBy;
}, [widget.query]);
return (
<div className="panel-container" ref={graphRef}>
{containerDimensions.width > 0 && containerDimensions.height > 0 && (
@@ -128,6 +132,7 @@ function BarPanel(props: PanelWrapperProps): JSX.Element {
width={containerDimensions.width}
height={containerDimensions.height}
layoutChildren={layoutChildren}
groupBy={groupBy}
isStackedBarChart={widget.stackedBarChart ?? false}
yAxisUnit={widget.yAxisUnit}
decimalPrecision={widget.decimalPrecision}

View File

@@ -105,6 +105,7 @@ export function prepareBarPanelConfig({
colorMapping: widget.customLegendColors ?? {},
isDarkMode,
stepInterval: currentStepInterval,
metric: series.metric,
});
});

View File

@@ -104,6 +104,10 @@ function TimeSeriesPanel(props: PanelWrapperProps): JSX.Element {
widget.decimalPrecision,
]);
const groupBy = useMemo(() => {
return widget.query.builder.queryData[0].groupBy;
}, [widget.query]);
return (
<div className="panel-container" ref={graphRef}>
{containerDimensions.width > 0 && containerDimensions.height > 0 && (
@@ -117,6 +121,7 @@ function TimeSeriesPanel(props: PanelWrapperProps): JSX.Element {
yAxisUnit={widget.yAxisUnit}
decimalPrecision={widget.decimalPrecision}
data={chartData as uPlot.AlignedData}
groupBy={groupBy}
width={containerDimensions.width}
height={containerDimensions.height}
layoutChildren={layoutChildren}

View File

@@ -83,7 +83,7 @@ describe('TimeSeriesPanel utils', () => {
const data = prepareChartData(apiResponse);
expect(data).toHaveLength(1);
expect(data[0]).toEqual([]);
expect(data[0]).toStrictEqual([]);
});
it('returns timestamps and one series of y values for single series', () => {
@@ -102,8 +102,8 @@ describe('TimeSeriesPanel utils', () => {
const data = prepareChartData(apiResponse);
expect(data).toHaveLength(2);
expect(data[0]).toEqual([1000, 2000]);
expect(data[1]).toEqual([10, 20]);
expect(data[0]).toStrictEqual([1000, 2000]);
expect(data[1]).toStrictEqual([10, 20]);
});
it('merges timestamps and fills missing values with null for multiple series', () => {
@@ -128,11 +128,11 @@ describe('TimeSeriesPanel utils', () => {
const data = prepareChartData(apiResponse);
expect(data[0]).toEqual([1000, 2000, 3000]);
expect(data[0]).toStrictEqual([1000, 2000, 3000]);
// First series: 1, null, 3
expect(data[1]).toEqual([1, null, 3]);
expect(data[1]).toStrictEqual([1, null, 3]);
// Second series: 10, 20, null
expect(data[2]).toEqual([10, 20, null]);
expect(data[2]).toStrictEqual([10, 20, null]);
});
});

View File

@@ -131,6 +131,7 @@ export const prepareUPlotConfig = ({
pointSize: 5,
fillMode: widget.fillMode || FillMode.None,
isDarkMode,
metric: series.metric,
});
});

View File

@@ -62,7 +62,7 @@ describe('legendVisibilityUtils', () => {
const result = getStoredSeriesVisibility('widget-1');
expect(result).not.toBeNull();
expect(result).toEqual([
expect(result).toStrictEqual([
{ label: 'CPU', show: true },
{ label: 'Memory', show: false },
]);
@@ -85,7 +85,7 @@ describe('legendVisibilityUtils', () => {
const result = getStoredSeriesVisibility('widget-1');
expect(result).not.toBeNull();
expect(result).toEqual([
expect(result).toStrictEqual([
{ label: 'CPU', show: true },
{ label: 'CPU', show: false },
{ label: 'Memory', show: false },
@@ -128,7 +128,7 @@ describe('legendVisibilityUtils', () => {
const stored = getStoredSeriesVisibility('widget-1');
expect(stored).not.toBeNull();
expect(stored).toEqual([
expect(stored).toStrictEqual([
{ label: 'CPU', show: true },
{ label: 'Memory', show: false },
]);
@@ -150,7 +150,7 @@ describe('legendVisibilityUtils', () => {
const stored = getStoredSeriesVisibility('widget-new');
expect(stored).not.toBeNull();
expect(stored).toEqual([{ label: 'CPU', show: false }]);
expect(stored).toStrictEqual([{ label: 'CPU', show: false }]);
});
it('updates existing widget visibility when entry already exists', () => {
@@ -176,7 +176,7 @@ describe('legendVisibilityUtils', () => {
const stored = getStoredSeriesVisibility('widget-1');
expect(stored).not.toBeNull();
expect(stored).toEqual([
expect(stored).toStrictEqual([
{ label: 'CPU', show: false },
{ label: 'Memory', show: true },
]);
@@ -202,7 +202,7 @@ describe('legendVisibilityUtils', () => {
const stored = getStoredSeriesVisibility('widget-1');
expect(stored).not.toBeNull();
expect(stored).toEqual([
expect(stored).toStrictEqual([
{ label: 'x-axis', show: true },
{ label: 'CPU', show: false },
]);
@@ -232,10 +232,10 @@ describe('legendVisibilityUtils', () => {
{ label: 'B', show: true },
]);
expect(getStoredSeriesVisibility('widget-a')).toEqual([
expect(getStoredSeriesVisibility('widget-a')).toStrictEqual([
{ label: 'A', show: true },
]);
expect(getStoredSeriesVisibility('widget-b')).toEqual([
expect(getStoredSeriesVisibility('widget-b')).toStrictEqual([
{ label: 'B', show: true },
]);
});
@@ -252,7 +252,7 @@ describe('legendVisibilityUtils', () => {
);
const [_, value] = (localStorage.setItem as jest.Mock).mock.calls[0];
expect((): void => JSON.parse(value)).not.toThrow();
expect(JSON.parse(value)).toEqual([
expect(JSON.parse(value)).toStrictEqual([
{ name: 'widget-1', dataIndex: [{ label: 'CPU', show: true }] },
]);
});
@@ -263,7 +263,7 @@ describe('legendVisibilityUtils', () => {
const raw = localStorage.getItem(storageKey);
expect(raw).not.toBeNull();
const parsed = JSON.parse(raw ?? '[]');
expect(parsed).toEqual([{ name: 'widget-1', dataIndex: [] }]);
expect(parsed).toStrictEqual([{ name: 'widget-1', dataIndex: [] }]);
expect(getStoredSeriesVisibility('widget-1')).toBeNull();
});
});

View File

@@ -188,7 +188,9 @@ describe('ForgotPassword Component', () => {
const submitButton = screen.getByTestId('forgot-password-submit');
await user.click(submitButton);
expect(await screen.findByText(/check your email/i)).toBeInTheDocument();
await expect(
screen.findByText(/check your email/i),
).resolves.toBeInTheDocument();
expect(
screen.getByText(/we've sent a password reset link/i),
).toBeInTheDocument();
@@ -208,7 +210,9 @@ describe('ForgotPassword Component', () => {
const submitButton = screen.getByTestId('forgot-password-submit');
await user.click(submitButton);
expect(await screen.findByTestId('back-to-login')).toBeInTheDocument();
await expect(
screen.findByTestId('back-to-login'),
).resolves.toBeInTheDocument();
});
it('redirects to login when clicking back to login on success screen', async () => {
@@ -225,7 +229,9 @@ describe('ForgotPassword Component', () => {
const submitButton = screen.getByTestId('forgot-password-submit');
await user.click(submitButton);
expect(await screen.findByTestId('back-to-login')).toBeInTheDocument();
await expect(
screen.findByTestId('back-to-login'),
).resolves.toBeInTheDocument();
const backToLoginButton = screen.getByTestId('back-to-login');
await user.click(backToLoginButton);
@@ -250,7 +256,9 @@ describe('ForgotPassword Component', () => {
const submitButton = screen.getByTestId('forgot-password-submit');
await user.click(submitButton);
expect(await screen.findByText(/user not found/i)).toBeInTheDocument();
await expect(
screen.findByText(/user not found/i),
).resolves.toBeInTheDocument();
});
it('displays error message when API returns server error', async () => {
@@ -263,9 +271,9 @@ describe('ForgotPassword Component', () => {
const submitButton = screen.getByTestId('forgot-password-submit');
await user.click(submitButton);
expect(
await screen.findByText(/internal server error occurred/i),
).toBeInTheDocument();
await expect(
screen.findByText(/internal server error occurred/i),
).resolves.toBeInTheDocument();
});
it('clears error message on new submission attempt', async () => {
@@ -295,7 +303,9 @@ describe('ForgotPassword Component', () => {
const submitButton = screen.getByTestId('forgot-password-submit');
await user.click(submitButton);
expect(await screen.findByText(/user not found/i)).toBeInTheDocument();
await expect(
screen.findByText(/user not found/i),
).resolves.toBeInTheDocument();
// Click submit again
await user.click(submitButton);
@@ -303,7 +313,9 @@ describe('ForgotPassword Component', () => {
await waitFor(() => {
expect(screen.queryByText(/user not found/i)).not.toBeInTheDocument();
});
expect(await screen.findByText(/check your email/i)).toBeInTheDocument();
await expect(
screen.findByText(/check your email/i),
).resolves.toBeInTheDocument();
});
});
@@ -336,7 +348,9 @@ describe('ForgotPassword Component', () => {
await user.click(submitButton);
// Button should show loading state
expect(await screen.findByText(/sending\.\.\./i)).toBeInTheDocument();
await expect(
screen.findByText(/sending\.\.\./i),
).resolves.toBeInTheDocument();
});
it('disables submit button during loading', async () => {

View File

@@ -139,8 +139,8 @@ function ChartPreview({
if (startTime && endTime && startTime !== endTime) {
dispatch(
UpdateTimeInterval('custom', [
parseInt(getTimeString(startTime), 10),
parseInt(getTimeString(endTime), 10),
Number.parseInt(getTimeString(startTime), 10),
Number.parseInt(getTimeString(endTime), 10),
]),
);
}

View File

@@ -76,7 +76,7 @@ describe('usePrefillAlertConditions', () => {
builder: { queryData: [{ reduceTo: 'p90' }] },
} as any),
);
expect(result.current.matchType).toBe(null);
expect(result.current.matchType).toBeNull();
});
it('returns the correct matchType for multiple queries with same time aggregation', () => {
@@ -112,7 +112,7 @@ describe('usePrefillAlertConditions', () => {
},
} as any),
);
expect(result.current.matchType).toBe(null);
expect(result.current.matchType).toBeNull();
});
it('returns the correct op, target, targetUnit from the higher priority threshold for multiple thresholds', () => {

View File

@@ -370,7 +370,7 @@ function FormAlertRules({
// onQueryCategoryChange handles changes to query category
// in state as well as sets additional defaults
const onQueryCategoryChange = (val: EQueryType): void => {
const element = document.getElementById('top');
const element = document.querySelector('#top');
if (element) {
element.scrollIntoView({ behavior: 'smooth' });
}

View File

@@ -5,10 +5,10 @@ import { getUpdatedStepInterval } from './utils';
describe('getUpdatedStepInterval', () => {
it('should return 60', () => {
const result = getUpdatedStepInterval('5m0s');
expect(result).toEqual(60);
expect(result).toBe(60);
});
it('should return 60 for 10m0s', () => {
const result = getUpdatedStepInterval('10m0s');
expect(result).toEqual(60);
expect(result).toBe(60);
});
});

View File

@@ -44,7 +44,7 @@ describe('Table Panel utils', () => {
expect(getQueryLegend(query, 'A')).toBe('p99');
// should return undefined when legend not present
expect(getQueryLegend(query, 'B')).toBe(undefined);
expect(getQueryLegend(query, 'B')).toBeUndefined();
});
it('sorter function for table sorting', () => {

View File

@@ -108,7 +108,7 @@ describe('EntityLogs', () => {
});
await waitFor(() => {
expect(capturedQueryRangePayloads.length).toBe(1);
expect(capturedQueryRangePayloads).toHaveLength(1);
});
await waitFor(async () => {
@@ -131,7 +131,7 @@ describe('EntityLogs', () => {
});
await waitFor(() => {
expect(capturedQueryRangePayloads.length).toBe(2);
expect(capturedQueryRangePayloads).toHaveLength(2);
});
const firstPayload = capturedQueryRangePayloads[0];

View File

@@ -149,7 +149,7 @@ describe('ServiceDetails for S3 Sync service', () => {
expect(capturedPayload).not.toBeNull();
});
expect(capturedPayload).toEqual({
expect(capturedPayload).toStrictEqual({
config: {
aws: {
logs: {

View File

@@ -68,12 +68,12 @@ describe('filterAlerts', () => {
it('should return all alerts when filter is empty', () => {
const result = filterAlerts(mockAlerts, '');
expect(result).toEqual(mockAlerts);
expect(result).toStrictEqual(mockAlerts);
});
it('should return all alerts when filter is only whitespace', () => {
const result = filterAlerts(mockAlerts, ' ');
expect(result).toEqual(mockAlerts);
expect(result).toStrictEqual(mockAlerts);
});
it('should filter alerts by alert name', () => {

View File

@@ -8,8 +8,19 @@ import {
OPERATORS,
QUERY_BUILDER_FUNCTIONS,
} from 'constants/antlrQueryConstants';
import { FeatureKeys } from 'constants/features';
import { QueryParams } from 'constants/query';
import { useActiveLog } from 'hooks/logs/useActiveLog';
import { useGetSearchQueryParam } from 'hooks/queryBuilder/useGetSearchQueryParam';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { ICurrentQueryData } from 'hooks/useHandleExplorerTabChange';
import { useNotifications } from 'hooks/useNotifications';
import { ExplorerViews } from 'pages/LogsExplorer/utils';
import { useAppContext } from 'providers/App/App';
import {
BaseAutocompleteData,
DataTypes,
} from 'types/api/queryBuilder/queryAutocompleteResponse';
import { TitleWrapper } from './BodyTitleRenderer.styles';
import { DROPDOWN_KEY } from './constant';
@@ -25,17 +36,32 @@ function BodyTitleRenderer({
parentIsArray = false,
nodeKey,
value,
handleChangeSelectedView,
}: BodyTitleRendererProps): JSX.Element {
const { onAddToQuery } = useActiveLog();
const { stagedQuery, updateQueriesData } = useQueryBuilder();
const { featureFlags } = useAppContext();
const [, setCopy] = useCopyToClipboard();
const { notifications } = useNotifications();
const viewName = useGetSearchQueryParam(QueryParams.viewName) || '';
const cleanedNodeKey = removeObjectFromString(nodeKey);
const isBodyJsonQueryEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.BODY_JSON_ENABLED)
?.active || false;
// Group by is supported only for body json query enabled and not for array elements
const isGroupBySupported =
isBodyJsonQueryEnabled && !cleanedNodeKey.includes('[]');
const filterHandler = (isFilterIn: boolean) => (): void => {
if (parentIsArray) {
onAddToQuery(
generateFieldKeyForArray(
removeObjectFromString(nodeKey),
cleanedNodeKey,
getDataTypes(value),
isBodyJsonQueryEnabled,
),
`${value}`,
isFilterIn
@@ -45,7 +71,7 @@ function BodyTitleRenderer({
);
} else {
onAddToQuery(
`body.${removeObjectFromString(nodeKey)}`,
`body.${cleanedNodeKey}`,
`${value}`,
isFilterIn ? OPERATORS['='] : OPERATORS['!='],
getDataTypes(value),
@@ -53,10 +79,67 @@ function BodyTitleRenderer({
}
};
const groupByHandler = useCallback((): void => {
if (!stagedQuery) {
return;
}
const groupByKey = parentIsArray
? generateFieldKeyForArray(
cleanedNodeKey,
getDataTypes(value),
isBodyJsonQueryEnabled,
)
: `body.${cleanedNodeKey}`;
const fieldDataType = getDataTypes(value);
const normalizedDataType: DataTypes | undefined = Object.values(
DataTypes,
).includes(fieldDataType as DataTypes)
? (fieldDataType as DataTypes)
: undefined;
const updatedQuery = updateQueriesData(
stagedQuery,
'queryData',
(item, index) => {
if (index === 0) {
const newGroupByItem: BaseAutocompleteData = {
key: groupByKey,
type: '',
dataType: normalizedDataType,
};
return { ...item, groupBy: [...(item.groupBy || []), newGroupByItem] };
}
return item;
},
);
const queryData: ICurrentQueryData = {
name: viewName,
id: updatedQuery.id,
query: updatedQuery,
};
handleChangeSelectedView?.(ExplorerViews.TIMESERIES, queryData);
}, [
cleanedNodeKey,
handleChangeSelectedView,
isBodyJsonQueryEnabled,
parentIsArray,
stagedQuery,
updateQueriesData,
value,
viewName,
]);
const onClickHandler: MenuProps['onClick'] = (props): void => {
const mapper = {
[DROPDOWN_KEY.FILTER_IN]: filterHandler(true),
[DROPDOWN_KEY.FILTER_OUT]: filterHandler(false),
[DROPDOWN_KEY.GROUP_BY]: groupByHandler,
};
const handler = mapper[props.key];
@@ -76,6 +159,14 @@ function BodyTitleRenderer({
key: DROPDOWN_KEY.FILTER_OUT,
label: `Filter out ${value}`,
},
...(isGroupBySupported
? [
{
key: DROPDOWN_KEY.GROUP_BY,
label: `Group by ${nodeKey}`,
},
]
: []),
],
onClick: onClickHandler,
};
@@ -84,7 +175,6 @@ function BodyTitleRenderer({
(e: React.MouseEvent): void => {
// Prevent tree node expansion/collapse
e.stopPropagation();
const cleanedKey = removeObjectFromString(nodeKey);
let copyText: string;
// Check if value is an object or array
@@ -106,8 +196,8 @@ function BodyTitleRenderer({
if (copyText) {
const notificationMessage = isObject
? `${cleanedKey} object copied to clipboard`
: `${cleanedKey} copied to clipboard`;
? `${cleanedNodeKey} object copied to clipboard`
: `${cleanedNodeKey} copied to clipboard`;
notifications.success({
message: notificationMessage,
@@ -115,7 +205,7 @@ function BodyTitleRenderer({
});
}
},
[nodeKey, parentIsArray, setCopy, value, notifications],
[cleanedNodeKey, parentIsArray, setCopy, value, notifications],
);
return (

View File

@@ -251,20 +251,20 @@ describe('ContextLogRenderer', () => {
const afterQuery = (afterPayload.compositeQuery as any).queries[0].spec;
// Verify timestamps remain constant
expect(afterStart).toEqual(initialPayload.start);
expect(afterEnd).toEqual(initialPayload.end);
expect(afterStart).toStrictEqual(initialPayload.start);
expect(afterEnd).toStrictEqual(initialPayload.end);
// Verify offset changes
expect(initialQuery.offset).toEqual(0);
expect(afterQuery.offset).toEqual(10);
expect(initialQuery.offset).toBe(0);
expect(afterQuery.offset).toBe(10);
// Verify filter changes
expect(initialQuery.filter.expression).toContain(expectedOpChange.before);
expect(afterQuery.filter.expression).toContain(expectedOpChange.after);
// Verify query structure remains consistent
expect(initialQuery.name).toEqual(afterQuery.name);
expect(initialQuery.signal).toEqual(afterQuery.signal);
expect(initialQuery.name).toStrictEqual(afterQuery.name);
expect(initialQuery.signal).toStrictEqual(afterQuery.signal);
};
it('should keep the start and end timestamps constant on clicking load more (prev / next) pages', async () => {

View File

@@ -1,3 +1,4 @@
import { ChangeViewFunctionType } from 'container/ExplorerOptions/types';
import { MetricsType } from 'container/MetricsApplication/constant';
import { ILog } from 'types/api/logs/log';
@@ -6,6 +7,7 @@ export interface BodyTitleRendererProps {
nodeKey: string;
value: unknown;
parentIsArray?: boolean;
handleChangeSelectedView?: ChangeViewFunctionType;
}
export type AnyObject = { [key: string]: any };

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