Compare commits

..

1 Commits

Author SHA1 Message Date
Manika Malhotra
693401dbbb feat(frontend): adopt reworked @signozhq/ui components across remaining areas 2026-10-08 18:12:17 +05:30
250 changed files with 2169 additions and 2608 deletions

View File

@@ -13,6 +13,7 @@ const config: Config.InitialOptions = {
moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
modulePathIgnorePatterns: ['dist'],
moduleNameMapper: {
'^@signozhq/ui/sonner$': '<rootDir>/src/shims/signozhq-ui-sonner.tsx',
'\\.(png|jpg|jpeg|gif|svg|webp|avif|ico|bmp|tiff)$':
'<rootDir>/__mocks__/fileMock.ts',
// The icon glob module uses `import.meta.glob` (Vite-only); jest can't parse

View File

@@ -52,9 +52,9 @@
"@monaco-editor/react": "^4.7.0",
"@sentry/react": "10.57.0",
"@sentry/vite-plugin": "5.3.0",
"@signozhq/design-tokens": "2.2.1",
"@signozhq/design-tokens": "file:.yalc/@signozhq/design-tokens",
"@signozhq/icons": "0.4.0",
"@signozhq/ui": "0.2.0",
"@signozhq/ui": "file:.yalc/@signozhq/ui",
"@tanstack/react-table": "8.21.3",
"@tanstack/react-virtual": "3.13.22",
"@uiw/codemirror-theme-copilot": "4.23.11",

442
frontend/pnpm-lock.yaml generated
View File

@@ -72,14 +72,14 @@ importers:
specifier: 5.3.0
version: 5.3.0
'@signozhq/design-tokens':
specifier: 2.2.1
version: 2.2.1
specifier: file:.yalc/@signozhq/design-tokens
version: file:.yalc/@signozhq/design-tokens
'@signozhq/icons':
specifier: 0.4.0
version: 0.4.0
'@signozhq/ui':
specifier: 0.2.0
version: 0.2.0(@date-fns/tz@1.4.1)(@emotion/is-prop-valid@1.2.0)(@signozhq/icons@0.4.0)(@types/react-dom@18.0.10)(@types/react@18.0.26)(date-fns@4.1.0)(react-dom@18.2.0(react@18.2.0))(react-router-dom@5.3.4(react@18.2.0))(react-router@6.30.6(react@18.2.0))(react@18.2.0)
specifier: file:.yalc/@signozhq/ui
version: file:.yalc/@signozhq/ui(@date-fns/tz@1.4.1)(@emotion/is-prop-valid@1.2.0)(@signozhq/icons@0.4.0)(@types/react-dom@18.0.10)(@types/react@18.0.26)(date-fns@4.1.0)(react-dom@18.2.0(react@18.2.0))(react-router-dom@5.3.4(react@18.2.0))(react-router@6.30.6(react@18.2.0))(react@18.2.0)
'@tanstack/react-table':
specifier: 8.21.3
version: 8.21.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -2928,9 +2928,6 @@ packages:
'@posthog/core@1.6.0':
resolution: {integrity: sha512-Tbh8UACwbb7jFdDC7wwXHtfNzO+4wKh3VbyMHmp2UBe6w1jliJixexTJNfkqdGZm+ht3M10mcKvGGPnoZ2zLBg==}
'@radix-ui/number@1.1.3':
resolution: {integrity: sha512-Road2bidD0uu/1BGDOWNdPI06g0lIRy6IF9GZcIrDK2KGItfor8IQwQa+yM2ERgHM1MmHxaxpTzk0/Jp42lNfA==}
'@radix-ui/primitive@1.1.7':
resolution: {integrity: sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q==}
@@ -2947,19 +2944,6 @@ packages:
'@types/react-dom':
optional: true
'@radix-ui/react-collection@1.1.15':
resolution: {integrity: sha512-9W+B9NPF0NaaPh/1NJd3+KqsnlLqU9H7T2rvww+fp+T/evVXdNAyYcnfRQZFOjkR1ajQp3yORlqnI8soawLvNA==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/react-compose-refs@1.1.5':
resolution: {integrity: sha512-+48PbAAbq3didjJxa+OaWY2ZwgAKsNiRGyeHKszblZMQ+kcpd9pAaT11cMkGEie0vsOi3QdeTE6d5Fe3Gn61kA==}
peerDependencies:
@@ -2991,15 +2975,6 @@ packages:
'@types/react-dom':
optional: true
'@radix-ui/react-direction@1.1.4':
resolution: {integrity: sha512-5pzg4FGQNpExhnhT2zlrP1wZFaYCd1K0nYWoFAdcYoYK868IEigqMX3B3f8yIoRlAhAeDWciLI6ZdCKHF9P4Vg==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@radix-ui/react-dismissable-layer@1.1.19':
resolution: {integrity: sha512-8g4pfOL9HoKKLWGiypT+dphVqjFfmcXO5GBnhsG6zI+lxAx/8feQpr+1LSN8Re3hiZ+XkLNS4O9ztK11/LzQ6w==}
peerDependencies:
@@ -3114,71 +3089,6 @@ packages:
'@types/react-dom':
optional: true
'@radix-ui/react-progress@1.1.16':
resolution: {integrity: sha512-5XnomAsoZZCY+KNTxbIghpGqPruZvKFNlvcAljVAOdDRDsH4/OZQxhtwo5wdtoDM5R6MhJBb2sPnDuRFep3lzg==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/react-radio-group@1.4.7':
resolution: {integrity: sha512-cgYFEkntCxppHZgtSZ+7vh0wbZQ+IC7PPMw8DSnRG27B6kDd32/Zw0OJt7dGDigCoprMuWHjg2PvUn3PYvPFoQ==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/react-roving-focus@1.1.19':
resolution: {integrity: sha512-V9jI6hDjT7l3jsCQD9bLNvDLM3tH/gdbOTp7Tefp3hbbgCGQoK7tUvrWiRlcoBHIZ809ElXwNQwVo0B98LuTXQ==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/react-select@2.3.7':
resolution: {integrity: sha512-WFGImkmbzcfxeIwq/+4HvRN0pizBwbwQUED4I13ezQsDdfl38ZntN6TmR8XaSzPBqoCToe8rF75j6NPNDSzhbg==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/react-slider@1.4.7':
resolution: {integrity: sha512-mTSLf1GC/C0moWjTbvCM6Qn/gBjvlFt1azuWF2v7MN5C3Zq2U2J2lN3ZEYkpujuOU5Ro7A28wkviSxaKnG0BYg==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/react-slot@1.3.3':
resolution: {integrity: sha512-qx7oqnYbxnK9kYI9m317qmFmEgo6ywqWvbTogdj7cL9p3/yx4M48p7Rnw5z3H890cL/ow/EeWJsuTykeZVXP5Q==}
peerDependencies:
@@ -3188,19 +3098,6 @@ packages:
'@types/react':
optional: true
'@radix-ui/react-tabs@1.1.21':
resolution: {integrity: sha512-UKxJlZid7FVtsk/WTxj4i4uSEgj2Au+KBbS7SQyTlzMhhn+86Cz3tISZdTa87bfEfcuvZezf2ZsxD4xuEKtkog==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/react-use-callback-ref@1.1.4':
resolution: {integrity: sha512-R6OUY2e2fA6Yn6s+VSx5KBV6Nx8LQEhu+cz7LCej18rQ1HLyg9PSC9jP/ZNx0o6FAIK9c0F1kHylzSxKsdlkrQ==}
peerDependencies:
@@ -3228,15 +3125,6 @@ packages:
'@types/react':
optional: true
'@radix-ui/react-use-is-hydrated@0.1.3':
resolution: {integrity: sha512-umO/aJ+82CpOnhDZUTbILCQf7kU/g0iv+oGs/Q8jw7IkhWBzaEP4sA268PhFAJTFetbwp3ICc6ktpI4TqtxcIw==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@radix-ui/react-use-layout-effect@1.1.4':
resolution: {integrity: sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw==}
peerDependencies:
@@ -3246,15 +3134,6 @@ packages:
'@types/react':
optional: true
'@radix-ui/react-use-previous@1.1.4':
resolution: {integrity: sha512-XoSLhbRbqxFtgJoi2fNHA3C6pDlY34x508vUpUGoFZfvePfHXHbE1lC4FYFMnJWgiCRroSTw6fOsXQoVS9RwZg==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@radix-ui/react-use-rect@1.1.4':
resolution: {integrity: sha512-cSOCh6JlkmfjLyNcLiu2nB4v+nm+dkZ+Q5KHWk/soo4U7ZLiEQFKHK9/YmtBHjfCEaU43IBKQOc4/uJmCaiCTQ==}
peerDependencies:
@@ -3273,19 +3152,6 @@ packages:
'@types/react':
optional: true
'@radix-ui/react-visually-hidden@1.2.11':
resolution: {integrity: sha512-NFS86RYYZb4/exihaESBGOpMJFz8MGLAfu3mOBSGByVnVPC9JPASfYubxd/8KbkQK0sYAv8lVQDEQukDX/qXvQ==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/rect@1.1.3':
resolution: {integrity: sha512-JtyZR+mqgBibTo8xea3B6ZRmzZiM/YeVBtUkas6zMuXjAlfIFIW2FgqeM9eLyvEaYX66vr6DJMK+4U6LV0KhNw==}
@@ -3608,14 +3474,14 @@ packages:
'@sideway/pinpoint@2.0.0':
resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==}
'@signozhq/design-tokens@2.2.1':
resolution: {integrity: sha512-ulf6lhWUP6qxqsyemQySUMfOIKRvefvZ5rBRv+wlhOpPfYPk3uatPmPkKEhAjISpX8f9g1Gg8wgRZxUCysf20Q==}
'@signozhq/design-tokens@file:.yalc/@signozhq/design-tokens':
resolution: {directory: .yalc/@signozhq/design-tokens, type: directory}
'@signozhq/icons@0.4.0':
resolution: {integrity: sha512-QctNvNPlQlsefFdIVmSy/P/7a1IcQ3IryKP0KPMqtoqew3q89FGUmFa5IfEJ7Z3CHhtG1zaXwBKqP72QkLyA3g==}
'@signozhq/ui@0.2.0':
resolution: {integrity: sha512-j20ldiOkR150ON0BCDhlq6fXGoPN++7w6e4t2HtM2XMM4buJO7aHzPzNKvDRZ2UUf/LGPULPAW8w6sg6gUVHyw==}
'@signozhq/ui@file:.yalc/@signozhq/ui':
resolution: {directory: .yalc/@signozhq/ui, type: directory}
peerDependencies:
'@signozhq/icons': 0.3.0
react: ^18.2.0
@@ -4985,12 +4851,6 @@ packages:
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
engines: {node: '>=6'}
cmdk@1.1.1:
resolution: {integrity: sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==}
peerDependencies:
react: ^18 || ^19 || ^19.0.0-rc
react-dom: ^18 || ^19 || ^19.0.0-rc
co@4.6.0:
resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}
engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
@@ -7593,12 +7453,6 @@ packages:
neo-async@2.6.2:
resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
next-themes@0.4.6:
resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==}
peerDependencies:
react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc
react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc
no-case@3.0.4:
resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==}
@@ -9093,12 +8947,6 @@ packages:
resolution: {integrity: sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==}
engines: {node: '>=20'}
sonner@2.0.7:
resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==}
peerDependencies:
react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
sort-asc@0.1.0:
resolution: {integrity: sha512-jBgdDd+rQ+HkZF2/OHCmace5dvpos/aWQpcxuyRs9QUbPRnkEJmYVo81PIGpjIdpOcsnJ4rGjStfDHsbn+UVyw==}
engines: {node: '>=0.10.0'}
@@ -10120,7 +9968,7 @@ snapshots:
'@ant-design/cssinjs@1.17.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
'@emotion/hash': 0.8.0
'@emotion/unitless': 0.7.5
classnames: 2.3.2
@@ -10136,7 +9984,7 @@ snapshots:
dependencies:
'@ant-design/colors': 7.0.0
'@ant-design/icons-svg': 4.3.1
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
classnames: 2.3.2
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0
@@ -10144,7 +9992,7 @@ snapshots:
'@ant-design/react-slick@1.0.2(react@18.2.0)':
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
classnames: 2.3.2
json2mq: 0.2.0
react: 18.2.0
@@ -12670,8 +12518,6 @@ snapshots:
dependencies:
cross-spawn: 7.0.6
'@radix-ui/number@1.1.3': {}
'@radix-ui/primitive@1.1.7': {}
'@radix-ui/react-arrow@1.1.15(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
@@ -12683,18 +12529,6 @@ snapshots:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/react-collection@1.1.15(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.5(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-context': 1.2.2(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-primitive': 2.1.10(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-slot': 1.3.3(@types/react@18.0.26)(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
optionalDependencies:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/react-compose-refs@1.1.5(@types/react@18.0.26)(react@18.2.0)':
dependencies:
react: 18.2.0
@@ -12730,12 +12564,6 @@ snapshots:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/react-direction@1.1.4(@types/react@18.0.26)(react@18.2.0)':
dependencies:
react: 18.2.0
optionalDependencies:
'@types/react': 18.0.26
'@radix-ui/react-dismissable-layer@1.1.19(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.7
@@ -12846,101 +12674,6 @@ snapshots:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/react-progress@1.1.16(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@radix-ui/react-context': 1.2.2(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-primitive': 2.1.10(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
optionalDependencies:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/react-radio-group@1.4.7(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.7
'@radix-ui/react-compose-refs': 1.1.5(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-context': 1.2.2(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-direction': 1.1.4(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-presence': 1.1.10(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-primitive': 2.1.10(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-use-controllable-state': 1.2.6(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-use-size': 1.1.4(@types/react@18.0.26)(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
optionalDependencies:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/react-roving-focus@1.1.19(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.7
'@radix-ui/react-collection': 1.1.15(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-compose-refs': 1.1.5(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-context': 1.2.2(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-direction': 1.1.4(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-id': 1.1.4(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-primitive': 2.1.10(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-use-callback-ref': 1.1.4(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-use-controllable-state': 1.2.6(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-use-is-hydrated': 0.1.3(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-use-layout-effect': 1.1.4(@types/react@18.0.26)(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
optionalDependencies:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/react-select@2.3.7(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@radix-ui/number': 1.1.3
'@radix-ui/primitive': 1.1.7
'@radix-ui/react-collection': 1.1.15(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-compose-refs': 1.1.5(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-context': 1.2.2(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-direction': 1.1.4(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-focus-guards': 1.1.6(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-id': 1.1.4(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-popper': 1.3.7(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-portal': 1.1.17(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-presence': 1.1.10(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-primitive': 2.1.10(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-slot': 1.3.3(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-use-callback-ref': 1.1.4(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-use-controllable-state': 1.2.6(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-use-layout-effect': 1.1.4(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-use-previous': 1.1.4(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-visually-hidden': 1.2.11(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
aria-hidden: 1.2.6
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
react-remove-scroll: 2.7.2(@types/react@18.0.26)(react@18.2.0)
optionalDependencies:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/react-slider@1.4.7(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@radix-ui/number': 1.1.3
'@radix-ui/primitive': 1.1.7
'@radix-ui/react-collection': 1.1.15(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-compose-refs': 1.1.5(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-context': 1.2.2(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-direction': 1.1.4(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-primitive': 2.1.10(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-use-controllable-state': 1.2.6(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-use-layout-effect': 1.1.4(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-use-previous': 1.1.4(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-use-size': 1.1.4(@types/react@18.0.26)(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
optionalDependencies:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/react-slot@1.3.3(@types/react@18.0.26)(react@18.2.0)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.5(@types/react@18.0.26)(react@18.2.0)
@@ -12948,22 +12681,6 @@ snapshots:
optionalDependencies:
'@types/react': 18.0.26
'@radix-ui/react-tabs@1.1.21(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.7
'@radix-ui/react-context': 1.2.2(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-direction': 1.1.4(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-id': 1.1.4(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-presence': 1.1.10(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-primitive': 2.1.10(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-use-controllable-state': 1.2.6(@types/react@18.0.26)(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
optionalDependencies:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/react-use-callback-ref@1.1.4(@types/react@18.0.26)(react@18.2.0)':
dependencies:
react: 18.2.0
@@ -12986,24 +12703,12 @@ snapshots:
optionalDependencies:
'@types/react': 18.0.26
'@radix-ui/react-use-is-hydrated@0.1.3(@types/react@18.0.26)(react@18.2.0)':
dependencies:
react: 18.2.0
optionalDependencies:
'@types/react': 18.0.26
'@radix-ui/react-use-layout-effect@1.1.4(@types/react@18.0.26)(react@18.2.0)':
dependencies:
react: 18.2.0
optionalDependencies:
'@types/react': 18.0.26
'@radix-ui/react-use-previous@1.1.4(@types/react@18.0.26)(react@18.2.0)':
dependencies:
react: 18.2.0
optionalDependencies:
'@types/react': 18.0.26
'@radix-ui/react-use-rect@1.1.4(@types/react@18.0.26)(react@18.2.0)':
dependencies:
'@radix-ui/rect': 1.1.3
@@ -13018,20 +12723,11 @@ snapshots:
optionalDependencies:
'@types/react': 18.0.26
'@radix-ui/react-visually-hidden@1.2.11(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@radix-ui/react-primitive': 2.1.10(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
optionalDependencies:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/rect@1.1.3': {}
'@rc-component/color-picker@1.4.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
'@ctrl/tinycolor': 3.6.1
classnames: 2.3.2
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -13051,7 +12747,7 @@ snapshots:
'@rc-component/mutate-observer@1.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
classnames: 2.3.2
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0
@@ -13067,7 +12763,7 @@ snapshots:
'@rc-component/tour@1.10.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
'@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@rc-component/trigger': 1.18.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
classnames: 2.3.2
@@ -13077,7 +12773,7 @@ snapshots:
'@rc-component/trigger@1.18.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
'@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
classnames: 2.3.2
rc-motion: 2.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -13327,41 +13023,33 @@ snapshots:
'@sideway/pinpoint@2.0.0': {}
'@signozhq/design-tokens@2.2.1': {}
'@signozhq/design-tokens@file:.yalc/@signozhq/design-tokens': {}
'@signozhq/icons@0.4.0': {}
'@signozhq/ui@0.2.0(@date-fns/tz@1.4.1)(@emotion/is-prop-valid@1.2.0)(@signozhq/icons@0.4.0)(@types/react-dom@18.0.10)(@types/react@18.0.26)(date-fns@4.1.0)(react-dom@18.2.0(react@18.2.0))(react-router-dom@5.3.4(react@18.2.0))(react-router@6.30.6(react@18.2.0))(react@18.2.0)':
'@signozhq/ui@file:.yalc/@signozhq/ui(@date-fns/tz@1.4.1)(@emotion/is-prop-valid@1.2.0)(@signozhq/icons@0.4.0)(@types/react-dom@18.0.10)(@types/react@18.0.26)(date-fns@4.1.0)(react-dom@18.2.0(react@18.2.0))(react-router-dom@5.3.4(react@18.2.0))(react-router@6.30.6(react@18.2.0))(react@18.2.0)':
dependencies:
'@base-ui/react': 1.7.0(@date-fns/tz@1.4.1)(@types/react@18.0.26)(date-fns@4.1.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@chenglou/pretext': 0.0.8
'@radix-ui/react-dialog': 1.1.23(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-icons': 1.3.2(react@18.2.0)
'@radix-ui/react-popover': 1.1.23(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-progress': 1.1.16(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-radio-group': 1.4.7(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-select': 2.3.7(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-slider': 1.4.7(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-slot': 1.3.3(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-tabs': 1.1.21(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@signozhq/icons': 0.4.0
'@tanstack/react-table': 8.21.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@tanstack/react-virtual': 3.14.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@types/lodash-es': 4.17.12
clsx: 2.1.1
cmdk: 1.1.1(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
copy-text-to-clipboard: 3.2.2
dayjs: 1.11.23
lodash-es: 4.18.1
motion: 11.18.2(@emotion/is-prop-valid@1.2.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
next-themes: 0.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
nuqs: 2.9.6(react-router-dom@5.3.4(react@18.2.0))(react-router@6.30.6(react@18.2.0))(react@18.2.0)
react: 18.2.0
react-compiler-runtime: 1.0.0(react@18.2.0)
react-day-picker: 9.9.0(react@18.2.0)
react-dom: 18.2.0(react@18.2.0)
react-resizable-panels: 4.12.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
sonner: 2.0.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
transitivePeerDependencies:
- '@date-fns/tz'
- '@emotion/is-prop-valid'
@@ -14638,7 +14326,7 @@ snapshots:
better-xlsx@0.7.6:
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
jszip: 3.10.1
kind-of: 6.0.3
@@ -14675,7 +14363,7 @@ snapshots:
broadcast-channel@3.7.0:
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
detect-node: 2.1.0
js-sha3: 0.8.0
microseconds: 0.2.0
@@ -14893,18 +14581,6 @@ snapshots:
clsx@2.1.1: {}
cmdk@1.1.1(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@radix-ui/react-compose-refs': 1.1.5(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-dialog': 1.1.23(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-id': 1.1.4(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-primitive': 2.1.10(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
transitivePeerDependencies:
- '@types/react'
- '@types/react-dom'
co@4.6.0: {}
codemirror@6.0.1:
@@ -17528,7 +17204,7 @@ snapshots:
match-sorter@6.3.1:
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
remove-accents: 0.4.2
math-intrinsics@1.1.0: {}
@@ -18044,11 +17720,6 @@ snapshots:
neo-async@2.6.2: {}
next-themes@0.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
no-case@3.0.4:
dependencies:
lower-case: 2.0.2
@@ -18696,7 +18367,7 @@ snapshots:
rc-cascader@3.20.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
array-tree-filter: 2.1.0
classnames: 2.3.2
rc-select: 14.10.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -18707,7 +18378,7 @@ snapshots:
rc-checkbox@3.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
classnames: 2.3.2
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0
@@ -18715,7 +18386,7 @@ snapshots:
rc-collapse@3.7.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
classnames: 2.3.2
rc-motion: 2.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -18724,7 +18395,7 @@ snapshots:
rc-dialog@9.3.4(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
'@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
classnames: 2.3.2
rc-motion: 2.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -18734,7 +18405,7 @@ snapshots:
rc-drawer@6.5.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
'@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
classnames: 2.3.2
rc-motion: 2.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -18744,7 +18415,7 @@ snapshots:
rc-dropdown@4.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
'@rc-component/trigger': 1.18.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
classnames: 2.3.2
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -18753,7 +18424,7 @@ snapshots:
rc-field-form@1.40.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
async-validator: 4.2.5
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0
@@ -18761,7 +18432,7 @@ snapshots:
rc-image@7.3.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
'@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
classnames: 2.3.2
rc-dialog: 9.3.4(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -18772,7 +18443,7 @@ snapshots:
rc-input-number@8.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
'@rc-component/mini-decimal': 1.0.1
classnames: 2.3.2
rc-input: 1.3.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -18782,7 +18453,7 @@ snapshots:
rc-input@1.3.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
classnames: 2.3.2
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0
@@ -18790,7 +18461,7 @@ snapshots:
rc-mentions@2.9.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
'@rc-component/trigger': 1.18.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
classnames: 2.3.2
rc-input: 1.3.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -18802,7 +18473,7 @@ snapshots:
rc-menu@9.12.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
'@rc-component/trigger': 1.18.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
classnames: 2.3.2
rc-motion: 2.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -18813,7 +18484,7 @@ snapshots:
rc-motion@2.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
classnames: 2.3.2
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0
@@ -18821,7 +18492,7 @@ snapshots:
rc-notification@5.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
classnames: 2.3.2
rc-motion: 2.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -18830,7 +18501,7 @@ snapshots:
rc-overflow@1.3.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
classnames: 2.3.2
rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -18839,7 +18510,7 @@ snapshots:
rc-pagination@3.7.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
classnames: 2.3.2
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0
@@ -18847,7 +18518,7 @@ snapshots:
rc-picker@3.14.6(date-fns@4.1.0)(dayjs@1.11.20)(moment@2.30.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
'@rc-component/trigger': 1.18.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
classnames: 2.3.2
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -18860,7 +18531,7 @@ snapshots:
rc-progress@3.5.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
classnames: 2.3.2
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0
@@ -18868,7 +18539,7 @@ snapshots:
rc-rate@2.12.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
classnames: 2.3.2
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0
@@ -18876,7 +18547,7 @@ snapshots:
rc-resize-observer@1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
classnames: 2.3.2
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0
@@ -18885,7 +18556,7 @@ snapshots:
rc-segmented@2.2.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
classnames: 2.3.2
rc-motion: 2.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -18906,7 +18577,7 @@ snapshots:
rc-slider@10.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
classnames: 2.3.2
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0
@@ -18914,7 +18585,7 @@ snapshots:
rc-steps@6.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
classnames: 2.3.2
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0
@@ -18922,7 +18593,7 @@ snapshots:
rc-switch@4.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
classnames: 2.3.2
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0
@@ -18930,7 +18601,7 @@ snapshots:
rc-table@7.35.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
'@rc-component/context': 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
classnames: 2.3.2
rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -18941,7 +18612,7 @@ snapshots:
rc-tabs@12.13.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
classnames: 2.3.2
rc-dropdown: 4.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
rc-menu: 9.12.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -18953,7 +18624,7 @@ snapshots:
rc-textarea@1.5.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
classnames: 2.3.2
rc-input: 1.3.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -18963,7 +18634,7 @@ snapshots:
rc-tooltip@6.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
'@rc-component/trigger': 1.18.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
classnames: 2.3.2
react: 18.2.0
@@ -18971,7 +18642,7 @@ snapshots:
rc-tree-select@5.15.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
classnames: 2.3.2
rc-select: 14.10.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
rc-tree: 5.8.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -18981,7 +18652,7 @@ snapshots:
rc-tree@5.8.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
classnames: 2.3.2
rc-motion: 2.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -18991,7 +18662,7 @@ snapshots:
rc-upload@4.3.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
classnames: 2.3.2
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0
@@ -18999,14 +18670,14 @@ snapshots:
rc-util@5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
react-is: 18.3.1
rc-virtual-list@3.11.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
classnames: 2.3.2
rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -19297,7 +18968,7 @@ snapshots:
react-router@5.3.4(react@18.2.0):
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
history: 4.10.1
hoist-non-react-statics: 3.3.2
loose-envify: 1.4.0
@@ -19834,11 +19505,6 @@ snapshots:
ansi-styles: 6.2.3
is-fullwidth-code-point: 5.1.0
sonner@2.0.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
sort-asc@0.1.0: {}
sort-desc@0.1.1: {}

View File

@@ -15,6 +15,5 @@
}
.divider {
--divider-color: var(--l1-border);
--divider-margin: 10px 0 16px 0;
--divider-border: var(--l1-border);
}

View File

@@ -28,7 +28,11 @@ function AlertBreadcrumb({
items={breadcrumbItems}
data-testid={testId}
/>
{showDivider && <Divider className={styles.divider} />}
{showDivider && (
<div className={styles.divider}>
<Divider spacing="10px 16px" />
</div>
)}
</>
);
}

View File

@@ -56,22 +56,15 @@ function ProgressRender(item: string | number): JSX.Element {
const percent = Number(Number(item).toFixed(1));
return (
<div className="progress-container">
<Progress
percent={percent}
strokeLinecap="butt"
showInfo
strokeColor={((): string => {
const cpuPercent = percent;
if (cpuPercent >= 90) {
return Color.BG_SAKURA_500;
<div className="progress-bar">
<Progress
percent={percent}
showInfo
color={
percent >= 90 ? 'highlight-danger' : percent >= 60 ? 'warning' : 'success'
}
if (cpuPercent >= 60) {
return Color.BG_AMBER_500;
}
return Color.BG_FOREST_500;
})()}
className="progress-bar"
/>
/>
</div>
</div>
);
}

View File

@@ -72,7 +72,7 @@ export default function CeleryTaskDetail({
endTime ? `- ${formatTimestamp(endTime)}` : ''
}`}
</Typography.Text>
<Divider type="vertical" />
<Divider orientation="vertical" />
<Typography.Text className="subtitle">{taskData.value}</Typography.Text>
</div>
</div>

View File

@@ -42,6 +42,16 @@
gap: var(--spacing-1);
margin-bottom: var(--spacing-4);
// Input restyle (the old .create-sa-form__input class, as --input-* tokens)
--input-foreground: var(--l1-foreground);
--input-background: var(--l2-background);
--input-border: var(--l1-border);
--input-font-size: var(--paragraph-base-400-font-size);
--input-border-radius: 2px;
--input-placeholder: var(--l3-foreground);
--input-placeholder-opacity: 1;
--input-focus-ring: var(--primary);
> label {
font-size: var(--paragraph-base-400-font-size);
font-weight: var(--paragraph-base-400-font-weight);
@@ -50,25 +60,6 @@
}
}
&__input {
height: 32px;
color: var(--l1-foreground);
background-color: var(--l2-background);
border-color: var(--l1-border);
font-size: var(--paragraph-base-400-font-size);
border-radius: 2px;
width: 100%;
&::placeholder {
color: var(--l3-foreground);
}
&:focus {
border-color: var(--primary);
box-shadow: none;
}
}
&__error {
font-size: var(--paragraph-small-400-font-size);
color: var(--destructive);

View File

@@ -116,11 +116,10 @@ function CreateServiceAccountModal(): JSX.Element {
<Input
id="sa-name"
placeholder="Enter a name"
className="create-sa-form__input"
value={field.value}
onChange={field.onChange}
onBlur={field.onBlur}
data-testid="create-sa-name-input"
testId="create-sa-name-input"
/>
)}
/>

View File

@@ -58,7 +58,7 @@ describe('CreateServiceAccountModal', () => {
// The form only renders once the create check resolves, and the name field
// registers its `required` rule on mount, so the empty-form invalid state
// settles a tick later.
await screen.findByTestId('create-sa-name-input');
await screen.findByTestId('create-sa-name-input-field');
await waitFor(() =>
expect(screen.getByTestId('create-sa-submit-btn')).toHaveAttribute(
@@ -72,7 +72,7 @@ describe('CreateServiceAccountModal', () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
renderModal();
const nameInput = await screen.findByTestId('create-sa-name-input');
const nameInput = await screen.findByTestId('create-sa-name-input-field');
const submitBtn = await screen.findByTestId('create-sa-submit-btn');
await user.type(nameInput, 'test');
@@ -90,7 +90,7 @@ describe('CreateServiceAccountModal', () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
renderModal();
const nameInput = await screen.findByTestId('create-sa-name-input');
const nameInput = await screen.findByTestId('create-sa-name-input-field');
await user.type(nameInput, 'Deploy Bot');
const submitBtn = screen.getByTestId('create-sa-submit-btn');
@@ -128,7 +128,7 @@ describe('CreateServiceAccountModal', () => {
renderModal();
const nameInput = await screen.findByTestId<HTMLInputElement>(
'create-sa-name-input',
'create-sa-name-input-field',
);
await user.type(nameInput, 'Deploy Bot');
const submitBtn = screen.getByTestId('create-sa-submit-btn');
@@ -160,7 +160,7 @@ describe('CreateServiceAccountModal', () => {
renderModal();
const nameInput = await screen.findByTestId('create-sa-name-input');
const nameInput = await screen.findByTestId('create-sa-name-input-field');
await user.type(nameInput, 'Dupe Bot');
const submitBtn = screen.getByTestId('create-sa-submit-btn');
@@ -209,7 +209,9 @@ describe('CreateServiceAccountModal', () => {
screen.findByText(/is not authorized to perform/i),
).resolves.toBeInTheDocument();
expect(screen.queryByTestId('create-sa-name-input')).not.toBeInTheDocument();
expect(
screen.queryByTestId('create-sa-name-input-field'),
).not.toBeInTheDocument();
expect(
screen.getByTestId('create-service-account-modal'),
).toBeInTheDocument();
@@ -244,7 +246,7 @@ describe('CreateServiceAccountModal', () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
renderModal();
const nameInput = await screen.findByTestId('create-sa-name-input');
const nameInput = await screen.findByTestId('create-sa-name-input-field');
await user.type(nameInput, 'Bot');
await user.clear(nameInput);

View File

@@ -34,34 +34,19 @@ $item-spacing: 8px;
@include flex-center;
gap: 6px;
width: -webkit-fill-available;
}
&__input {
@include text-style-base;
width: 100%;
background: transparent;
border: none;
border-radius: 0;
box-shadow: none;
outline: none;
height: auto;
color: var(--l1-foreground);
font-size: 14px;
line-height: 20px;
letter-spacing: -0.07px;
padding: 0;
&:focus,
&:focus-visible,
&:hover {
border: none;
box-shadow: none;
outline: none;
}
&::placeholder {
color: var(--l2-foreground);
}
// Restyle the unstyled search Input (old .timezone-picker__input rules,
// as --input-* tokens picked up by the Input frame inside)
--input-height: auto;
--input-padding: 0;
--input-border-width: 0;
--input-border-radius: 0;
--input-foreground: var(--l1-foreground);
--input-font-size: 14px;
--input-line-height: 20px;
--input-letter-spacing: -0.07px;
--input-placeholder: var(--l2-foreground);
--input-placeholder-opacity: 1;
}
&__esc-key {

View File

@@ -65,7 +65,8 @@ function SearchBar({
/>
<Input
type="text"
className="timezone-picker__input"
variant="unstyled"
noFocusRing
placeholder="Search timezones..."
value={value}
onChange={(e): void => onChange(e.target.value)}

View File

@@ -471,20 +471,19 @@ function EditMemberDrawer({
<label className="edit-member-drawer__label" htmlFor="member-name">
Name
</label>
<Tooltip title={isRootUser ? ROOT_USER_TOOLTIP : undefined}>
<Input
id="member-name"
value={localDisplayName}
onChange={(e): void => {
setLocalDisplayName(e.target.value);
setSaveErrors((prev) =>
prev.filter((err) => err.context !== 'Name update'),
);
}}
placeholder="Enter name"
disabled={isRootUser || isDeleted}
/>
</Tooltip>
<Input
id="member-name"
value={localDisplayName}
onChange={(e): void => {
setLocalDisplayName(e.target.value);
setSaveErrors((prev) =>
prev.filter((err) => err.context !== 'Name update'),
);
}}
placeholder="Enter name"
disabled={isRootUser || isDeleted}
disabledTooltip={isRootUser ? ROOT_USER_TOOLTIP : undefined}
/>
</div>
<div className="edit-member-drawer__field">

View File

@@ -32,12 +32,16 @@
}
}
// Wraps the search Input; restyles it via its --input-* tokens
// (the Input is size="large" for the 40px height).
.searchInput {
background-color: var(--l1-background);
height: 40px;
border-radius: 0;
border-left: none;
border-right: none;
--input-background: var(--l1-background);
--input-border-radius: 0;
[data-slot='input'] {
border-left: none;
border-right: none;
}
}
.section {

View File

@@ -140,10 +140,10 @@ function FieldsSelectorContent({
<X className={styles.closeIcon} size={16} onClick={onClose} />
</div>
<section>
<section className={styles.searchInput}>
<Input
className={styles.searchInput}
type="text"
size="large"
value={inputValue}
placeholder="Search for a field..."
onChange={handleInputChange}

View File

@@ -30,63 +30,41 @@
font-weight: var(--font-weight-light);
}
// Wrapper around the Input; restyles the frame inside via --input-* tokens.
.input {
flex: 1;
min-width: 150px;
font-family: 'Space Mono', monospace !important;
--input-border-radius: 0px;
border: 1px solid var(--input-with-label-border-color, var(--l2-border));
background: var(--input-with-label-background-color, var(--l2-background));
color: var(--input-with-label-color, var(--l2-foreground));
font-size: 12px !important;
line-height: 25px;
position: relative;
--input-font-family: 'Space Mono', monospace;
--input-font-size: 12px;
--input-border-radius: 0px;
--input-border: var(--input-with-label-border-color, var(--l2-border));
--input-background: var(
--input-with-label-background-color,
var(--l2-background)
);
--input-foreground: var(--input-with-label-color, var(--l2-foreground));
--input-placeholder: var(--input-with-label-color, var(--l3-foreground));
--input-placeholder-opacity: 1;
&:hover,
&:focus {
z-index: 1;
}
.ant-select-selector {
position: relative;
border-radius: inherit;
}
.ant-select:hover .ant-select-selector,
.ant-select-focused .ant-select-selector {
&:focus-within {
z-index: 1;
}
&.input__has-label-after {
margin-left: -1px;
.ant-select-selector {
margin-left: -1px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}
&.input__has-close-button {
.ant-select-selector {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
~ .close-btn {
margin-left: -1px;
}
}
&::placeholder {
color: var(--input-with-label-color, var(--l3-foreground)) !important;
font-size: 12px !important;
}
&[type='number']::-webkit-inner-spin-button,
&[type='number']::-webkit-outer-spin-button {
input[type='number']::-webkit-inner-spin-button,
input[type='number']::-webkit-outer-spin-button {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
@@ -109,17 +87,8 @@
}
&.labelAfter {
.input {
border-radius: 2px;
border: 1px solid var(--input-with-label-border-color, var(--l2-border));
background: var(--input-with-label-background-color, var(--l2-background));
border-top-right-radius: 0px;
border-bottom-right-radius: 0px;
.ant-select-selector {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.input [data-slot='input'] {
border-radius: 2px 0 0 2px;
}
.label {

View File

@@ -46,19 +46,23 @@ function InputWithLabel({
})}
>
{!labelAfter && <Typography.Text className="label">{label}</Typography.Text>}
<Input
<div
className={cx('input', {
'input__has-label-after': !labelAfter,
'input__has-close-button': !!onClose,
})}
placeholder={placeholder}
type={type}
value={inputValue}
onChange={handleChange}
disabled={disabled}
name={label.toLowerCase()}
data-testid={`input-${label}`}
/>
>
<Input
placeholder={placeholder}
type={type}
value={inputValue}
onChange={handleChange}
disabled={disabled}
disabledTooltip={undefined}
name={label.toLowerCase()}
testId={`input-${label}`}
/>
</div>
{labelAfter && <Typography.Text className="label">{label}</Typography.Text>}
{onClose && (
<Button

View File

@@ -59,18 +59,6 @@
--invite-members-field-background,
var(--l2-background)
);
--input-hover-background: var(
--invite-members-field-background,
var(--l2-background)
);
--input-focus-background: var(
--invite-members-field-background,
var(--l2-background)
);
--input-disabled-background: var(
--invite-members-field-background,
var(--l2-background)
);
input::placeholder {
color: var(--l3-foreground);

View File

@@ -1,4 +1,4 @@
import { CircleAlert, Plus, Trash2 } from '@signozhq/icons';
import { CircleAlert, Plus, SolidCheckCircle2, Trash2 } from '@signozhq/icons';
import { Button } from '@signozhq/ui/button';
import { Callout } from '@signozhq/ui/callout';
import { Input } from '@signozhq/ui/input';
@@ -97,7 +97,7 @@ function InviteMembers({
onChange={(e): void => updateEmail(row.id, e.target.value)}
name={`invite-email-${row.id}`}
autoComplete="email"
data-testid={`invite-email-${row.id}`}
testId={`invite-email-${row.id}`}
/>
{emailValidity[row.id] === false && row.email.trim() !== '' && (
<Typography.Text size="small" className={styles.errorText}>
@@ -152,61 +152,62 @@ function InviteMembers({
</div>
{hasValidationErrors && (
<Callout
type="error"
size="small"
showIcon
icon={<CircleAlert size={12} />}
className={styles.callout}
data-testid="invite-validation-error"
>
{getValidationErrorMessage()}
</Callout>
<div className={styles.callout}>
<Callout
color="danger"
size="sm"
icon={<CircleAlert />}
testId="invite-validation-error"
>
{getValidationErrorMessage()}
</Callout>
</div>
)}
{hasResults && hasFailures && (
<Callout
type="error"
size="small"
showIcon
icon={<CircleAlert size={12} />}
className={styles.callout}
data-testid="invite-api-error"
>
<div className={styles.results}>
{hasSuccesses && (
<div className={styles.callout}>
<Callout
color="danger"
size="sm"
icon={<CircleAlert />}
testId="invite-api-error"
>
<div className={styles.results}>
{hasSuccesses && (
<Typography.Text size="small">
{successResults.length} invite(s) sent successfully.
</Typography.Text>
)}
<Typography.Text size="small">
{successResults.length} invite(s) sent successfully.
{failedResults.length} invite(s) failed:
</Typography.Text>
)}
<Typography.Text size="small">
{failedResults.length} invite(s) failed:
</Typography.Text>
<ul className={styles.resultsList}>
{failedResults.map((result) => (
<li key={result.email}>
<Typography.Text size="small">
{result.email}: {result.error}
</Typography.Text>
</li>
))}
</ul>
</div>
</Callout>
<ul className={styles.resultsList}>
{failedResults.map((result) => (
<li key={result.email}>
<Typography.Text size="small">
{result.email}: {result.error}
</Typography.Text>
</li>
))}
</ul>
</div>
</Callout>
</div>
)}
{hasResults && !hasFailures && hasSuccesses && (
<Callout
type="success"
size="small"
showIcon
className={styles.callout}
data-testid="invite-success"
>
<Typography.Text size="small">
{successResults.length} invite(s) sent successfully!
</Typography.Text>
</Callout>
<div className={styles.callout}>
<Callout
color="success"
size="sm"
icon={<SolidCheckCircle2 />}
testId="invite-success"
>
<Typography.Text size="small">
{successResults.length} invite(s) sent successfully!
</Typography.Text>
</Callout>
</div>
)}
{renderFooter?.({

View File

@@ -12,11 +12,6 @@
gap: 8px;
}
.divider {
height: 16px;
margin: 0;
}
.timestamp {
font-family: 'Geist Mono', monospace;
font-size: var(--font-size-sm);

View File

@@ -76,7 +76,7 @@ function LogDetailsHeader({
return (
<div className={styles.header} data-log-detail-ignore="true">
<div className={styles.leftSection}>
<Divider type="vertical" className={styles.divider} />
<Divider orientation="vertical" height={16} spacing={0} />
<Typography.Text
className={styles.timestamp}
data-testid="log-details-header-timestamp"

View File

@@ -202,46 +202,19 @@
.max-lines-per-row-input {
display: flex;
.ant-input-number-handler-wrap {
display: none;
}
--input-height: 26px;
--input-border-radius: 0;
--input-border: var(--l1-border);
.ant-input-number {
[data-testid='max-lines-per-row-field'] {
min-width: 36px;
width: auto;
border-right: none;
border-left: none;
border-top: 1px solid var(--l1-border);
border-bottom: 1px solid var(--l1-border);
text-align: center;
height: 26px;
border-radius: 0;
&:active,
&:focus {
border: none;
box-shadow: none;
}
}
.ant-input-number-focused {
box-shadow: none !important;
}
.ant-input-number-input-wrap {
input {
text-align: center;
font-size: 13px;
&:active,
&:focus {
border: none;
}
}
&:active,
&:focus {
border: none;
}
}

View File

@@ -1,5 +1,6 @@
import { useCallback, useEffect, useState } from 'react';
import { Button, InputNumber, Popover, Tooltip } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Popover, Tooltip } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import cx from 'classnames';
import { LogViewMode } from 'container/OptionsMenu/types';
@@ -207,11 +208,14 @@ function OptionsMenu({
{' '}
<Minus size={12} />{' '}
</button>
<InputNumber
<Input.Number
min={1}
max={10}
value={maxLinesPerRow}
onChange={handleLinesPerRowChange}
controls={false}
noFocusRing
testId="max-lines-per-row-field"
/>
<button
type="button"

View File

@@ -68,11 +68,7 @@
// Meant to fix the query builder colors
--input-background: var(--l2-background);
--input-hover-background: var(--l2-background);
--input-focus-background: var(--l2-background);
--input-border-color: var(--l2-border);
--input-hover-border-color: var(--internal-ant-border-color-hover);
--input-focus-border-color: var(--internal-ant-border-color-hover);
}
&-aggregation-container {

View File

@@ -168,7 +168,7 @@ describe('QueryBuilderV2 + QueryV2 - base render', () => {
expect(limitInput).toBeInTheDocument();
expect(limitInput).toHaveAttribute('type', 'number');
expect(limitInput).toHaveAttribute('name', 'limit');
expect(limitInput).toHaveAttribute('data-testid', 'input-Limit');
expect(limitInput).toHaveAttribute('data-testid', 'input-Limit-field');
});
it('Cmd+Enter on an input triggers handleRunQuery via container handler', async () => {

View File

@@ -159,7 +159,7 @@ describe('QueryAddOns', () => {
/>,
);
const input = screen.getByTestId('input-Limit') as HTMLInputElement;
const input = screen.getByTestId('input-Limit-field') as HTMLInputElement;
expect(screen.getByTestId('limit-content')).toBeInTheDocument();
expect(input.value).toBe('5');
@@ -185,7 +185,9 @@ describe('QueryAddOns', () => {
);
expect(screen.getByTestId('order-by-content')).toBeInTheDocument();
const limitInput = screen.getByTestId('input-Limit') as HTMLInputElement;
const limitInput = screen.getByTestId(
'input-Limit-field',
) as HTMLInputElement;
expect(screen.getByTestId('limit-content')).toBeInTheDocument();
expect(limitInput.value).toBe('7');
});

View File

@@ -6,18 +6,15 @@
border-bottom: 1px solid var(--l1-border);
.search {
input {
--input-background: var(--l2-background);
--input-hover-background: var(--l2-background);
--input-focus-background: var(--l2-background);
&::placeholder {
color: var(--l3-foreground);
}
--input-font-size: 14px;
--input-border-color: var(--l1-border);
--input-focus-border-color: var(--primary-background);
--input-focus-outline-width: 0;
--input-focus-outline-offset: 0;
// Set on the wrapper so the Input frame inside picks them up.
--input-background: var(--l2-background);
--input-font-size: 14px;
--input-border-color: var(--l1-border);
--input-focus-ring-color: var(--primary-background);
--input-focus-outline-offset: 0;
input::placeholder {
color: var(--l3-foreground);
}
}

View File

@@ -116,6 +116,7 @@ export default function CheckboxFilter(props: ICheckboxProps): JSX.Element {
placeholder="Filter values"
onChange={(e): void => setSearchTextDebounced(e.target.value)}
disabled={isFilterDisabled}
disabledTooltip={FILTER_DISABLED_REASON}
/>
</section>
)}

View File

@@ -46,10 +46,6 @@
.search {
--input-background: var(--l2-background);
--input-hover-background: var(--l2-background);
--input-focus-background: var(--l2-background);
--input-border-color: var(--l2-border);
--input-focus-border-color: var(--l2-border);
}
.searchSpinner {

View File

@@ -19,7 +19,9 @@ import { NON_SELECTED_OPERATORS } from '../checkboxFilterQuery';
import useActiveQueryIndex from 'components/QuickFilters/hooks/useActiveQueryIndex';
import useCheckboxDisclosure from '../useCheckboxDisclosure';
import useCheckboxFilterActions from '../useCheckboxFilterActions';
import useCheckboxFilterState from '../useCheckboxFilterState';
import useCheckboxFilterState, {
FILTER_DISABLED_REASON,
} from '../useCheckboxFilterState';
import { useFieldValues } from './useFieldValues';
import { useExistingQuery } from './useExistingQuery';
import { isKeyMatch } from '../utils';
@@ -195,7 +197,8 @@ export default function CheckboxFilterV2(
placeholder="Filter values"
onChange={(e): void => setSearchTextDebounced(e.target.value)}
disabled={isFilterDisabled}
data-testid="checkbox-filter-search"
disabledTooltip={FILTER_DISABLED_REASON}
testId="checkbox-filter-search"
suffix={
isFetching ? (
<LoaderCircle

View File

@@ -61,7 +61,7 @@ describe('CheckboxFilterV2 - interactions', () => {
expect(screen.getByTestId('checkbox-value-row-staging')).toBeInTheDocument();
await user.click(screen.getByTestId('checkbox-filter-search-toggle'));
const searchInput = screen.getByTestId('checkbox-filter-search');
const searchInput = screen.getByTestId('checkbox-filter-search-field');
await user.type(searchInput, 'prod');
await waitFor(() => {
@@ -145,7 +145,7 @@ describe('CheckboxFilterV2 - interactions', () => {
expect(screen.getByTestId('section-divider-related')).toBeInTheDocument();
await user.click(screen.getByTestId('checkbox-filter-search-toggle'));
const searchInput = screen.getByTestId('checkbox-filter-search');
const searchInput = screen.getByTestId('checkbox-filter-search-field');
await user.type(searchInput, 'prod');
await waitFor(() => {
@@ -195,7 +195,7 @@ describe('CheckboxFilterV2 - interactions', () => {
await screen.findByTestId('checkbox-value-row-prod');
await user.click(screen.getByTestId('checkbox-filter-search-toggle'));
const searchInput = screen.getByTestId('checkbox-filter-search');
const searchInput = screen.getByTestId('checkbox-filter-search-field');
await user.type(searchInput, 'prod');
await waitFor(() => {
@@ -240,7 +240,7 @@ describe('CheckboxFilterV2 - interactions', () => {
await screen.findByTestId('checkbox-value-row-prod');
await user.click(screen.getByTestId('checkbox-filter-search-toggle'));
const searchInput = screen.getByTestId('checkbox-filter-search');
const searchInput = screen.getByTestId('checkbox-filter-search-field');
await user.type(searchInput, 'xyz-no-match');
await waitFor(() => {
@@ -348,7 +348,7 @@ describe('CheckboxFilterV2 - interactions', () => {
await screen.findByTestId('checkbox-value-row-pod-a-v1');
await user.click(screen.getByTestId('checkbox-filter-search-toggle'));
const searchInput = screen.getByTestId('checkbox-filter-search');
const searchInput = screen.getByTestId('checkbox-filter-search-field');
await user.type(searchInput, 'pod-a');
// After search, both sections should still appear with filtered results

View File

@@ -111,7 +111,7 @@ describe('CheckboxFilterV2 - states', () => {
await screen.findByTestId('checkbox-value-row-production');
await user.click(screen.getByTestId('checkbox-filter-search-toggle'));
const searchInput = screen.getByTestId('checkbox-filter-search');
const searchInput = screen.getByTestId('checkbox-filter-search-field');
await user.type(searchInput, 'prod');
await waitFor(() => {

View File

@@ -8,7 +8,7 @@ import {
useState,
} from 'react';
import { Input } from 'antd';
import { Slider } from '@signozhq/ui/slider';
import { Slider, type SliderRangeValue } from '@signozhq/ui/slider';
import { getMs } from 'utils/timeUtils';
import useDebouncedFn from 'hooks/useDebouncedFunction';
@@ -90,13 +90,13 @@ export function DurationSection(props: DurationProps): JSX.Element {
debouncedFunction(min, max);
};
const onRangeHandler = (value: number | number[]): void => {
const [min, max] = value as number[];
const onRangeHandler = (value: SliderRangeValue): void => {
const [min, max] = value;
updateDurationFilter(min.toString(), max.toString());
};
const TipComponent = useCallback(
(value: number) => <div>{`${value.toString()}ms`}</div>,
const formatTooltipValue = useCallback(
(value: number): string => `${value.toString()}ms`,
[],
);
@@ -125,13 +125,14 @@ export function DurationSection(props: DurationProps): JSX.Element {
/>
</div>
<div className="duration-input-slider">
<Slider
<Slider.Range
min={0}
max={100000}
range
tooltip={{ formatter: TipComponent }}
color="primary"
tooltip
formatValue={formatTooltipValue}
onChange={(value): void => {
const [min, max] = value as number[];
const [min, max] = value;
onRangeSliderHandler([String(min), String(max)]);
}}
onAfterChange={onRangeHandler}

View File

@@ -55,8 +55,7 @@
min-width: 70px;
}
.sync-tag,
.select-box {
.sync-tag {
display: flex;
padding: 5px 9px;
flex-direction: column;
@@ -77,17 +76,21 @@
}
.select-box {
display: flex;
padding: 2px 5px;
flex-direction: row;
justify-content: center;
align-items: center;
gap: 3px;
height: 30px;
}
.select-box-item {
min-width: 60px;
text-transform: uppercase;
--combobox-trigger-background: var(--primary-background);
--combobox-trigger-border: color-mix(
in srgb,
var(--primary-background) 20%,
transparent
);
--combobox-trigger-border-hover: var(--primary-background);
--combobox-trigger-label: var(--primary-foreground);
--combobox-trigger-icon: var(--primary-foreground);
--combobox-trigger-icon-hover: var(--primary-foreground);
--combobox-trigger-font-family: 'Geist Mono';
--combobox-trigger-border-radius: 2px;
--combobox-trigger-min-block-size: 30px;
}
}

View File

@@ -6,14 +6,7 @@ import {
RefreshCw,
Settings2 as SettingsIcon,
} from '@signozhq/icons';
import {
Combobox,
ComboboxCommand,
ComboboxContent,
ComboboxItem,
ComboboxList,
ComboboxTrigger,
} from '@signozhq/ui/combobox';
import { Combobox, type ComboboxItemType } from '@signozhq/ui/combobox';
import { Skeleton, Tooltip } from 'antd';
import { Button } from '@signozhq/ui/button';
import { Switch } from '@signozhq/ui/switch';
@@ -83,7 +76,6 @@ export default function QuickFilters(props: IQuickFiltersProps): JSX.Element {
redirectWithQueryBuilderData,
panelType,
} = useQueryBuilder();
const [open, setOpen] = useState(false);
// Sync lastUsedQuery when queries change (e.g., after deletion)
const validQueryIndex = useMemo(
@@ -110,6 +102,16 @@ export default function QuickFilters(props: IQuickFiltersProps): JSX.Element {
}));
}, [currentQuery?.builder?.queryData]);
const queryItems = useMemo<ComboboxItemType[]>(
() =>
queryOptions.map((option) => ({
type: 'item',
value: String(option.value),
label: option.label,
})),
[queryOptions],
);
// Show dropdown in ListView only for TRACES_EXPLORER source
const shouldShowDropdownInListView =
isListView && source === QuickFiltersSource.TRACES_EXPLORER;
@@ -186,34 +188,20 @@ export default function QuickFilters(props: IQuickFiltersProps): JSX.Element {
{queryOptions.length > 1 &&
!isAIObservabilityRowView &&
(!isListView || shouldShowDropdownInListView) ? (
<Combobox open={open} onOpenChange={setOpen}>
<ComboboxTrigger
<div className="select-box">
<Combobox
aria-label="Select a query"
placeholder="Select a query"
value={queryOptions.find((f) => f.value === validQueryIndex)?.label || ''}
className="select-box"
searchInputProps={{ placeholder: 'Search queries' }}
items={queryItems}
value={String(validQueryIndex)}
onChange={(value): void => {
if (value !== undefined) {
handleQueryChange(Number(value));
}
}}
/>
{open && (
<ComboboxContent>
<ComboboxCommand>
<ComboboxList>
{queryOptions.map((option) => (
<ComboboxItem
key={option.value}
value={String(option.value)}
onSelect={(): void => {
handleQueryChange(option.value);
setOpen(false);
}}
isSelected={validQueryIndex === option.value}
>
{option.label}
</ComboboxItem>
))}
</ComboboxList>
</ComboboxCommand>
</ComboboxContent>
)}
</Combobox>
</div>
) : (
displayedQueryName && (
<Tooltip

View File

@@ -202,15 +202,29 @@ describe('Quick Filters', () => {
expect(screen.getByRole('option', { name: 'Query C' })).toBeInTheDocument();
});
// Select Query B
const queryBOption = screen.getByRole('option', { name: 'Query B' });
await user.click(queryBOption);
// Select Query B with the keyboard: jsdom cannot deliver the pointer
// click Base UI expects, so filter through the search row and pick with
// Enter instead
await waitFor(() => {
expect(
screen.getByRole('combobox', { name: 'Search queries' }),
).toHaveFocus();
});
await user.keyboard('Query B');
await waitFor(() => {
expect(
screen.queryByRole('option', { name: 'Query A' }),
).not.toBeInTheDocument();
});
await user.keyboard('{ArrowDown}{Enter}');
// Verify setLastUsedQuery was called with index 1
await waitFor(() => {
expect(setLastUsedQuery).toHaveBeenCalledWith(1);
});
});
// filtering and picking through the search row takes Base UI past the
// default 5s under jsdom
}, 20000);
it('should not display query dropdown in ListView', () => {
(useQueryBuilder as jest.Mock).mockReturnValue({

View File

@@ -1,4 +1,4 @@
import { Check, Copy } from '@signozhq/icons';
import { Check, Copy, SolidInfoCircle } from '@signozhq/icons';
import { Badge } from '@signozhq/ui/badge';
import { Button } from '@signozhq/ui/button';
import { Callout } from '@signozhq/ui/callout';
@@ -44,11 +44,9 @@ function KeyCreatedPhase({
</div>
<div className="add-key-modal__callout-wrapper">
<Callout
type="info"
showIcon
title="Store the key securely. This is the only time it will be displayed."
/>
<Callout color="info" size="sm" icon={<SolidInfoCircle />}>
Store the key securely. This is the only time it will be displayed.
</Callout>
</div>
</div>
);

View File

@@ -53,7 +53,6 @@ function KeyFormPhase({
<Input
id="key-name"
placeholder="Enter key name e.g.: Service Owner"
className="add-key-modal__input"
testId="add-key-name-input"
{...register('keyName', {
required: true,

View File

@@ -70,7 +70,6 @@ function EditKeyForm({
) : (
<Input
id="edit-key-name"
className="edit-key-modal__input"
placeholder="Enter key name"
{...register('name')}
/>

View File

@@ -74,7 +74,8 @@ describe('AddKeyModal', () => {
// The form only renders once the checks resolve, so waiting for it also
// guarantees the button is no longer in its authz-loading state.
const nameInput = await screen.findByTestId('add-key-name-input');
// The Input's testId lands on its frame; the native input is `-field`.
const nameInput = await screen.findByTestId('add-key-name-input-field');
const createBtn = await screen.findByTestId('add-key-submit-btn');
expect(createBtn).toHaveAttribute('aria-disabled', 'true');
@@ -94,7 +95,7 @@ describe('AddKeyModal', () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
renderModal();
const nameInput = await screen.findByTestId('add-key-name-input');
const nameInput = await screen.findByTestId('add-key-name-input-field');
const submitBtn = await screen.findByTestId('add-key-submit-btn');
await user.type(nameInput, 'Deploy Key');
await waitFor(() =>
@@ -118,8 +119,9 @@ describe('AddKeyModal', () => {
);
renderModal();
const nameInput =
await screen.findByTestId<HTMLInputElement>('add-key-name-input');
const nameInput = await screen.findByTestId<HTMLInputElement>(
'add-key-name-input-field',
);
const submitBtn = await screen.findByTestId('add-key-submit-btn');
await user.type(nameInput, 'Deploy Key');
await waitFor(() =>
@@ -139,7 +141,7 @@ describe('AddKeyModal', () => {
renderModal();
const nameInput = await screen.findByTestId('add-key-name-input');
const nameInput = await screen.findByTestId('add-key-name-input-field');
const submitBtn = await screen.findByTestId('add-key-submit-btn');
await user.type(nameInput, 'Deploy Key');
await waitFor(() =>

View File

@@ -15,20 +15,18 @@
border: 1px solid var(--l2-border);
}
// Wrapper around the chromeless new-tag Input (the Input itself is
// variant="unstyled"); the placeholder colour comes via the --input-* tokens.
.input {
flex: 1;
min-width: 120px;
border: none;
background: transparent;
&::placeholder {
color: var(--l3-foreground);
}
--input-placeholder: var(--l3-foreground);
--input-placeholder-opacity: 1;
}
// Wrapper around the inline chip-edit Input; width lives on the Input prop.
.editInput {
width: 160px;
height: 24px;
--input-height: 24px;
}
.error {

View File

@@ -9,7 +9,8 @@ type User = ReturnType<typeof userEvent.setup>;
const startEditingFirstChip = async (user: User): Promise<HTMLElement> => {
await user.click(screen.getAllByTestId(`${TID}-chip`)[0]);
return screen.getByTestId(`${TID}-edit`);
// The Input's testId lands on its frame; the native input is `${testId}-field`.
return screen.getByTestId(`${TID}-edit-field`);
};
describe('TagKeyValueInput — inline chip edit', () => {
@@ -101,7 +102,7 @@ describe('TagKeyValueInput — backend-rule validation', () => {
const onTagsChange = jest.fn();
render(<TagKeyValueInput tags={[]} onTagsChange={onTagsChange} />);
const input = screen.getByTestId(TID);
const input = screen.getByTestId(`${TID}-field`);
await user.type(input, 'env:pro d{Enter}');
expect(screen.getByTestId(`${TID}-error`)).toHaveTextContent(

View File

@@ -115,21 +115,22 @@ function TagKeyValueInput({
<div className={styles.field}>
{tags.map((tag, index) =>
index === editIndex ? (
<Input
key={tag}
className={styles.editInput}
value={editValue}
autoFocus
testId={`${testId}-edit`}
onChange={(e: ChangeEvent<HTMLInputElement>): void => {
setEditValue(e.target.value);
if (error) {
setError('');
}
}}
onKeyDown={handleEditKeyDown}
onBlur={(): void => commitEdit(true)}
/>
<span key={tag} className={styles.editInput}>
<Input
width={160}
value={editValue}
autoFocus
testId={`${testId}-edit`}
onChange={(e: ChangeEvent<HTMLInputElement>): void => {
setEditValue(e.target.value);
if (error) {
setError('');
}
}}
onKeyDown={handleEditKeyDown}
onBlur={(): void => commitEdit(true)}
/>
</span>
) : (
<Pill.Closeable
key={tag}
@@ -142,14 +143,17 @@ function TagKeyValueInput({
</Pill.Closeable>
),
)}
<Input
className={styles.input}
value={inputValue}
placeholder={placeholder}
testId={testId}
onChange={handleChange}
onKeyDown={handleKeyDown}
/>
<div className={styles.input}>
<Input
variant="unstyled"
width="100%"
value={inputValue}
placeholder={placeholder}
testId={testId}
onChange={handleChange}
onKeyDown={handleKeyDown}
/>
</div>
</div>
{error && (
<Typography className={styles.error} data-testid={`${testId}-error`}>

View File

@@ -17,7 +17,7 @@ import {
horizontalListSortingStrategy,
SortableContext,
} from '@dnd-kit/sortable';
import { ComboboxSimple } from '@signozhq/ui/combobox';
import { Combobox } from '@signozhq/ui/combobox';
import { Pagination } from '@signozhq/ui/pagination';
import type { Row } from '@tanstack/react-table';
import {
@@ -668,14 +668,16 @@ function TanStackTableInner<TData, TItemKey = string>(
/>
{pagination.showPageSize !== false && (
<div className={viewStyles.paginationPageSize}>
<ComboboxSimple
<Combobox
testId="pagination-page-size"
aria-label="Rows per page"
placeholder="Page size"
searchInputProps={{ placeholder: 'Search page sizes' }}
value={limit?.toString()}
defaultValue="10"
onChange={(value): void => {
value ??= '10';
setLimit(+value);
pagination.onLimitChange?.(+value);
onChange={(value: string | undefined): void => {
const nextValue = value ?? '10';
setLimit(+nextValue);
pagination.onLimitChange?.(+nextValue);
if (page !== 1) {
setPage(1);
pagination.onPageChange?.(1);

View File

@@ -125,7 +125,7 @@
.paginationPageSize {
width: 80px;
--combobox-trigger-height: 2rem;
--combobox-trigger-min-block-size: 2rem;
}
.paginationTotalCount {

View File

@@ -2,7 +2,7 @@ import type { CSSProperties, ReactNode } from 'react';
import type { ColumnDef } from '@tanstack/react-table';
import { RowKeyData, TableColumnDef } from './types';
import { ComboboxSimpleItem } from '@signozhq/ui/combobox';
import type { ComboboxItemType } from '@signozhq/ui/combobox';
export const getColumnId = <TData>(column: TableColumnDef<TData>): string =>
column.id;
@@ -151,11 +151,12 @@ const DEFAULT_PAGE_SIZES = [10, 20, 30, 50, 100];
export function buildPageSizeItems(
calculatedSize?: number | null,
): ComboboxSimpleItem[] {
const items: ComboboxSimpleItem[] = [];
): ComboboxItemType[] {
const items: ComboboxItemType[] = [];
if (calculatedSize) {
items.push({
type: 'item',
value: calculatedSize.toString(),
label: `Auto (${calculatedSize})`,
displayValue: calculatedSize.toString(),
@@ -165,6 +166,7 @@ export function buildPageSizeItems(
for (const size of DEFAULT_PAGE_SIZES) {
if (size !== calculatedSize) {
items.push({
type: 'item',
value: size.toString(),
label: size.toString(),
displayValue: size.toString(),

View File

@@ -1,14 +1,9 @@
import React, { useEffect } from 'react';
import cx from 'classnames';
import { useLocation } from 'react-router-dom';
import {
CommandDialog,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
CommandShortcut,
Command,
type CommandActionItemType,
type CommandItemType,
} from '@signozhq/ui/command';
import logEvent from 'api/common/logEvent';
import {
@@ -26,7 +21,10 @@ import { IS_DEV } from 'lib/env';
import history from 'lib/history';
import { ROLES as UserRole } from 'types/roles';
import { createShortcutActions } from '../../constants/shortcutActions';
import {
type CmdAction,
createShortcutActions,
} from '../../constants/shortcutActions';
import { useCmdK } from '../../providers/cmdKProvider';
import './cmdKPalette.scss';
@@ -58,17 +56,6 @@ const openAuthZDevModal = IS_DEV
}
: undefined;
type CmdAction = {
id: string;
name: string;
shortcut?: string[];
keywords?: string;
section?: string;
icon?: React.ReactNode;
roles?: UserRole[];
perform: () => void;
};
export function CmdKPalette({
userRole,
}: {
@@ -76,7 +63,7 @@ export function CmdKPalette({
}): JSX.Element | null {
const { open, setOpen } = useCmdK();
const { setAutoSwitch, setTheme, theme } = useThemeMode();
const { setAutoSwitch, setTheme } = useThemeMode();
const location = useLocation();
const isAIAssistantEnabled = useIsAIAssistantEnabled();
const startNewConversation = useAIAssistantStore(
@@ -146,8 +133,28 @@ export function CmdKPalette({
(a) => !a.roles || a.roles.includes(userRole),
);
const toCommandItem = (action: CmdAction): CommandActionItemType => ({
type: 'item',
value: action.id,
label: action.name,
prefix: action.icon,
searchMetadata: action.keywords,
shortcut:
action.shortcut && action.shortcut.length > 0
? action.shortcut.join(' • ')
: undefined,
onClick: (): void => {
// the palette closes itself after a pick, also when this throws
try {
action.perform();
} catch (e) {
console.error('Error invoking action', e);
}
},
});
// group permitted actions by section
const grouped: [string, CmdAction[]][] = ((): [string, CmdAction[]][] => {
const items: CommandItemType[] = ((): CommandItemType[] => {
const map = new Map<string, CmdAction[]>();
permitted.forEach((a) => {
@@ -161,61 +168,25 @@ export function CmdKPalette({
}
});
return Array.from(map.entries());
return Array.from(map.entries()).map(([section, sectionActions]) => ({
type: 'group',
value: section.toLowerCase().replace(/\s+/g, '-'),
label: section,
items: sectionActions.map(toCommandItem),
}));
})();
const handleInvoke = (action: CmdAction): void => {
try {
action.perform();
} catch (e) {
console.error('Error invoking action', e);
} finally {
setOpen(false);
}
};
return (
<>
<CommandDialog
<Command
label="Command palette"
open={open}
onOpenChange={setOpen}
position="top"
offset={110}
>
<CommandInput placeholder="Search…" className="cmdk-input-wrapper" />
<CommandList className="cmdk-list-scroll">
<CommandEmpty>No results</CommandEmpty>
{grouped.map(([section, items]) => (
<CommandGroup
key={section}
heading={section}
className="cmdk-section-heading"
>
{items.map((it) => (
<CommandItem
key={it.id}
onSelect={(): void => handleInvoke(it)}
value={it.name}
className={theme === 'light' ? 'cmdk-item-light' : 'cmdk-item'}
>
<span
className={cx(
'cmd-item-icon',
it.id === 'ai-assistant' && 'noz-icon',
)}
>
{it.icon}
</span>
{it.name}
{it.shortcut && it.shortcut.length > 0 && (
<CommandShortcut>{it.shortcut.join(' • ')}</CommandShortcut>
)}
</CommandItem>
))}
</CommandGroup>
))}
</CommandList>
</CommandDialog>
items={items}
searchInputProps={{ placeholder: 'Search…' }}
noContent="No results"
testId="cmdk-palette"
/>
{IS_DEV && AuthZDevModal && (
<React.Suspense fallback={null}>
<AuthZDevModal />

View File

@@ -27,7 +27,7 @@ export type CmdAction = {
shortcut?: string[];
keywords?: string;
section?: string;
icon?: React.ReactNode;
icon?: React.ReactElement;
roles?: ROLES[];
perform: () => void;
};

View File

@@ -255,11 +255,6 @@
width: 90%;
}
.contextPopoverSearchInput {
width: 100%;
box-sizing: border-box;
}
.contextPopoverEntities {
display: flex;
flex-direction: column;

View File

@@ -1093,7 +1093,6 @@ export default function ChatInput({
<Input
type="text"
placeholder={`Search ${activeContextCategory.toLowerCase()}…`}
className={styles.contextPopoverSearchInput}
value={pickerSearchQuery}
onChange={(e): void => setPickerSearchQuery(e.target.value)}
prefix={<Search size={12} />}

View File

@@ -88,7 +88,20 @@
margin-left: 2px;
}
.input,
// The free-text Inputs inside .field / .multiSelectFieldset pick up the old
// `.input` look through the Input component's CSS tokens.
.field,
.multiSelectFieldset {
--input-background: var(--l2-background);
--input-border: var(--l2-border);
--input-border-radius: var(--radius-2);
--input-height: 28px;
--input-padding: 5px 8px;
--input-font-size: 13px;
--input-foreground: var(--l1-foreground);
--input-focus-ring: var(--accent-primary);
}
.select {
background: var(--l2-background);
border: 1px solid var(--l2-border);
@@ -108,14 +121,6 @@
cursor: pointer;
}
// Constrain the Radix-based SelectContent popover so it never grows wider
// than the trigger button. `--radix-select-trigger-width` is set by Radix
// at the popper layer when `position: 'popper'` (the default).
.selectContent {
width: var(--radix-select-trigger-width);
min-width: var(--radix-select-trigger-width);
}
.radioGroup,
.checkboxGroup {
display: flex;

View File

@@ -3,12 +3,8 @@ import cx from 'classnames';
import { Button } from '@signozhq/ui/button';
import { Checkbox } from '@signozhq/ui/checkbox';
import { Input } from '@signozhq/ui/input';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
} from '@signozhq/ui/select';
import { Select } from '@signozhq/ui/select';
import type { SelectItemType } from '@signozhq/ui/select';
import logEvent from 'api/common/logEvent';
import { ClarificationFieldTypeDTO } from 'api/ai-assistant/sigNozAIAssistantAPI.schemas';
import type {
@@ -247,10 +243,7 @@ function FieldInput({ field, value, onChange }: FieldInputProps): JSX.Element {
// "Other (type your own)" entry — a plain `options: null` would
// otherwise fall through to the bare text-input renderer).
if (type === ClarificationFieldTypeDTO.select && (options || allowCustom)) {
const handleSelectChange = (next: string | string[]): void => {
// `multiple` is off → callback receives a single string. The wider
// `string | string[]` typing comes from the shared Select root.
const picked = Array.isArray(next) ? (next[0] ?? '') : next;
const handleSelectChange = (picked: string): void => {
if (picked === CUSTOM_OPTION_SENTINEL) {
setIsCustom(true);
onChange(customValue);
@@ -260,6 +253,23 @@ function FieldInput({ field, value, onChange }: FieldInputProps): JSX.Element {
}
};
const selectItems: SelectItemType[] = [
...(options ?? []).map(
(opt): SelectItemType => ({ type: 'item', value: opt, label: opt }),
),
...(allowCustom
? [
{
type: 'item',
value: CUSTOM_OPTION_SENTINEL,
label: CUSTOM_OPTION_LABEL,
} as SelectItemType,
]
: []),
];
const selectedValue = isCustom ? CUSTOM_OPTION_SENTINEL : String(value ?? '');
return (
<div className={styles.field}>
<label className={styles.label} htmlFor={id}>
@@ -271,34 +281,16 @@ function FieldInput({ field, value, onChange }: FieldInputProps): JSX.Element {
)}
</label>
<Select
value={isCustom ? CUSTOM_OPTION_SENTINEL : String(value ?? '')}
id={id}
items={selectItems}
placeholder="Select…"
aria-required={required || undefined}
value={selectedValue || undefined}
onChange={handleSelectChange}
>
<SelectTrigger
id={id}
placeholder="Select…"
aria-required={required || undefined}
/>
{/* Pin the dropdown width to the trigger via Radix's
`--radix-select-trigger-width`; otherwise the popover
sizes to its widest item and looks misaligned. */}
<SelectContent className={styles.selectContent}>
{options?.map((opt) => (
<SelectItem key={opt} value={opt}>
{opt}
</SelectItem>
))}
{allowCustom && (
<SelectItem value={CUSTOM_OPTION_SENTINEL}>
{CUSTOM_OPTION_LABEL}
</SelectItem>
)}
</SelectContent>
</Select>
/>
{isCustom && (
<Input
type="text"
className={styles.input}
placeholder="Enter a custom value"
value={customValue}
onChange={(e): void => {
@@ -407,7 +399,6 @@ function FieldInput({ field, value, onChange }: FieldInputProps): JSX.Element {
{isCustom && (
<Input
type="text"
className={styles.input}
placeholder="Enter a custom value"
value={customValue}
onChange={(e): void => updateCustomValue(e.target.value)}
@@ -431,7 +422,6 @@ function FieldInput({ field, value, onChange }: FieldInputProps): JSX.Element {
<Input
id={id}
type={type === 'number' ? 'number' : 'text'}
className={styles.input}
value={String(value ?? '')}
aria-required={required || undefined}
onChange={(e): void => {

View File

@@ -62,16 +62,16 @@
opacity: 0.7;
}
// Wrapper around the chromeless rename Input (variant="unstyled"); the accent
// bottom border marks the edit state, and the --input-* tokens keep the field
// as compact as the title row it replaces.
.input {
width: 100%;
background: transparent;
border: none;
border-bottom: 1px solid var(--accent-primary);
outline: none;
color: var(--l1-foreground);
font-size: 12px;
font-family: inherit;
padding: 1px 0;
--input-height: 20px;
--input-padding: 1px 0;
--input-font-size: 12px;
--input-foreground: var(--l1-foreground);
}
.actions {

View File

@@ -176,16 +176,21 @@ export default function ConversationItem({
<div className={styles.body}>
{isEditing ? (
<Input
ref={inputRef}
className={styles.input}
value={editValue}
onChange={(e): void => setEditValue(e.target.value)}
onKeyDown={handleKeyDown}
onBlur={commitEdit}
onClick={(e): void => e.stopPropagation()}
maxLength={80}
/>
<div className={styles.input}>
<Input
ref={inputRef}
// The wrapper's accent bottom border is the edit/focus
// treatment, so the Input renders chromeless.
variant="unstyled"
noFocusRing
value={editValue}
onChange={(e): void => setEditValue(e.target.value)}
onKeyDown={handleKeyDown}
onBlur={commitEdit}
onClick={(e): void => e.stopPropagation()}
maxLength={80}
/>
</div>
) : (
<>
<span className={styles.title} title={displayTitle}>

View File

@@ -43,11 +43,9 @@
.searchBar {
padding: 0px 8px 12px;
flex-shrink: 0;
}
.search {
width: 100%;
font-size: 12px;
// The search Input fills its parent by default; its text size comes from
// the component's CSS token.
--input-font-size: 12px;
}
.list {

View File

@@ -193,7 +193,6 @@ export default function ConversationsList({
onChange={(e): void => setSearchQuery(e.target.value)}
placeholder="Search conversations…"
prefix={<Search size={12} />}
className={styles.search}
/>
</div>

View File

@@ -46,7 +46,7 @@
height: 80px;
}
.top-contributors-progress {
--progress-background: transparent;
--progress-track-background-color: transparent;
}
&__content {

View File

@@ -1,5 +1,4 @@
import { HTMLAttributes } from 'react';
import { Color } from '@signozhq/design-tokens';
import { Table, TableColumnsType as ColumnsType } from 'antd';
import { Progress } from '@signozhq/ui/progress';
import logEvent from 'api/common/logEvent';
@@ -49,12 +48,13 @@ function TopContributorsRows({
relatedTracesLink={record.relatedTracesLink}
relatedLogsLink={record.relatedLogsLink}
>
<Progress
percent={(count / totalCurrentTriggers) * 100}
showInfo={false}
strokeColor={Color.BG_ROBIN_500}
className="top-contributors-progress"
/>
<div className="top-contributors-progress">
<Progress
percent={(count / totalCurrentTriggers) * 100}
showInfo={false}
color="primary"
/>
</div>
</ConditionalAlertPopover>
),
},

View File

@@ -387,7 +387,7 @@ describe('Create Alert Channel', () => {
it('Should check if API key label, required, info(help_email_to), and textbox are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_email_to',
testId: 'email-to-textbox',
testId: 'email-to-textbox-field',
helpText: 'help_email_to',
required: true,
});
@@ -479,7 +479,7 @@ describe('Create Alert Channel', () => {
it('Should check if saving with a webhook url outside chat.googleapis.com displays error notification', async () => {
const user = userEvent.setup();
await fillField(user, 'channel-name-textbox', 'gchat-channel');
await fillField(user, 'channel-name-textbox-field', 'gchat-channel');
await fillField(user, 'webhook-url-textbox', 'https://example.com/webhook');
await user.click(screen.getByTestId('save-channel-button'));
@@ -506,7 +506,7 @@ describe('Create Alert Channel', () => {
const user = userEvent.setup();
await fillField(user, 'channel-name-textbox', 'gchat-channel');
await fillField(user, 'channel-name-textbox-field', 'gchat-channel');
await fillField(user, 'webhook-url-textbox', validWebhookUrl);
await user.click(screen.getByTestId('save-channel-button'));
@@ -538,7 +538,10 @@ describe('Create Alert Channel', () => {
user: ReturnType<typeof userEvent.setup>,
site: string,
): Promise<void> => {
await user.type(screen.getByTestId('channel-name-textbox'), 'jira-channel');
await user.type(
screen.getByTestId('channel-name-textbox-field'),
'jira-channel',
);
await user.type(screen.getByTestId('jira-site-textbox'), site);
await user.type(screen.getByTestId('jira-email-textbox'), 'me@acme.com');
await user.type(screen.getByTestId('jira-api-token-textbox'), 'tok123');
@@ -687,7 +690,7 @@ describe('Create Alert Channel', () => {
it('Should block save when the API key is missing', async () => {
const user = userEvent.setup();
await user.type(
screen.getByTestId('channel-name-textbox'),
screen.getByTestId('channel-name-textbox-field'),
'jsmops-channel',
);
@@ -715,7 +718,7 @@ describe('Create Alert Channel', () => {
const user = userEvent.setup();
await user.type(
screen.getByTestId('channel-name-textbox'),
screen.getByTestId('channel-name-textbox-field'),
'jsmops-channel',
);
await user.type(screen.getByTestId('jsmops-api-key-textbox'), 'key-abc');
@@ -773,7 +776,7 @@ describe('Create Alert Channel', () => {
it('Should block save when the URL or token is missing', async () => {
const user = userEvent.setup();
await user.type(
screen.getByTestId('channel-name-textbox'),
screen.getByTestId('channel-name-textbox-field'),
'incidentio-channel',
);
@@ -790,7 +793,7 @@ describe('Create Alert Channel', () => {
it('Should display an error when the URL is not an alert events URL', async () => {
const user = userEvent.setup();
await user.type(
screen.getByTestId('channel-name-textbox'),
screen.getByTestId('channel-name-textbox-field'),
'incidentio-channel',
);
await user.type(
@@ -823,7 +826,7 @@ describe('Create Alert Channel', () => {
const user = userEvent.setup();
await user.type(
screen.getByTestId('channel-name-textbox'),
screen.getByTestId('channel-name-textbox-field'),
'incidentio-channel',
);
await user.type(

View File

@@ -297,7 +297,7 @@ describe('Create Alert Channel (Normal User)', () => {
it('Should check if API key label, required, info(help_email_to), and textbox are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_email_to',
testId: 'email-to-textbox',
testId: 'email-to-textbox-field',
helpText: 'help_email_to',
required: true,
});

View File

@@ -43,7 +43,7 @@ describe('Should check if the edit alert channel is properly displayed', () => {
it('Should check if the name label and textbox are displayed properly', () => {
testLabelInputAndHelpValue({
labelText: 'field_channel_name',
testId: 'channel-name-textbox',
testId: 'channel-name-textbox-field',
value: 'Dummy-Channel',
});
});

View File

@@ -158,7 +158,7 @@ function DomainDetails({
title={
<div className="domain-details-drawer-header">
<div className="domain-details-drawer-header-title">
<Divider type="vertical" />
<Divider orientation="vertical" />
{domainData?.domainName && (
<Typography.Text className="title">

View File

@@ -1,6 +1,5 @@
import { useMemo } from 'react';
import { useQueries } from 'react-query';
import { Color } from '@signozhq/design-tokens';
import { Skeleton, Tooltip } from 'antd';
import { Progress } from '@signozhq/ui/progress';
import { Typography } from '@signozhq/ui/typography';
@@ -136,26 +135,21 @@ function DomainMetrics({
) : (
<Tooltip title={formattedDomainMetricsData.errorRate}>
{formattedDomainMetricsData.errorRate !== '-' ? (
<Progress
percent={Number(
Number(formattedDomainMetricsData.errorRate).toFixed(2),
)}
strokeLinecap="butt"
showInfo
strokeColor={((): string => {
const errorRatePercent = Number(
<div className="progress-bar">
<Progress
percent={Number(
Number(formattedDomainMetricsData.errorRate).toFixed(2),
);
if (errorRatePercent >= 90) {
return Color.BG_SAKURA_500;
)}
showInfo
color={
Number(formattedDomainMetricsData.errorRate) >= 90
? 'highlight-danger'
: Number(formattedDomainMetricsData.errorRate) >= 60
? 'warning'
: 'success'
}
if (errorRatePercent >= 60) {
return Color.BG_AMBER_500;
}
return Color.BG_FOREST_500;
})()}
className="progress-bar"
/>
/>
</div>
) : (
'-'
)}

View File

@@ -1,6 +1,5 @@
import { useMemo } from 'react';
import { UseQueryResult } from 'react-query';
import { Color } from '@signozhq/design-tokens';
import { Skeleton, Tooltip } from 'antd';
import { Progress } from '@signozhq/ui/progress';
import { Typography } from '@signozhq/ui/typography';
@@ -80,24 +79,19 @@ function EndPointMetrics({
) : (
<Tooltip title={metricsData?.errorRate}>
{metricsData?.errorRate !== '-' ? (
<Progress
percent={Number(Number(metricsData?.errorRate ?? 0).toFixed(2))}
strokeLinecap="butt"
showInfo
strokeColor={((): string => {
const errorRatePercent = Number(
Number(metricsData?.errorRate ?? 0).toFixed(2),
);
if (errorRatePercent >= 90) {
return Color.BG_SAKURA_500;
<div className="progress-bar">
<Progress
percent={Number(Number(metricsData?.errorRate ?? 0).toFixed(2))}
showInfo
color={
Number(metricsData?.errorRate ?? 0) >= 90
? 'highlight-danger'
: Number(metricsData?.errorRate ?? 0) >= 60
? 'warning'
: 'success'
}
if (errorRatePercent >= 60) {
return Color.BG_AMBER_500;
}
return Color.BG_FOREST_500;
})()}
className="progress-bar"
/>
/>
</div>
) : (
'-'
)}

View File

@@ -1,5 +1,4 @@
import { ReactNode } from 'react';
import { Color } from '@signozhq/design-tokens';
import { TableColumnType as ColumnType, Tooltip } from 'antd';
import { Progress } from '@signozhq/ui/progress';
import { Badge } from '@signozhq/ui/badge';
@@ -47,6 +46,18 @@ import {
EndPointsResponseRow,
} from './types';
function metricProgressColor(
percent: number,
): 'success' | 'warning' | 'highlight-danger' {
if (percent >= 90) {
return 'highlight-danger';
}
if (percent >= 60) {
return 'warning';
}
return 'success';
}
export const isEmptyFilterValue = (value: unknown): boolean =>
value === '' || value === null || value === undefined || value === 'n/a';
/**
@@ -258,22 +269,13 @@ export const columnsConfig: ColumnType<APIDomainsRowData>[] = [
const errorRateValue =
errorRate === 'n/a' || errorRate === '-' ? 0 : errorRate;
return (
<Progress
percent={Number((errorRateValue as number).toFixed(2))}
strokeLinecap="butt"
showInfo
strokeColor={((): string => {
const errorRatePercent = Number((errorRateValue as number).toFixed(2));
if (errorRatePercent >= 90) {
return Color.BG_SAKURA_500;
}
if (errorRatePercent >= 60) {
return Color.BG_AMBER_500;
}
return Color.BG_FOREST_500;
})()}
className="progress-bar error-rate"
/>
<div className="progress-bar error-rate">
<Progress
percent={Number((errorRateValue as number).toFixed(2))}
showInfo
color={metricProgressColor(Number((errorRateValue as number).toFixed(2)))}
/>
</div>
);
},
},
@@ -1023,26 +1025,23 @@ export const getEndPointsColumnsConfig = (
align: 'right',
className: `column`,
render: (errorRate: number | string): React.ReactNode => (
<Progress
percent={Number(
(
(errorRate === 'n/a' || errorRate === '-' ? 0 : errorRate) as number
).toFixed(1),
)}
strokeLinecap="butt"
showInfo
strokeColor={((): string => {
const errorRatePercent = Number((errorRate as number).toFixed(1));
if (errorRatePercent >= 90) {
return Color.BG_SAKURA_500;
}
if (errorRatePercent >= 60) {
return Color.BG_AMBER_500;
}
return Color.BG_FOREST_500;
})()}
className="progress-bar error-rate"
/>
<div className="progress-bar error-rate">
<Progress
percent={Number(
(
(errorRate === 'n/a' || errorRate === '-' ? 0 : errorRate) as number
).toFixed(1),
)}
showInfo
color={metricProgressColor(
Number(
(
(errorRate === 'n/a' || errorRate === '-' ? 0 : errorRate) as number
).toFixed(1),
),
)}
/>
</div>
),
},
{
@@ -2514,24 +2513,15 @@ export const dependentServicesColumns: ColumnType<DependentServicesData>[] = [
align: 'center',
render: (errorPercentage: number | string): React.ReactNode =>
errorPercentage !== '-' ? (
<Progress
percent={Number((errorPercentage as number).toFixed(2))}
strokeLinecap="butt"
showInfo
strokeColor={((): string => {
const errorPercentagePercent = Number(
(errorPercentage as number).toFixed(2),
);
if (errorPercentagePercent >= 90) {
return Color.BG_SAKURA_500;
}
if (errorPercentagePercent >= 60) {
return Color.BG_AMBER_500;
}
return Color.BG_FOREST_500;
})()}
className="progress-bar error-rate"
/>
<div className="progress-bar error-rate">
<Progress
percent={Number((errorPercentage as number).toFixed(2))}
showInfo
color={metricProgressColor(
Number((errorPercentage as number).toFixed(2)),
)}
/>
</div>
) : (
'-'
),
@@ -3021,30 +3011,23 @@ export const getAllEndpointsWidgetData = (
</span>
),
F1: (errorRate: any): ReactNode => (
<Progress
percent={Number(
(
(errorRate === 'n/a' || errorRate === '-' ? 0 : errorRate) as number
).toFixed(2),
)}
strokeLinecap="butt"
showInfo
strokeColor={((): string => {
const errorRatePercent = Number(
<div className="progress-bar error-rate">
<Progress
percent={Number(
(
(errorRate === 'n/a' || errorRate === '-' ? 0 : errorRate) as number
).toFixed(2),
);
if (errorRatePercent >= 90) {
return Color.BG_SAKURA_500;
}
if (errorRatePercent >= 60) {
return Color.BG_AMBER_500;
}
return Color.BG_FOREST_500;
})()}
className="progress-bar error-rate"
/>
)}
showInfo
color={metricProgressColor(
Number(
(
(errorRate === 'n/a' || errorRate === '-' ? 0 : errorRate) as number
).toFixed(2),
),
)}
/>
</div>
),
};

View File

@@ -4,7 +4,13 @@ import { Typography } from '@signozhq/ui/typography';
import React, { useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useMutation } from 'react-query';
import { CircleCheck, Landmark, MonitorDown } from '@signozhq/icons';
import {
CircleCheck,
Landmark,
MonitorDown,
SolidAlertCircle,
SolidInfoCircle,
} from '@signozhq/icons';
import {
Card,
Col,
@@ -480,12 +486,11 @@ export default function BillingContainer(): JSX.Element {
{!isLoading && !isFetchingBillingData && !showGracePeriodMessage
? headerText && (
<Callout
title={headerText}
type="info"
showIcon
style={{ marginTop: 12 }}
/>
<div style={{ marginTop: 12 }}>
<Callout color="info" size="sm" icon={<SolidInfoCircle />}>
{headerText}
</Callout>
</div>
)
: null}
@@ -498,21 +503,22 @@ export default function BillingContainer(): JSX.Element {
billingData &&
trialInfo?.gracePeriodEnd &&
showGracePeriodMessage ? (
<Callout
title={`Your data is safe with us until ${getFormattedDate(
trialInfo?.gracePeriodEnd || Date.now(),
)}. Please upgrade plan now to retain your data.`}
type="info"
showIcon
style={{ marginTop: 12 }}
/>
<div style={{ marginTop: 12 }}>
<Callout color="info" size="sm" icon={<SolidInfoCircle />}>
{`Your data is safe with us until ${getFormattedDate(
trialInfo?.gracePeriodEnd || Date.now(),
)}. Please upgrade plan now to retain your data.`}
</Callout>
</div>
) : null}
{isSubscriptionPastDue &&
(!isLoading && !isFetchingBillingData ? (
<Callout type="error" showIcon style={{ marginTop: 12 }}>
{subscriptionPastDueMessage()}
</Callout>
<div style={{ marginTop: 12 }}>
<Callout color="danger" size="sm" icon={<SolidAlertCircle />}>
{subscriptionPastDueMessage()}
</Callout>
</div>
) : (
<Skeleton.Input active style={{ height: 20, marginTop: 20 }} />
))}
@@ -553,9 +559,11 @@ export default function BillingContainer(): JSX.Element {
)}
</div>
{!isLoading && !isFetchingBillingData && (
<Callout type="info" size="small" className={styles.billingUpdateNote}>
Billing metrics are updated once every 24 hours.
</Callout>
<div className={styles.billingUpdateNote}>
<Callout color="info" size="sm" icon={<SolidInfoCircle />}>
Billing metrics are updated once every 24 hours.
</Callout>
</div>
)}
<div className={styles.billingDetails}>

View File

@@ -92,7 +92,7 @@ describe('CancelSubscriptionBanner', () => {
screen.getByText(/Cancelling your subscription would stop your data/i),
).toBeInTheDocument();
expect(screen.getByText(/Type/i)).toBeInTheDocument();
expect(screen.getByTestId('cancel-confirm-input')).toBeInTheDocument();
expect(screen.getByTestId('cancel-confirm-input-field')).toBeInTheDocument();
expect(screen.getByRole('button', { name: /go back/i })).toBeInTheDocument();
expect(
screen.getByTestId('cancel-subscription-confirm-btn'),
@@ -114,7 +114,7 @@ describe('CancelSubscriptionBanner', () => {
const confirmButton = screen.getByTestId('cancel-subscription-confirm-btn');
expect(confirmButton).toHaveAttribute('aria-disabled', 'true');
const input = screen.getByTestId('cancel-confirm-input');
const input = screen.getByTestId('cancel-confirm-input-field');
await user.type(input, 'canc');
expect(confirmButton).toHaveAttribute('aria-disabled', 'true');
@@ -134,7 +134,7 @@ describe('CancelSubscriptionBanner', () => {
});
await user.click(screen.getByTestId('cancel-subscription-btn'));
const input = screen.getByTestId('cancel-confirm-input');
const input = screen.getByTestId('cancel-confirm-input-field');
await user.type(input, 'cancel');
await user.click(screen.getByRole('button', { name: /go back/i }));
@@ -149,7 +149,7 @@ describe('CancelSubscriptionBanner', () => {
);
});
await user.click(screen.getByTestId('cancel-subscription-btn'));
expect(screen.getByTestId('cancel-confirm-input')).toHaveValue('');
expect(screen.getByTestId('cancel-confirm-input-field')).toHaveValue('');
});
it('fires mailto via DOM-attached anchor and shows fallback view after confirming', async () => {
@@ -165,7 +165,7 @@ describe('CancelSubscriptionBanner', () => {
);
});
await user.click(screen.getByTestId('cancel-subscription-btn'));
await user.type(screen.getByTestId('cancel-confirm-input'), 'cancel');
await user.type(screen.getByTestId('cancel-confirm-input-field'), 'cancel');
await user.click(screen.getByTestId('cancel-subscription-confirm-btn'));
const appendedAnchor = appendSpy.mock.calls
@@ -201,7 +201,7 @@ describe('CancelSubscriptionBanner', () => {
);
});
await user.click(screen.getByTestId('cancel-subscription-btn'));
await user.type(screen.getByTestId('cancel-confirm-input'), 'cancel');
await user.type(screen.getByTestId('cancel-confirm-input-field'), 'cancel');
await user.click(screen.getByTestId('cancel-subscription-confirm-btn'));
await user.click(screen.getByTestId('copy-email-template-btn'));
@@ -227,7 +227,7 @@ describe('CancelSubscriptionBanner', () => {
);
});
await user.click(screen.getByTestId('cancel-subscription-btn'));
await user.type(screen.getByTestId('cancel-confirm-input'), 'cancel');
await user.type(screen.getByTestId('cancel-confirm-input-field'), 'cancel');
await user.click(screen.getByTestId('cancel-subscription-confirm-btn'));
await user.click(screen.getByTestId('retry-mailto-btn'));
@@ -251,7 +251,7 @@ describe('CancelSubscriptionBanner', () => {
);
});
await user.click(screen.getByTestId('cancel-subscription-btn'));
await user.type(screen.getByTestId('cancel-confirm-input'), 'cancel');
await user.type(screen.getByTestId('cancel-confirm-input-field'), 'cancel');
await user.click(screen.getByTestId('cancel-subscription-confirm-btn'));
await user.click(screen.getByRole('button', { name: /close/i }));

View File

@@ -216,7 +216,7 @@ function CancelSubscriptionBanner(): JSX.Element {
placeholder="Enter the word cancel..."
value={confirmText}
onChange={(e): void => setConfirmText(e.target.value)}
data-testid="cancel-confirm-input"
testId="cancel-confirm-input"
/>
</div>
)}

View File

@@ -101,8 +101,8 @@ function ThresholdItem({
onChange={(e): void =>
updateThreshold(threshold.id, 'label', e.target.value)
}
style={{ width: 200 }}
data-testid="threshold-name-input"
width={200}
testId="threshold-name-input"
/>
<Typography.Text className="sentence-text">on value</Typography.Text>
<Typography.Text className="sentence-text highlighted-text">
@@ -114,9 +114,9 @@ function ThresholdItem({
onChange={(e): void =>
updateThreshold(threshold.id, 'thresholdValue', e.target.value)
}
style={{ width: 100 }}
width={100}
type="number"
data-testid="threshold-value-input"
testId="threshold-value-input"
/>
{yAxisUnitSelect}
{!notificationSettings.routingPolicies && (
@@ -165,9 +165,9 @@ function ThresholdItem({
onChange={(e): void =>
updateThreshold(threshold.id, 'recoveryThresholdValue', e.target.value)
}
style={{ width: 100 }}
width={100}
type="number"
data-testid="recovery-threshold-value-input"
testId="recovery-threshold-value-input"
/>
<Tooltip title="Remove recovery threshold">
<Button

View File

@@ -319,15 +319,12 @@ describe('ThresholdItem', () => {
it('renders with correct input widths', () => {
renderThresholdItem();
const labelInput = screen.getByPlaceholderText(
TEST_CONSTANTS.ENTER_THRESHOLD_NAME,
);
const valueInput = screen.getByPlaceholderText(
TEST_CONSTANTS.ENTER_THRESHOLD_VALUE,
);
// The width prop lands on the input frame as a CSS custom property
const labelInputFrame = screen.getByTestId('threshold-name-input');
const valueInputFrame = screen.getByTestId('threshold-value-input');
expect(labelInput).toHaveStyle('width: 200px');
expect(valueInput).toHaveStyle('width: 100px');
expect(labelInputFrame).toHaveStyle('--input-internal-width: 200px');
expect(valueInputFrame).toHaveStyle('--input-internal-width: 100px');
});
it('renders channels selector with correct width', () => {

View File

@@ -73,20 +73,21 @@ function CreateAlertHeader(): JSX.Element {
</div>
)}
<div className="alert-header__content">
<Input
type="text"
value={alertState.name}
onChange={(e): void => {
const newName = e.target.value;
setAlertState({ type: 'SET_ALERT_NAME', payload: newName });
if (isEditMode && alertRuleContext?.setAlertRuleName) {
alertRuleContext.setAlertRuleName(newName);
}
}}
className="alert-header__input title"
placeholder="Enter alert rule name"
data-testid="alert-name-input"
/>
<div className="alert-header__input title">
<Input
type="text"
value={alertState.name}
onChange={(e): void => {
const newName = e.target.value;
setAlertState({ type: 'SET_ALERT_NAME', payload: newName });
if (isEditMode && alertRuleContext?.setAlertRuleName) {
alertRuleContext.setAlertRuleName(newName);
}
}}
placeholder="Enter alert rule name"
testId="alert-name-input"
/>
</div>
<LabelsInput
labels={alertState.labels}
onLabelsChange={(labels: Labels): void =>

View File

@@ -38,8 +38,8 @@
}
&__input.title {
background-color: transparent;
color: var(--l1-foreground);
--input-background: transparent;
--input-foreground: var(--l1-foreground);
width: 100%;
min-width: 300px;
}

View File

@@ -23,7 +23,7 @@ function AdvancedOptions(): JSX.Element {
<Input
placeholder="Enter tolerance limit..."
type="number"
style={{ width: 100 }}
width={100}
onChange={(e): void =>
setAdvancedOptions({
type: 'SET_SEND_NOTIFICATION_IF_DATA_IS_MISSING',
@@ -56,7 +56,7 @@ function AdvancedOptions(): JSX.Element {
<div className="advanced-option-item-input-group">
<Input
placeholder="Enter minimum datapoints..."
style={{ width: 100 }}
width={100}
type="number"
onChange={(e): void =>
setAdvancedOptions({

View File

@@ -217,7 +217,7 @@ function EvaluationWindowDetails({
value={evaluationWindow.startingAt.number}
onChange={(e): void => handleNumberChange(e.target.value)}
placeholder="Enter value"
data-testid="evaluation-window-details-custom-rolling-window-duration-input"
testId="evaluation-window-details-custom-rolling-window-duration-input"
/>
</div>
<div className="select-group time-select-group">

View File

@@ -3,42 +3,20 @@
align-items: center;
gap: 0;
.time-input-field {
width: 40px;
height: 32px;
background-color: var(--l2-background);
border: 1px solid var(--l1-border);
color: var(--l1-foreground);
font-family: 'Space Mono', monospace;
font-size: 13px;
font-weight: 600;
// The fields are @signozhq/ui Inputs, restyled through the input tokens.
--input-background: var(--l2-background);
--input-border: var(--l1-border);
--input-border-hover: var(--l1-border);
--input-foreground: var(--l1-foreground);
--input-placeholder: var(--l2-foreground);
--input-font-family: 'Space Mono', monospace;
--input-font-size: 13px;
--input-font-weight: 600;
--input-border-radius: 4px;
--input-padding: 0 4px;
input {
text-align: center;
border-radius: 4px;
&::placeholder {
color: var(--l2-foreground);
font-family: 'Space Mono', monospace;
}
&:hover {
border-color: var(--l1-border);
}
&:focus {
border-color: var(--l1-border);
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.1);
outline: none;
}
&:disabled {
background-color: var(--l2-background);
color: var(--l2-foreground);
cursor: not-allowed;
&:hover {
border-color: var(--l1-border);
}
}
}
.time-input-separator {

View File

@@ -131,13 +131,13 @@ function TimeInput({
if (e.key === 'ArrowRight' || e.key === 'Tab') {
e.preventDefault();
const nextField = document.querySelector(
`[data-field="${getNextField(currentField)}"]`,
`[data-field="${getNextField(currentField)}"] input`,
) as HTMLInputElement;
nextField?.focus();
} else if (e.key === 'ArrowLeft') {
e.preventDefault();
const prevField = document.querySelector(
`[data-field="${getPrevField(currentField)}"]`,
`[data-field="${getPrevField(currentField)}"] input`,
) as HTMLInputElement;
prevField?.focus();
}
@@ -152,10 +152,11 @@ function TimeInput({
onBlur={handleHoursBlur}
onKeyDown={(e): void => handleKeyDown(e, 'hours')}
disabled={disabled}
disabledTooltip={undefined}
maxLength={2}
className="time-input-field"
width={40}
placeholder="00"
data-testid="time-input-hours"
testId="time-input-hours"
/>
<span className="time-input-separator">:</span>
<Input
@@ -165,10 +166,11 @@ function TimeInput({
onBlur={handleMinutesBlur}
onKeyDown={(e): void => handleKeyDown(e, 'minutes')}
disabled={disabled}
disabledTooltip={undefined}
maxLength={2}
className="time-input-field"
width={40}
placeholder="00"
data-testid="time-input-minutes"
testId="time-input-minutes"
/>
<span className="time-input-separator">:</span>
<Input
@@ -178,10 +180,11 @@ function TimeInput({
onBlur={handleSecondsBlur}
onKeyDown={(e): void => handleKeyDown(e, 'seconds')}
disabled={disabled}
disabledTooltip={undefined}
maxLength={2}
className="time-input-field"
width={40}
placeholder="00"
data-testid="time-input-seconds"
testId="time-input-seconds"
/>
</div>
);

View File

@@ -25,6 +25,7 @@ function NotificationSettings(): JSX.Element {
value={notificationSettings.reNotification.value}
placeholder="Enter time interval..."
disabled={!notificationSettings.reNotification.enabled}
disabledTooltip={undefined}
type="number"
onChange={(e): void => {
setNotificationSettings({
@@ -37,7 +38,7 @@ function NotificationSettings(): JSX.Element {
},
});
}}
data-testid="repeat-notifications-time-input"
testId="repeat-notifications-time-input"
/>
<Select
value={notificationSettings.reNotification.unit || null}

View File

@@ -6,7 +6,7 @@ import {
ExternalLink,
FilePenLine,
Link2,
SolidAlertCircle,
SolidInfoCircle,
X,
} from '@signozhq/icons';
import { Button } from '@signozhq/ui/button';
@@ -270,14 +270,11 @@ export default function CustomDomainSettings(): JSX.Element {
</div>
{isPollingEnabled && (
<Callout
type="info"
showIcon
className="custom-domain-callout"
size="small"
icon={<SolidAlertCircle size={13} color="primary" />}
title={`Updating your URL to ⎯ ${customDomainSubdomain}.${dnsSuffix}. This may take a few mins.`}
/>
<div className="custom-domain-callout">
<Callout color="info" size="sm" icon={<SolidInfoCircle />}>
{`Updating your URL to ⎯ ${customDomainSubdomain}.${dnsSuffix}. This may take a few mins.`}
</Callout>
</div>
)}
<CustomDomainEditModal

View File

@@ -27,7 +27,7 @@
}
&__divider {
--divider-vertical-margin: 0;
--divider-vertical-margin-inline: 0;
}
}

View File

@@ -871,12 +871,13 @@ function ExplorerOptions({
}
{isQueryUpdated && (
<>
<Divider
type="vertical"
<span
className={cx('explorer-options-container__divider', {
hidden: !isEditDeleteSupported,
})}
/>
>
<Divider orientation="vertical" />
</span>
<Tooltip title="Update this view" placement="top">
<Button
className={cx('action-icon', isEditDeleteSupported ? ' ' : 'hidden')}

View File

@@ -40,6 +40,18 @@
width: 100%;
display: flex;
flex-direction: column;
// Restyle the @signozhq/ui Input to match .login-form-input (Login.styles.scss)
--input-background: var(--l2-background);
--input-border: var(--l2-border);
--input-border-hover: var(--l1-border);
--input-border-radius: 2px;
--input-padding: 6px 8px;
--input-font-family: Inter, sans-serif;
--input-font-size: 13px;
--input-letter-spacing: -0.065px;
--input-foreground: var(--l1-foreground);
--input-placeholder: var(--l3-foreground);
}
&.ant-form {

View File

@@ -96,14 +96,14 @@ describe('ForgotPassword Component', () => {
it('pre-fills email from props', () => {
render(<ForgotPassword {...defaultProps} />);
const emailInput = screen.getByTestId('email');
const emailInput = screen.getByTestId('email-field');
expect(emailInput).toHaveValue(TEST_EMAIL);
});
it('disables email input field', () => {
render(<ForgotPassword {...defaultProps} />);
const emailInput = screen.getByTestId('email');
const emailInput = screen.getByTestId('email-field');
expect(emailInput).toBeDisabled();
});

View File

@@ -147,10 +147,10 @@ function ForgotPassword({
<Input
type="email"
id="forgotPasswordEmail"
data-testid="email"
testId="email"
required
disabled
className="login-form-input"
disabledTooltip={undefined}
/>
</Form.Item>
</div>

View File

@@ -27,7 +27,7 @@ function EmailForm({ setSelectedConfig }: EmailFormProps): JSX.Element {
<Input
onChange={handleInputChange('to')}
placeholder={t('placeholder_email_to')}
data-testid="email-to-textbox"
testId="email-to-textbox"
/>
</Form.Item>

View File

@@ -32,7 +32,7 @@ function WebhookSettings({ setSelectedConfig }: WebhookProps): JSX.Element {
api_url: event.target.value,
}));
}}
data-testid="webhook-url-textbox"
testId="webhook-url-textbox"
/>
</Form.Item>
<Form.Item
@@ -47,7 +47,7 @@ function WebhookSettings({ setSelectedConfig }: WebhookProps): JSX.Element {
username: event.target.value,
}));
}}
data-testid="webhook-username-textbox"
testId="webhook-username-textbox"
/>
</Form.Item>
<Form.Item
@@ -63,7 +63,7 @@ function WebhookSettings({ setSelectedConfig }: WebhookProps): JSX.Element {
password: event.target.value,
}));
}}
data-testid="webhook-password-textbox"
testId="webhook-password-textbox"
/>
</Form.Item>
</>

View File

@@ -88,8 +88,9 @@ function FormAlertChannels({
<Form initialValues={initialValue} layout="vertical" form={formInstance}>
<Form.Item label={t('field_channel_name')} labelAlign="left" name="name">
<Input
data-testid="channel-name-textbox"
testId="channel-name-textbox"
disabled={editing}
disabledTooltip={undefined}
onChange={(event): void => {
setSelectedConfig((state) => ({
...state,

View File

@@ -1,3 +1,4 @@
import { SolidInfoCircle } from '@signozhq/icons';
import { Callout } from '@signozhq/ui/callout';
import ClickHouseQueryBuilder from 'container/QueryBuilder/rawQueryEditors/ClickHouse/query';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
@@ -32,25 +33,21 @@ function ChQuerySection({ alertType }: ChQuerySectionProps): JSX.Element {
<>
{docLink && (
<div className="info-banner-wrapper">
<Callout
type="info"
showIcon
title={
<span>
<a href={docLink} target="_blank" rel="noopener">
Learn to write faster, optimized queries
</a>
{showAgentSkill && (
<>
{' · Using AI? '}
<a href={DOCLINKS.AGENT_SKILL_INSTALL} target="_blank" rel="noopener">
Install the SigNoz ClickHouse query agent skill
</a>
</>
)}
</span>
}
/>
<Callout color="info" size="sm" icon={<SolidInfoCircle />}>
<span>
<a href={docLink} target="_blank" rel="noopener">
Learn to write faster, optimized queries
</a>
{showAgentSkill && (
<>
{' · Using AI? '}
<a href={DOCLINKS.AGENT_SKILL_INSTALL} target="_blank" rel="noopener">
Install the SigNoz ClickHouse query agent skill
</a>
</>
)}
</span>
</Callout>
</div>
)}
<ClickHouseQueryBuilder

View File

@@ -60,7 +60,6 @@
--query-builder-v2-toggle-group-active-background-color: var(--l2-background);
--query-builder-v2-toggle-group-background-color-hover: var(--l3-background);
--input-height: 36px;
--input-hover-background: var(--l3-background);
--input-hover-border-color: var(--internal-ant-border-color-hover);
}
}

View File

@@ -1,14 +1,6 @@
import { useTranslation } from 'react-i18next';
import {
Checkbox,
Collapse,
Form,
InputNumber,
InputNumberProps,
Select,
SelectProps,
Space,
} from 'antd';
import { Checkbox, Collapse, Form, Select, SelectProps, Space } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Typography } from '@signozhq/ui/typography';
import type { DefaultOptionType } from 'antd/es/select';
import {
@@ -293,7 +285,7 @@ function RuleOptions({
</Form.Item>
);
const onChange: InputNumberProps['onChange'] = (value): void => {
const onChange = (value: number | null): void => {
setAlertDef({
...alertDef,
condition: {
@@ -394,13 +386,12 @@ function RuleOptions({
{ruleType !== AlertDetectionTypes.ANOMALY_DETECTION_ALERT && (
<Space direction="horizontal" align="center">
<Form.Item noStyle>
<InputNumber
addonBefore={t('field_threshold')}
value={alertDef?.condition?.target}
<Input.Number
prefix={t('field_threshold')}
value={alertDef?.condition?.target ?? null}
onChange={onChange}
type="number"
data-testid="alert-threshold-target-input"
onWheel={(e): void => e.currentTarget.blur()}
width={200}
testId="alert-threshold-target-input"
/>
</Form.Item>
@@ -447,10 +438,18 @@ function RuleOptions({
</Form.Item>
<Typography.Text>{t('text_alert_on_absent')}</Typography.Text>
<Form.Item noStyle name={['condition', 'absentFor']}>
<InputNumber
<Form.Item
noStyle
name={['condition', 'absentFor']}
// Input.Number is a controlled input: map the form store's
// `undefined` (field not set yet) to `null` (empty field).
getValueProps={(value): { value: number | null } => ({
value: value ?? null,
})}
>
<Input.Number
min={1}
value={alertDef?.condition?.absentFor}
width={90}
onChange={(value): void => {
setAlertDef({
...alertDef,
@@ -460,8 +459,6 @@ function RuleOptions({
},
});
}}
type="number"
onWheel={(e): void => e.currentTarget.blur()}
/>
</Form.Item>
<Typography.Text>{t('text_for')}</Typography.Text>
@@ -486,10 +483,18 @@ function RuleOptions({
</Form.Item>
<Typography.Text>{t('text_require_min_points')}</Typography.Text>
<Form.Item noStyle name={['condition', 'requiredNumPoints']}>
<InputNumber
<Form.Item
noStyle
name={['condition', 'requiredNumPoints']}
// Input.Number is a controlled input: map the form store's
// `undefined` (field not set yet) to `null` (empty field).
getValueProps={(value): { value: number | null } => ({
value: value ?? null,
})}
>
<Input.Number
min={1}
value={alertDef?.condition?.requiredNumPoints}
width={90}
onChange={(value): void => {
setAlertDef({
...alertDef,
@@ -499,8 +504,6 @@ function RuleOptions({
},
});
}}
type="number"
onWheel={(e): void => e.currentTarget.blur()}
/>
</Form.Item>
<Typography.Text>{t('text_num_points')}</Typography.Text>

View File

@@ -1,5 +1,6 @@
import { useState } from 'react';
import { Link } from 'react-router-dom';
import { SolidInfoCircle } from '@signozhq/icons';
import { Callout } from '@signozhq/ui/callout';
import getLocalStorageApi from 'api/browser/localstorage/get';
import setLocalStorageApi from 'api/browser/localstorage/set';
@@ -40,42 +41,43 @@ function LicenseRowDismissibleCallout(): JSX.Element | null {
};
return !isCalloutDismissed ? (
<Callout
type="info"
size="small"
showIcon
action="dismissible"
onClick={handleDismissCallout}
className="license-key-callout"
>
<div className="license-key-callout__description">
This is <strong>NOT</strong> your ingestion or Service account key.
{(hasServiceAccountsAccess || hasIngestionAccess) && (
<>
{' '}
Find your{' '}
{hasServiceAccountsAccess && (
<Link
to={ROUTES.SERVICE_ACCOUNTS_SETTINGS}
className="license-key-callout__link"
>
Service account here
</Link>
)}
{hasServiceAccountsAccess && hasIngestionAccess && ' and '}
{hasIngestionAccess && (
<Link
to={ROUTES.INGESTION_SETTINGS}
className="license-key-callout__link"
>
Ingestion key here
</Link>
)}
.
</>
)}
</div>
</Callout>
<div className="license-key-callout">
<Callout.Closeable
color="info"
size="sm"
icon={<SolidInfoCircle />}
closed={false}
onClose={handleDismissCallout}
>
<div className="license-key-callout__description">
This is <strong>NOT</strong> your ingestion or Service account key.
{(hasServiceAccountsAccess || hasIngestionAccess) && (
<>
{' '}
Find your{' '}
{hasServiceAccountsAccess && (
<Link
to={ROUTES.SERVICE_ACCOUNTS_SETTINGS}
className="license-key-callout__link"
>
Service account here
</Link>
)}
{hasServiceAccountsAccess && hasIngestionAccess && ' and '}
{hasIngestionAccess && (
<Link
to={ROUTES.INGESTION_SETTINGS}
className="license-key-callout__link"
>
Ingestion key here
</Link>
)}
.
</>
)}
</div>
</Callout.Closeable>
</div>
) : null;
}

View File

@@ -134,6 +134,7 @@ function Retention({
min={0}
value={selectedValue && selectedValue >= 0 ? selectedValue : ''}
disabled={isCloudUserVal}
disabledTooltip={undefined}
onChange={(e): void => onChangeHandler(e, setSelectedValue)}
/>
<Select

View File

@@ -33,7 +33,7 @@ function StepsProgress({
steps={totalChecklistItems}
percent={progress}
showInfo={false}
strokeLinecap="butt"
color="primary"
/>
</div>
</div>

View File

@@ -9,7 +9,7 @@ import { K8sDetailsMetadataConfig } from 'container/InfraMonitoringK8sV2/Base/K8
import { INFRA_MONITORING_ATTR_KEYS } from 'container/InfraMonitoringK8sV2/constants';
import { formatValueForExpression } from 'components/QueryBuilderV2/utils';
import { TextNoData } from 'container/InfraMonitoringK8sV2/components';
import { getStrokeColorForPercent } from 'container/InfraMonitoringK8sV2/components/EntityProgressBar.utils';
import { getProgressColorForPercent } from 'container/InfraMonitoringK8sV2/components/EntityProgressBar.utils';
import { SelectedItemParams } from 'container/InfraMonitoringK8sV2/hooks';
import {
getHostQueryPayload,
@@ -52,7 +52,7 @@ export const hostDetailsMetadataConfig: HostDetailMetadataConfigType[] = [
render: (value): React.ReactNode => (
<Progress
percent={Number(Number(value).toFixed(1))}
strokeColor={getStrokeColorForPercent('cpu', Number(value))}
color={getProgressColorForPercent('cpu', Number(value))}
showInfo
/>
),
@@ -63,7 +63,7 @@ export const hostDetailsMetadataConfig: HostDetailMetadataConfigType[] = [
render: (value): React.ReactNode => (
<Progress
percent={Number(Number(value).toFixed(1))}
strokeColor={getStrokeColorForPercent('memory', Number(value))}
color={getProgressColorForPercent('memory', Number(value))}
showInfo
/>
),

View File

@@ -202,7 +202,7 @@ export default function K8sBaseDetails<T>({
>
<X />
</Button>
<Divider type="vertical" />
<Divider orientation="vertical" />
<Typography.Text className={styles.title}>
{entityName ||
((isEntityError || hasResponseError) && 'Failed to load entity details') ||

View File

@@ -41,9 +41,6 @@
.lineClampContainer {
padding: 12px;
--input-prefix-padding: var(--spacing-3);
--input-suffix-padding: var(--spacing-3);
}
.columnsList {

View File

@@ -169,7 +169,7 @@ function K8sOptionsSidePanel<TData>({
max={10}
value={lineClamp}
onChange={handleLineClampChange}
data-testid="line-clamp-input"
testId="line-clamp-input"
type="number"
prefix={
<Button

View File

@@ -1,8 +1,12 @@
import { MouseEvent, useCallback, useMemo, useState } from 'react';
import { useQueryClient } from 'react-query';
import {
RefreshCw,
SolidAlertTriangle,
SolidInfoCircle,
} from '@signozhq/icons';
import { Button } from '@signozhq/ui/button';
import { Callout } from '@signozhq/ui/callout';
import { RefreshCw } from '@signozhq/icons';
import setLocalStorage from 'api/browser/localstorage/set';
import {
invalidateGetChecks,
@@ -81,81 +85,80 @@ export function K8sInstrumentationChecksCallout({
return (
<div className={styles.checkContainer}>
<Callout
type={hasMissingItems ? 'warning' : 'info'}
showIcon
size="medium"
title={
<div className={styles.header}>
Instrumentation checks
<Button
variant="solid"
color="warning"
size="sm"
onClick={handleRecheck}
loading={isFetching}
prefix={<RefreshCw size={12} />}
testId="instrumentation-checks-recheck-btn"
>
Recheck
</Button>
</div>
}
action="expandable"
defaultExpanded={isExpanded}
onClick={handleExpandToggle}
color={hasMissingItems ? 'warning' : 'info'}
size="md"
icon={hasMissingItems ? <SolidAlertTriangle /> : <SolidInfoCircle />}
>
<div className={styles.container} onClick={(e) => e.stopPropagation()}>
<div className={styles.entriesList}>
{checksData.presentDefaultEnabledMetrics?.map((entry) => (
<PresentEntryRow
key={`present-default-${entry.associatedComponent.name}`}
entry={entry}
typeLabel="Default enabled metrics"
itemType="metrics"
/>
))}
{checksData.presentOptionalMetrics?.map((entry) => (
<PresentEntryRow
key={`present-optional-${entry.associatedComponent.name}`}
entry={entry}
typeLabel="Optional metrics"
itemType="metrics"
/>
))}
{checksData.presentRequiredAttributes?.map((entry) => (
<PresentEntryRow
key={`present-attrs-${entry.associatedComponent.name}`}
entry={entry}
typeLabel="Required attributes"
itemType="attributes"
/>
))}
{checksData.missingDefaultEnabledMetrics?.map((entry) => (
<MissingEntryRow
key={`missing-default-${entry.associatedComponent.name}`}
entry={entry}
typeLabel="Missing default metrics"
itemType="metrics"
/>
))}
{checksData.missingOptionalMetrics?.map((entry) => (
<MissingEntryRow
key={`missing-optional-${entry.associatedComponent.name}`}
entry={entry}
typeLabel="Missing optional metrics"
itemType="metrics"
/>
))}
{checksData.missingRequiredAttributes?.map((entry) => (
<MissingEntryRow
key={`missing-attrs-${entry.associatedComponent.name}`}
entry={entry}
typeLabel="Missing required attributes"
itemType="attributes"
/>
))}
</div>
<div className={styles.header}>
<button type="button" onClick={handleExpandToggle}>
Instrumentation checks
</button>
<Button
variant="solid"
color="warning"
size="sm"
onClick={handleRecheck}
loading={isFetching}
prefix={<RefreshCw size={12} />}
testId="instrumentation-checks-recheck-btn"
>
Recheck
</Button>
</div>
{isExpanded && (
<div className={styles.container}>
<div className={styles.entriesList}>
{checksData.presentDefaultEnabledMetrics?.map((entry) => (
<PresentEntryRow
key={`present-default-${entry.associatedComponent.name}`}
entry={entry}
typeLabel="Default enabled metrics"
itemType="metrics"
/>
))}
{checksData.presentOptionalMetrics?.map((entry) => (
<PresentEntryRow
key={`present-optional-${entry.associatedComponent.name}`}
entry={entry}
typeLabel="Optional metrics"
itemType="metrics"
/>
))}
{checksData.presentRequiredAttributes?.map((entry) => (
<PresentEntryRow
key={`present-attrs-${entry.associatedComponent.name}`}
entry={entry}
typeLabel="Required attributes"
itemType="attributes"
/>
))}
{checksData.missingDefaultEnabledMetrics?.map((entry) => (
<MissingEntryRow
key={`missing-default-${entry.associatedComponent.name}`}
entry={entry}
typeLabel="Missing default metrics"
itemType="metrics"
/>
))}
{checksData.missingOptionalMetrics?.map((entry) => (
<MissingEntryRow
key={`missing-optional-${entry.associatedComponent.name}`}
entry={entry}
typeLabel="Missing optional metrics"
itemType="metrics"
/>
))}
{checksData.missingRequiredAttributes?.map((entry) => (
<MissingEntryRow
key={`missing-attrs-${entry.associatedComponent.name}`}
entry={entry}
typeLabel="Missing required attributes"
itemType="attributes"
/>
))}
</div>
</div>
)}
</Callout>
</div>
);

View File

@@ -4,6 +4,8 @@
gap: 6px;
flex-wrap: wrap;
color: var(--l1-foreground);
--divider-border: var(--callout-warning-border);
}
.missingIcon {
@@ -21,7 +23,3 @@
margin-left: 4px;
}
}
.divider {
--divider-color: var(--callout-warning-border);
}

View File

@@ -60,7 +60,7 @@ export function MissingEntryRow({
<ExternalLink size={12} />
</Typography.Link>
)}
<Divider className={styles.divider} />
<Divider />
</div>
);
}

View File

@@ -4,13 +4,11 @@
gap: 6px;
flex-wrap: wrap;
color: var(--l1-foreground);
--divider-border: var(--callout-warning-border);
}
.presentIcon {
color: var(--success-background);
flex-shrink: 0;
}
.divider {
--divider-color: var(--callout-warning-border);
}

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