Compare commits

...

153 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
Shivam Gupta
44add7b7cd feat(onboarding): add OpenCode, Baseten, and DBOS datasources (#11109)
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(onboarding): add OpenCode, Baseten, and DBOS datasources

Adds three new datasources to the onboarding config with logos and
documentation links, closing signoz.io issues #3111, #3053, and #3040.

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

* fix(onboarding): fix basetenUrl import alphabetical ordering

---------

Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 03:11:38 +00:00
Yunus M
feea9e9b36 refactor: remove light mode styles from various components and update… (#11080)
Some checks failed
build-staging / prepare (push) Has been cancelled
Release Drafter / update_release_draft (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
* refactor: remove light mode styles from various components and update color variables

* fix: remove hardcoded background in celery
2026-04-25 06:57:25 +00:00
Ashwin Bhatkal
e94767bda8 refactor(frontend): remove xstate and migrate to plain React state (#11059)
* refactor(frontend): remove xstate and migrate to plain React state

Replace xstate state machines with useState-based step tracking in the
three remaining consumers (labels form, dashboard search filter,
resource attribute provider). Drops xstate and @xstate/react from
dependencies and removes the corresponding no-restricted-imports
entries from oxlint config.

* refactor: clear list of dashboard

* chore: resolve comments
2026-04-25 05:11:39 +00:00
Vishal Sharma
bb10f51cc5 feat(settings): add SigNoz MCP Server setup page (#11025)
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(settings): add SigNoz MCP Server setup page

Add a new Settings page at /settings/mcp-server that guides Cloud users
through connecting AI assistants (Cursor, VS Code, Claude Desktop, Claude
Code, Codex) to SigNoz via the Model Context Protocol, and provides a
deep-link into Service Accounts for creating the API key the OAuth flow
needs.

* feat(settings): point MCP Server onboarding tile to in-app settings page

The onboarding-config-with-links entry for SigNoz MCP Server previously
linked out to the docs page. Now that we ship an in-product setup page
at /settings/mcp-server, route Cloud users there directly via the
existing internalRedirect pattern. Self-hosted users still see the
in-page fallback card with a docs link.

* fix(settings): fire MCP Server page-viewed event reliably on mount

Previously gated the PAGE_VIEWED analytics event on
isGlobalConfigFetched to avoid a double-fire when the async
ingestion_url resolved. Side effect: if /global/config was slow or
errored out, the event never fired. Fire once on mount instead with
hostname-derived region metadata, which is synchronous and reliable.

* feat(mcp-page): ui refactor and redesign

* feat(mcp-page): global config and page access changes

* feat(mcp-page): refactor and added fallback page

* feat(mcp-page): added test cases

* feat(mcp-page): formatting lint

* feat(mcp-page): code refactor

* feat(mcp-page): cleanup and migrated global config api to open api spec

* feat(mcp-page): removed translation json and add endpoint url to copy

* feat(mcp-page): added mcp server to menu always for cloud and enterprise

---------

Co-authored-by: SagarRajput-7 <sagar@signoz.io>
Co-authored-by: SagarRajput-7 <162284829+SagarRajput-7@users.noreply.github.com>
2026-04-24 21:25:00 +00:00
Vinicius Lourenço
cd16081a1e chore(oxlint): remove unicorn & other rules that breaks the code on --fix (#11097)
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
2026-04-24 17:42:49 +00:00
Ashwin Bhatkal
c23a53c8d2 fix: add config path and fmt config path in vs code settings (#11093)
* fix: add config path vs code settings

* fix: add fmt config path as well

* fix: quiet instead of fix
2026-04-24 15:09:30 +00:00
Abhi kumar
dbfe47e757 chore: added tooltip events + minor ui fixes (#11086)
* chore: added tooltip events + minor ui fixes

* chore: pr review comments

* chore: added todo for event removal

* fix: added fix for formatting issues

---------

Co-authored-by: Ashwin Bhatkal <ashwin96@gmail.com>
2026-04-24 13:30:26 +00:00
Ashwin Bhatkal
e29b032e70 test(useResourceAttribute): add ResourceProvider behavior coverage (#11069)
* test(useResourceAttribute): add ResourceProvider behavior coverage

Covers initial state, URL hydration, step-machine transitions (Idle ->
TagKey -> Operator -> TagValue), handleBlur commit/purge paths,
handleClose/handleClearAll, handleEnvironmentChange (add, clear,
replace, dot-metrics feature flag, preserving unrelated URL params),
and SERVICE_MAP visibility filtering.

Tests exercise only the public IResourceAttributeProps contract so they
serve as a behavior pin for any future refactor of the internal state
machine.

* test(useResourceAttribute): close ResourceProvider coverage gaps

Adds four tests covering:
- URL re-hydration effect fires when router URL changes mid-session
- SERVICE_MAP filters fetched tag keys through whilelistedKeys
- In-flight GetTagKeys keeps loading=true and clears optionsData
- API error payload still flips loading=false and leaves options empty

* fix: format file
2026-04-24 12:59:59 +00:00
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
474 changed files with 15112 additions and 7370 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

@@ -1,6 +1,8 @@
{
"oxc.typeAware": true,
"oxc.tsConfigPath": "./frontend/tsconfig.json",
"oxc.configPath": "./frontend/.oxlintrc.json",
"oxc.fmt.configPath": "./frontend/.oxfmtrc.json",
"editor.formatOnSave": true,
"editor.defaultFormatter": "oxc.oxc-vscode",
"editor.codeActionsOnSave": {
@@ -19,4 +21,3 @@
"python-envs.defaultEnvManager": "ms-python.python:system",
"python-envs.pythonProjects": []
}

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
}

View File

@@ -9,7 +9,6 @@
"react",
"react-perf",
"typescript",
"unicorn",
"jsx-a11y",
"import",
"jest",
@@ -206,6 +205,8 @@
"@typescript-eslint/explicit-function-return-type": "error",
// Requires explicit return types on functions
"@typescript-eslint/no-var-requires": "error",
"@typescript-eslint/no-useless-default-assignment": "off", // provide unsafe fixes in our codebase due to bad typing
"@typescript-eslint/no-duplicate-type-constituents": "off", // provide fixes that breaks some assumptions, eg: type A = L, B = L, C = A | B (removes B)
// Disallows require() in TypeScript (use import instead)
// Disabled - using TypeScript instead
"react/jsx-props-no-spreading": "off",
@@ -312,14 +313,6 @@
"name": "react-redux",
"message": "[State mgmt] react-redux is deprecated. Migrate to Zustand, nuqs, or react-query."
},
{
"name": "xstate",
"message": "[State mgmt] xstate is deprecated. Migrate to Zustand or react-query."
},
{
"name": "@xstate/react",
"message": "[State mgmt] @xstate/react is deprecated. Migrate to Zustand or react-query."
},
{
"name": "react",
"importNames": [
@@ -338,82 +331,6 @@
"react/no-array-index-key": "warn",
// TODO: Changed to warn during oxlint migration, should be changed to error,
"unicorn/error-message": "warn",
"unicorn/escape-case": "warn",
"unicorn/new-for-builtins": "warn",
"unicorn/no-abusive-eslint-disable": "warn",
"unicorn/no-console-spaces": "warn",
"unicorn/no-instanceof-array": "warn",
"unicorn/no-invalid-remove-event-listener": "warn",
"unicorn/no-new-array": "warn",
"unicorn/no-new-buffer": "warn",
"unicorn/no-thenable": "warn",
"unicorn/no-unreadable-array-destructuring": "warn",
"unicorn/no-useless-fallback-in-spread": "warn",
"unicorn/no-useless-length-check": "warn",
"unicorn/no-useless-promise-resolve-reject": "warn",
"unicorn/no-useless-spread": "warn",
"unicorn/no-zero-fractions": "warn",
"unicorn/number-literal-case": "warn",
"unicorn/prefer-array-find": "warn",
"unicorn/prefer-array-flat": "warn",
"unicorn/prefer-array-flat-map": "warn",
"unicorn/prefer-array-index-of": "warn",
"unicorn/prefer-array-some": "warn",
"unicorn/prefer-at": "warn",
"unicorn/prefer-code-point": "warn",
"unicorn/prefer-date-now": "warn",
"unicorn/prefer-default-parameters": "warn",
"unicorn/prefer-includes": "warn",
"unicorn/prefer-modern-math-apis": "warn",
"unicorn/prefer-native-coercion-functions": "warn",
"unicorn/prefer-node-protocol": "off",
"unicorn/prefer-number-properties": "warn",
"unicorn/prefer-optional-catch-binding": "warn",
"unicorn/prefer-regexp-test": "warn",
"unicorn/prefer-set-has": "warn",
"unicorn/prefer-string-replace-all": "warn",
"unicorn/prefer-string-slice": "warn",
"unicorn/prefer-string-starts-ends-with": "warn",
"unicorn/prefer-string-trim-start-end": "warn",
"unicorn/prefer-type-error": "warn",
"unicorn/require-array-join-separator": "warn",
"unicorn/require-number-to-fixed-digits-argument": "warn",
"unicorn/throw-new-error": "warn",
"unicorn/consistent-function-scoping": "warn",
"unicorn/explicit-length-check": "warn",
"unicorn/filename-case": [
"warn",
{
"case": "kebabCase"
}
],
"unicorn/no-array-for-each": "warn",
"unicorn/no-lonely-if": "warn",
"unicorn/no-negated-condition": "warn",
"unicorn/no-null": "warn",
"unicorn/no-object-as-default-parameter": "warn",
"unicorn/no-static-only-class": "warn",
"unicorn/no-this-assignment": "warn",
"unicorn/no-unreadable-iife": "warn",
"unicorn/no-useless-switch-case": "warn",
"unicorn/no-useless-undefined": "warn",
"unicorn/prefer-add-event-listener": "warn",
"unicorn/prefer-dom-node-append": "warn",
"unicorn/prefer-dom-node-dataset": "warn",
"unicorn/prefer-dom-node-remove": "warn",
"unicorn/prefer-dom-node-text-content": "warn",
"unicorn/prefer-keyboard-event-key": "warn",
"unicorn/prefer-math-trunc": "warn",
"unicorn/prefer-modern-dom-apis": "warn",
"unicorn/prefer-negative-index": "warn",
"unicorn/prefer-prototype-methods": "warn",
"unicorn/prefer-query-selector": "warn",
"unicorn/prefer-reflect-apply": "warn",
"unicorn/prefer-set-size": "warn",
"unicorn/prefer-spread": "warn",
"unicorn/prefer-ternary": "warn",
"unicorn/require-post-message-target-origin": "warn",
"oxc/bad-array-method-on-arguments": "error",
"oxc/bad-bitwise-operator": "error",
"oxc/bad-comparison-sequence": "error",
@@ -538,8 +455,8 @@
"sonarjs/no-nested-template-literals": "error",
// Avoids nested template literals
"sonarjs/no-redundant-boolean": "warn", // TODO: Change to error after migration
// Removes redundant boolean literals
"sonarjs/no-redundant-jump": "error",
// Removes redundant boolean literals - turned off because it clashes with unicorn rules
"sonarjs/no-redundant-jump": "off",
// Removes unnecessary returns/continues
"sonarjs/no-same-line-conditional": "error",
// Prevents same-line conditionals

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

@@ -63,7 +63,6 @@
"@visx/shape": "3.5.0",
"@visx/tooltip": "3.3.0",
"@vitejs/plugin-react": "5.1.4",
"@xstate/react": "^3.0.0",
"ansi-to-html": "0.7.2",
"antd": "5.11.0",
"antd-table-saveas-excel": "2.2.1",
@@ -146,7 +145,6 @@
"vite": "npm:rolldown-vite@7.3.1",
"vite-plugin-html": "3.2.2",
"web-vitals": "^0.2.4",
"xstate": "^4.31.0",
"zod": "4.3.6",
"zustand": "5.0.11"
},
@@ -214,9 +212,9 @@
"msw": "1.3.2",
"npm-run-all": "latest",
"orval": "7.18.0",
"oxfmt": "0.41.0",
"oxlint": "1.59.0",
"oxlint-tsgolint": "0.20.0",
"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",
@@ -240,9 +238,12 @@
},
"lint-staged": {
"*.(js|jsx|ts|tsx)": [
"oxfmt --check",
"oxlint --fix",
"oxfmt --write",
"sh scripts/typecheck-staged.sh"
],
"*.(scss|css)": [
"stylelint"
]
},
"resolutions": {

View File

@@ -16,5 +16,6 @@
"roles": "Roles",
"role_details": "Role Details",
"members": "Members",
"service_accounts": "Service Accounts"
"service_accounts": "Service Accounts",
"mcp_server": "MCP Server"
}

View File

@@ -53,5 +53,6 @@
"METER": "SigNoz | Meter",
"ROLES_SETTINGS": "SigNoz | Roles",
"MEMBERS_SETTINGS": "SigNoz | Members",
"SERVICE_ACCOUNTS_SETTINGS": "SigNoz | Service Accounts"
"SERVICE_ACCOUNTS_SETTINGS": "SigNoz | Service Accounts",
"MCP_SERVER": "SigNoz | MCP Server"
}

View File

@@ -16,5 +16,6 @@
"roles": "Roles",
"role_details": "Role Details",
"members": "Members",
"service_accounts": "Service Accounts"
"service_accounts": "Service Accounts",
"mcp_server": "MCP Server"
}

View File

@@ -76,5 +76,6 @@
"METER": "SigNoz | Meter",
"ROLES_SETTINGS": "SigNoz | Roles",
"MEMBERS_SETTINGS": "SigNoz | Members",
"SERVICE_ACCOUNTS_SETTINGS": "SigNoz | Service Accounts"
"SERVICE_ACCOUNTS_SETTINGS": "SigNoz | Service Accounts",
"MCP_SERVER": "SigNoz | MCP Server"
}

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

@@ -1,25 +0,0 @@
import axios from 'api';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import {
GlobalConfigData,
GlobalConfigDataProps,
} from 'types/api/globalConfig/types';
const getGlobalConfig = async (): Promise<
SuccessResponseV2<GlobalConfigData>
> => {
try {
const response = await axios.get<GlobalConfigDataProps>(`/global/config`);
return {
httpStatusCode: response.status,
data: response.data.data,
};
} catch (error) {
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
}
};
export default getGlobalConfig;

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

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" height="34" viewBox="0 0 131 34">
<path fill="currentColor" d="M.36 8.6h16.7v5.6H6.04c-.2 0-.35.16-.35.35v4.9c0 .2.16.35.35.35h11.02v5.6h-5.33c-.2 0-.35.16-.35.35v4.9c0 .2.16.35.35.35h4.98c.2 0 .35-.15.35-.35V25.4h5.34c.2 0 .35-.16.35-.35v-4.9c0-.2-.16-.35-.35-.35h-5.34v-5.6h5.34c.2 0 .35-.16.35-.35v-4.9c0-.2-.16-.35-.35-.35h-5.34V3.35c0-.2-.16-.35-.35-.35H.36c-.2 0-.36.16-.36.35v4.9c0 .2.16.35.36.35ZM44.41 14.7c-.5-.5-1.1-.9-1.76-1.18a5.62 5.62 0 0 0-4.6.17c-.73.37-1.32.91-1.75 1.62h-.17V8.59H34.1v16.83h2.04v-1.81h.17c.21.36.47.67.77.94.31.25.65.48 1.01.67.37.18.77.31 1.18.39a6.2 6.2 0 0 0 3.39-.24 5.36 5.36 0 0 0 3.02-3.1c.29-.75.44-1.62.44-2.6v-.47c0-.96-.16-1.83-.47-2.58-.3-.75-.7-1.4-1.23-1.9v-.01Zm-5.87.66a3.9 3.9 0 0 1 4.34.84c.36.35.64.8.83 1.3.2.5.3 1.07.3 1.7v.47c0 .64-.1 1.23-.3 1.74a3.75 3.75 0 0 1-2.06 2.15 4.27 4.27 0 0 1-3.12-.03 3.86 3.86 0 0 1-2.09-2.2c-.2-.52-.3-1.11-.3-1.75v-.29c0-.62.1-1.2.3-1.7v-.01c.21-.53.5-.99.84-1.36.36-.37.78-.66 1.26-.86ZM97.04 8.59H95v4.86h-2.94v1.86H95v8.17c0 .56.17 1.03.53 1.4.37.35.84.54 1.4.54h4.18v-1.87h-3.5c-.2 0-.33-.05-.43-.15-.1-.1-.14-.27-.14-.49v-7.6h4.65v-1.86h-4.65V8.59ZM114.61 15a5.48 5.48 0 0 0-1.8-1.33 5.6 5.6 0 0 0-2.57-.56 6.17 6.17 0 0 0-4.26 1.7 5.6 5.6 0 0 0-1.72 4.2v.57c0 .9.15 1.75.44 2.5a5.58 5.58 0 0 0 5.5 3.67c1.55 0 2.8-.35 3.72-1.04a5.35 5.35 0 0 0 1.91-2.73l.03-.07-1.94-.52-.02.07c-.11.33-.27.64-.46.94-.17.27-.4.52-.7.74-.28.22-.63.39-1.04.51-.41.13-.9.19-1.46.19a3.8 3.8 0 0 1-2.84-1.05 4.07 4.07 0 0 1-1.1-2.7h9.68v-1.6c0-.54-.11-1.12-.34-1.75a5.04 5.04 0 0 0-1.03-1.74Zm-8.25 3.21a3.8 3.8 0 0 1 1.22-2.25 4.19 4.19 0 0 1 3.99-.7c.44.16.83.38 1.17.66.34.27.62.62.82 1.02.21.38.34.8.38 1.27h-7.58ZM129.09 14.42a4.47 4.47 0 0 0-3.37-1.3c-.93 0-1.73.2-2.4.59-.64.39-1.15.97-1.52 1.74h-.17v-2h-2.04v11.97h2.04v-6.23c0-1.26.32-2.28.95-3.02a3.31 3.31 0 0 1 2.65-1.14c.94 0 1.7.3 2.24.9.56.6.83 1.52.83 2.74v6.75h2.04v-7.13c0-1.71-.42-3.02-1.25-3.87ZM88.1 15a5.48 5.48 0 0 0-1.78-1.33 5.6 5.6 0 0 0-2.58-.56 6.17 6.17 0 0 0-4.27 1.7 5.59 5.59 0 0 0-1.71 4.2v.56c0 .92.14 1.76.44 2.51a5.6 5.6 0 0 0 5.5 3.67c1.55 0 2.8-.35 3.72-1.04a5.36 5.36 0 0 0 1.91-2.73l.03-.07-1.94-.52-.03.07c-.1.32-.26.64-.45.94-.17.27-.4.52-.7.74-.29.21-.64.39-1.05.51-.4.12-.9.19-1.45.19a3.8 3.8 0 0 1-2.85-1.05 4.07 4.07 0 0 1-1.09-2.7h9.68v-1.61c0-.53-.12-1.12-.34-1.74A5.03 5.03 0 0 0 88.1 15Zm-8.24 3.21a3.83 3.83 0 0 1 1.22-2.25 4.2 4.2 0 0 1 3.99-.7c.44.16.83.38 1.16.66.35.27.62.62.83 1.02.2.38.33.8.37 1.27h-7.57ZM73.65 19.42a6.11 6.11 0 0 0-3.23-1.02 6.63 6.63 0 0 1-2.68-.58c-.47-.3-.7-.7-.7-1.25 0-.27.08-.5.21-.7.14-.2.33-.38.56-.52a4.05 4.05 0 0 1 1.78-.42c.85 0 1.54.21 2.06.63.53.41.83 1 .91 1.73l.01.1 1.95-.47-.01-.07c-.07-.45-.22-.91-.45-1.36a3.46 3.46 0 0 0-.94-1.2 4.6 4.6 0 0 0-1.52-.84 6.05 6.05 0 0 0-2.1-.34c-.58 0-1.13.07-1.65.22-.52.14-1 .36-1.43.65-.41.3-.74.66-.99 1.1a2.9 2.9 0 0 0-.37 1.49v.14c0 1.06.38 1.87 1.14 2.42a6.2 6.2 0 0 0 3.24.97c1.18.08 2.04.26 2.56.54.5.28.75.72.75 1.36 0 .6-.25 1.06-.78 1.4-.52.32-1.22.48-2.1.48a3.68 3.68 0 0 1-2.46-.79 3.13 3.13 0 0 1-1.04-2.14v-.09l-1.93.46h-.02v.07a4.4 4.4 0 0 0 3.1 4c.7.24 1.52.36 2.46.36.7 0 1.35-.09 1.93-.27.6-.16 1.12-.4 1.53-.72A3.38 3.38 0 0 0 74.8 22v-.14c0-1.07-.39-1.9-1.14-2.44ZM60.25 23.4c-.1-.1-.14-.27-.14-.49v-9.46h-2.05v1.85h-.16a3.78 3.78 0 0 0-1.61-1.63 4.62 4.62 0 0 0-2.26-.56c-.77 0-1.5.14-2.19.41a5.27 5.27 0 0 0-3.02 3.12c-.29.75-.44 1.63-.44 2.6v.38c0 .99.15 1.87.44 2.63.3.75.7 1.4 1.2 1.93a5.48 5.48 0 0 0 4.05 1.57c.8 0 1.51-.2 2.2-.58.69-.38 1.24-.97 1.63-1.75h.16v.06c0 .56.18 1.03.53 1.4.37.35.85.54 1.41.54h1.36v-1.87h-.68c-.2 0-.34-.05-.43-.15Zm-4.46.13c-.46.2-.97.3-1.52.3a3.68 3.68 0 0 1-2.75-1.09 4.42 4.42 0 0 1-1.05-3.12v-.38c0-.62.1-1.2.29-1.71a3.65 3.65 0 0 1 5-2.17c.47.2.88.49 1.21.86.35.37.62.83.8 1.36.2.5.3 1.08.3 1.7v.3c0 .63-.1 1.23-.3 1.76-.18.5-.45.96-.78 1.33-.33.37-.73.66-1.2.86Z"/>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -0,0 +1,13 @@
<svg width="109" height="24" viewBox="0 0 109 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_125_22125)">
<path d="M0 -2.08616e-07V24H17.9352C22.9911 24 26.0999 21.0858 26.0999 17.04V6.96C26.0999 2.91432 22.9911 -2.08616e-07 17.9352 -2.08616e-07H0ZM6.76413 5.82864H19.1992V18.1714H6.76413V5.82864Z" fill="currentColor"/>
<path d="M46.7659 18.6172H35.0824V14.16H46.7659V18.6172ZM46.595 5.38296V9.5658H35.0824V5.38296H46.595ZM50.2846 12.1373V11.5886C52.5734 10.5258 53.7008 8.8458 53.7008 6.13728C53.7008 2.64012 50.9337 0.000116183 45.5361 0.000116183H28.3184V24H45.7752C51.1728 24 53.9399 21.8401 53.9399 18.0685C53.9399 15.0172 52.6418 13.2001 50.2846 12.1373Z" fill="currentColor"/>
<path d="M62.397 18.1714H74.8319V5.82864H62.397V18.1714ZM63.6609 24C58.6049 24 55.4961 21.0858 55.4961 17.04V6.96012C55.4961 2.91432 58.6049 0.000116183 63.6609 0.000116183H73.568C78.6238 0.000116183 81.7326 2.91432 81.7326 6.96012V17.04C81.7326 21.0858 78.6238 24 73.568 24H63.6609Z" fill="currentColor"/>
<path d="M101.66 15.12L90.8995 14.3658C85.5361 13.9886 83.418 11.1772 83.418 7.47432V6.96012C83.418 2.91432 86.5266 0.000116183 91.5827 0.000116183H100.157C105.214 0.000116183 108.323 2.91432 108.323 6.96012V7.98864H101.968V5.14284H90.2504V8.43432L100.601 9.18864C105.999 9.56568 108.493 12.8572 108.493 16.5257V17.04C108.493 20.7428 105.384 24 100.328 24H91.5827C86.5266 24 83.418 20.7428 83.418 17.04V16.0115H89.7722V18.8572H101.66V15.12Z" fill="currentColor"/>
</g>
<defs>
<clipPath id="clip0_125_22125">
<rect width="108.494" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1 @@
<svg width='234' height='42' viewBox='0 0 234 42' fill='none' xmlns='http://www.w3.org/2000/svg'><path d='M18 30H6V18H18V30Z' fill='#CFCECD'/><path d='M18 12H6V30H18V12ZM24 36H0V6H24V36Z' fill='#656363'/><path d='M48 30H36V18H48V30Z' fill='#CFCECD'/><path d='M36 30H48V12H36V30ZM54 36H36V42H30V6H54V36Z' fill='#656363'/><path d='M84 24V30H66V24H84Z' fill='#CFCECD'/><path d='M84 24H66V30H84V36H60V6H84V24ZM66 18H78V12H66V18Z' fill='#656363'/><path d='M108 36H96V18H108V36Z' fill='#CFCECD'/><path d='M108 12H96V36H90V6H108V12ZM114 36H108V12H114V36Z' fill='#656363'/><path d='M144 30H126V18H144V30Z' fill='#CFCECD'/><path d='M144 12H126V30H144V36H120V6H144V12Z' fill='#211E1E'/><path d='M168 30H156V18H168V30Z' fill='#CFCECD'/><path d='M168 12H156V30H168V12ZM174 36H150V6H174V36Z' fill='#211E1E'/><path d='M198 30H186V18H198V30Z' fill='#CFCECD'/><path d='M198 12H186V30H198V12ZM204 36H180V6H198V0H204V36Z' fill='#211E1E'/><path d='M234 24V30H216V24H234Z' fill='#CFCECD'/><path d='M216 12V18H228V12H216ZM234 24H216V30H234V36H210V6H234V24Z' fill='#211E1E'/></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -74,7 +74,7 @@
width: 100%;
height: 100%;
background: radial-gradient(circle, #fff 10%, transparent 0);
background: radial-gradient(circle, var(--l1-foreground) 10%, transparent 0);
background-size: 12px 12px;
opacity: 1;

View File

@@ -99,36 +99,6 @@
}
}
.lightMode {
.auth-error-container {
.error-content {
&__error-code {
color: var(--l2-foreground);
}
&__error-message {
color: var(--l1-foreground);
}
&__message-badge-label-text {
color: var(--l2-foreground);
}
&__message-item {
color: var(--l1-foreground);
&::before {
background: var(--l3-background);
}
}
&__scroll-hint-text {
color: var(--l2-foreground);
}
}
}
}
@keyframes horizontal-shaking {
0% {
transform: translateX(0);

View File

@@ -87,23 +87,3 @@
background: var(--l3-background);
flex-shrink: 0;
}
.lightMode {
.auth-footer-content {
box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.08);
}
.auth-footer-icon {
filter: brightness(0) saturate(100%) invert(25%) sepia(8%) saturate(518%)
hue-rotate(192deg) brightness(80%) contrast(95%);
opacity: 0.9;
}
.auth-footer-text {
color: var(--text-neutral-light-200);
}
.auth-footer-link-icon {
color: var(--text-neutral-light-100);
}
}

View File

@@ -143,28 +143,3 @@
}
}
}
.lightMode {
.bg-dot-pattern {
background: radial-gradient(
circle,
var(--l3-background) 1px,
transparent 1px
);
background-size: 12px 12px;
}
.auth-page-gradient {
background: radial-gradient(
ellipse at center top,
color-mix(in srgb, var(--primary-background) 12%, transparent) 0%,
transparent 60%
);
opacity: 0.8;
filter: blur(200px);
@media (min-width: 768px) {
filter: blur(300px);
}
}
}

View File

@@ -41,7 +41,6 @@
justify-content: center;
align-items: center;
border: 1px solid var(--l1-border);
background: linear-gradient(0deg, transparent 0%, transparent 100%), #0b0c0e;
.ant-card-body {
height: 100%;
@@ -238,18 +237,7 @@
height: 2px;
bottom: 0;
left: 0;
background-color: var(--l1-foreground);
}
}
.lightMode {
.celery-task-graph-grid-container {
.celery-task-graph-worker-count {
background: unset;
}
}
.configure-option-Info {
border: 1px dashed var(--bg-robin-400);
background-color: var(--l1-background);
color: var(--l1-foreground);
}
}

View File

@@ -32,6 +32,7 @@ function CreateServiceAccountModal(): JSX.Element {
SA_QUERY_PARAMS.CREATE_SA,
parseAsBoolean.withDefault(false),
);
const [, setSelectedAccountId] = useQueryState(SA_QUERY_PARAMS.ACCOUNT);
const { showErrorModal, isErrorModalVisible } = useErrorModal();
@@ -50,11 +51,12 @@ function CreateServiceAccountModal(): JSX.Element {
const { mutate: createServiceAccount, isLoading: isSubmitting } =
useCreateServiceAccount({
mutation: {
onSuccess: async () => {
onSuccess: async (response) => {
toast.success('Service account created successfully');
reset();
await setIsOpen(null);
await invalidateListServiceAccounts(queryClient);
await setSelectedAccountId(response.data.id);
},
onError: (err) => {
const errMessage = convertToApiError(
@@ -67,7 +69,7 @@ function CreateServiceAccountModal(): JSX.Element {
function handleClose(): void {
reset();
setIsOpen(null);
void setIsOpen(null);
}
function handleCreate(values: FormValues): void {

View File

@@ -77,11 +77,11 @@
width: 280px;
&::placeholder {
color: white;
color: var(--l1-foreground);
}
&:focus::placeholder {
color: rgba($color: #ffffff, $alpha: 0.4);
color: rgba($color: var(--l1-foreground), $alpha: 0.4);
}
}
}
@@ -113,42 +113,6 @@
}
}
.lightMode {
.time-options-container {
.time-options-item {
&.active {
background-color: rgba($color: #ffffff, $alpha: 0.2);
&:hover {
cursor: pointer;
background-color: rgba($color: #ffffff, $alpha: 0.3);
}
}
&:hover {
cursor: pointer;
background-color: rgba($color: #ffffff, $alpha: 0.3);
}
}
}
.timeSelection-input {
display: flex;
gap: 8px;
align-items: center;
padding: 4px 8px;
padding-left: 0px !important;
input::placeholder {
color: var(---bg-ink-300);
}
input:focus::placeholder {
color: rgba($color: #000000, $alpha: 0.4);
}
}
}
.date-time-popover__footer {
border-top: 1px solid var(--l1-border);
padding: 8px 14px;
@@ -300,34 +264,3 @@
background: color-mix(in srgb, var(--bg-robin-200) 8%, transparent);
}
}
.lightMode {
.timezone-container {
.timezone {
background: rgb(179 179 179 / 15%);
&__icon {
stroke: var(--l1-foreground);
}
}
}
.custom-time-picker {
.timeSelection-input {
&:hover {
border-color: var(--l1-border) !important;
}
}
}
.timezone-badge {
background: rgb(179 179 179 / 15%);
}
.time-input-suffix-icon-badge {
background: rgb(179 179 179 / 15%);
&:hover {
background: rgb(179 179 179 / 20%);
}
}
}

View File

@@ -129,20 +129,3 @@ $item-spacing: 8px;
width: 15px;
}
}
.lightMode {
.timezone-picker {
&__search {
.search-icon {
stroke: var(--l1-foreground);
}
}
}
.timezone-name-wrapper {
&__selected-icon {
.check-icon {
stroke: var(--l1-foreground);
}
}
}
}

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

@@ -1,9 +1,5 @@
.dropdown-button {
color: #fff;
}
.dropdown-button--dark {
color: #000;
color: var(--l1-foreground);
}
.dropdown-icon {

View File

@@ -1,7 +1,6 @@
import { useState } from 'react';
import { EllipsisOutlined } from '@ant-design/icons';
import { Button, Dropdown, MenuProps } from 'antd';
import { useIsDarkMode } from 'hooks/useDarkMode';
import './DropDown.styles.scss';
@@ -12,8 +11,6 @@ function DropDown({
element: JSX.Element[];
onDropDownItemClick?: MenuProps['onClick'];
}): JSX.Element {
const isDarkMode = useIsDarkMode();
const items: MenuProps['items'] = element.map(
(e: JSX.Element, index: number) => ({
label: e,
@@ -35,7 +32,7 @@ function DropDown({
>
<Button
type="link"
className={!isDarkMode ? 'dropdown-button--dark' : 'dropdown-button'}
className={`dropdown-button`}
onClick={(e): void => {
e.preventDefault();
setDdOpen(true);

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

@@ -196,17 +196,3 @@
opacity: 0.5;
}
}
.lightMode {
.members-table {
.ant-table-tbody {
> tr.members-table-row--tinted > td {
background: rgba(0, 0, 0, 0.015);
}
> tr:hover > td {
background: rgba(0, 0, 0, 0.03) !important;
}
}
}
}

View File

@@ -167,22 +167,3 @@
padding-right: 8px;
}
}
.lightMode {
.config-btn {
&.missing-config-btn {
background: var(--bg-amber-100);
color: var(--bg-amber-500);
&:hover {
color: var(--bg-amber-600) !important;
}
}
.missing-config-btn {
.config-btn-content {
border-right: 1px solid var(--bg-amber-600);
}
}
}
}

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

@@ -16,7 +16,7 @@ $custom-border-color: #2c3044;
}
.ant-select-selection-placeholder {
color: color-mix(in srgb, var(--border) 45%, transparent);
color: color-mix(in srgb, var(--l2-foreground) 45%, transparent);
}
// Base styles are for dark mode
@@ -48,10 +48,6 @@ $custom-border-color: #2c3044;
visibility: visible !important;
pointer-events: none;
z-index: 2;
.lightMode & {
color: rgba(0, 0, 0, 0.85) !important;
}
}
&.ant-select-focused .ant-select-selection-placeholder {
@@ -67,10 +63,6 @@ $custom-border-color: #2c3044;
color: var(--l2-foreground);
z-index: 1;
pointer-events: none;
.lightMode & {
color: rgba(0, 0, 0, 0.85);
}
}
.ant-select-selector {
@@ -114,7 +106,7 @@ $custom-border-color: #2c3044;
}
.ant-select-selection-placeholder {
color: color-mix(in srgb, var(--border) 45%, transparent);
color: color-mix(in srgb, var(--l2-foreground) 45%, transparent);
}
// Customize tags in multiselect (dark mode by default)
@@ -217,7 +209,7 @@ $custom-border-color: #2c3044;
.empty-message {
padding: 12px;
text-align: center;
color: color-mix(in srgb, var(--border) 45%, transparent);
color: color-mix(in srgb, var(--l1-foreground) 45%, transparent);
}
}
@@ -575,7 +567,7 @@ $custom-border-color: #2c3044;
.empty-message {
padding: 12px;
text-align: center;
color: color-mix(in srgb, var(--border) 45%, transparent);
color: color-mix(in srgb, var(--l1-foreground) 45%, transparent);
}
.status-message {
@@ -983,10 +975,6 @@ $custom-border-color: #2c3044;
transition:
opacity 0.2s ease,
visibility 0.2s ease;
.lightMode & {
color: rgba(0, 0, 0, 0.85);
}
}
&:focus-within .all-text {

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

@@ -249,57 +249,6 @@
}
}
.lightMode {
.query-aggregation-container {
.aggregation-container {
.query-aggregation-select-container {
.query-aggregation-select-editor {
.cm-editor {
.cm-tooltip-autocomplete {
background: var(--l1-background) !important;
border: 1px solid var(--l1-border) !important;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1) !important;
backdrop-filter: none;
ul {
li {
&:hover,
&[aria-selected='true'] {
background: var(--l3-background) !important;
}
}
}
}
.cm-line {
::-moz-selection {
background: var(--l2-background) !important;
opacity: 0.5 !important;
}
::selection {
background: var(--l1-background) !important;
opacity: 0.5 !important;
}
.cm-function {
color: var(--primary-background) !important;
}
}
}
}
}
}
}
.query-aggregation-error-popover {
.ant-popover-inner {
background-color: var(--l1-background);
border: none;
box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.1);
}
}
}
.query-aggregation-error-popover {
.ant-popover-inner {
background-color: var(--l1-border);

View File

@@ -121,44 +121,3 @@
}
}
}
.lightMode {
.qb-trace-operator {
&-arrow {
&::before {
background: repeating-linear-gradient(
to right,
var(--l3-background),
var(--l3-background) 4px,
transparent 4px,
transparent 8px
);
}
&::after {
background-color: var(--l3-background);
}
}
&.non-list-view {
&::before {
background: repeating-linear-gradient(
to bottom,
var(--l3-background),
var(--l3-background) 4px,
transparent 4px,
transparent 8px
);
}
}
&-label-with-input {
border: 1px solid var(--l1-border) !important;
background: var(--l1-background) !important;
.label {
color: var(--l1-foreground) !important;
border-right: 1px solid var(--l1-border) !important;
background: var(--l1-background) !important;
}
}
}
}

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

@@ -152,7 +152,7 @@
width: 100%;
height: 100%;
background: radial-gradient(circle, #fff 10%, transparent 0);
background: radial-gradient(circle, var(--l1-foreground) 10%, transparent 0);
background-size: 12px 12px;
opacity: 1;

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

@@ -12,6 +12,12 @@
flex-shrink: 0;
}
&__layout {
display: flex;
flex-direction: column;
height: 100%;
}
&__tab-group {
[data-slot='toggle-group'] {
border-radius: 2px;

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

@@ -197,17 +197,3 @@
background-color: var(--l1-border);
}
}
.lightMode {
.sa-table {
.ant-table-tbody {
> tr.sa-table-row--tinted > td {
background: rgba(0, 0, 0, 0.015);
}
> tr:hover > td {
background: rgba(0, 0, 0, 0.03) !important;
}
}
}
}

View File

@@ -147,12 +147,12 @@
left: 50%;
width: 4px;
transform: translateX(-50%);
background: var(--l2-background);
opacity: 1;
pointer-events: none;
transition:
background 120ms ease,
width 120ms ease;
background: transparent;
}
.cursorColResize:hover .tanstackResizeHandleLine {

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

@@ -186,29 +186,3 @@
letter-spacing: -0.06px;
}
}
.lightMode {
.warning-content {
&__warning-code {
color: var(--l2-foreground);
}
&__warning-message {
color: var(--l1-foreground);
}
&__message-item {
color: var(--l1-foreground);
}
&__message-badge {
&-label-text {
color: var(--l1-foreground);
}
.key-value-label__value {
color: var(--l1-foreground);
}
}
&__docs-button {
background: var(--l1-background);
color: var(--l2-foreground);
}
}
}

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

@@ -3,6 +3,9 @@ export enum Events {
UPDATE_GRAPH_MANAGER_TABLE = 'UPDATE_GRAPH_MANAGER_TABLE',
TABLE_COLUMNS_DATA = 'TABLE_COLUMNS_DATA',
SLOW_API_WARNING = 'SLOW_API_WARNING',
TOOLTIP_PINNED = 'TOOLTIP_PINNED',
TOOLTIP_UNPINNED = 'TOOLTIP_UNPINNED',
TOOLTIP_CONTENT_SCROLLED = 'TOOLTIP_CONTENT_SCROLLED',
}
export enum InfraMonitoringEvents {

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

@@ -87,6 +87,7 @@ const ROUTES = {
HOME_PAGE: '/',
PUBLIC_DASHBOARD: '/public/dashboard/:dashboardId',
SERVICE_ACCOUNTS_SETTINGS: '/settings/service-accounts',
MCP_SERVER: '/settings/mcp-server',
} as const;
export default ROUTES;

View File

@@ -157,9 +157,3 @@
.view-all-drawer {
border-radius: 4px;
}
.lightMode {
.ant-table {
background: inherit;
}
}

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

@@ -226,54 +226,3 @@
}
}
}
.lightMode {
.api-quick-filter-left-section {
.api-quick-filters-header {
border-bottom: 1px solid var(--bg-vanilla-300);
}
}
.api-module-right-section {
.toolbar {
border-bottom: 1px solid var(--bg-vanilla-300);
}
}
.no-filtered-domains-message-container {
.no-filtered-domains-message-content {
.no-filtered-domains-message {
.no-domain-title {
color: var(--l1-foreground);
}
.no-domain-subtitle {
color: var(--l2-foreground);
.attribute {
font-family: 'Space Mono';
}
}
}
}
}
.api-monitoring-domain-list-table {
.ant-table {
.ant-table-cell {
color: var(--l1-foreground);
}
.table-row-light {
background: none;
}
.table-row-dark {
background: none;
}
.round-metric-tag {
color: var(--l1-foreground);
}
}
}
}

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,
});

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