Compare commits

..

8 Commits

Author SHA1 Message Date
SagarRajput-7
24178ae20f chore: jest module resolution fix 2026-04-10 23:24:21 +05:30
SagarRajput-7
1bf38b5dba chore: added modulewrapper for jests 2026-04-10 14:52:44 +05:30
SagarRajput-7
67374c28d8 chore: more asset migration 2026-04-10 14:05:36 +05:30
SagarRajput-7
0723e89e52 chore: moved json to ts for the onboarding data sources 2026-04-10 14:02:41 +05:30
SagarRajput-7
dce5960728 chore: fixed formatting on homechecklist styles 2026-04-09 17:08:01 +05:30
SagarRajput-7
f4608087f4 feat: migrate public assets to src/assets with ES imports
Move public/Icons, public/Images, public/Logos, public/svgs to
src/assets/ and replace all string literal asset references across
74 files with ES imports via the @ alias.

Assets are now processed through Vite's module pipeline, making them
content-hashed in dist/ and base-path-aware — prerequisite for the
runtime URL prefix feature (base path).

Known gap: src/ReactI18/index.tsx loadPath still uses absolute /locales/
path — to be fixed in the base path feature PR.
2026-04-09 17:08:01 +05:30
SagarRajput-7
11fab85b50 fix: correct broken SCSS asset url() references 2026-04-09 17:08:01 +05:30
SagarRajput-7
41b7c1c71c chore: add @ alias and base:./ for asset migration 2026-04-09 17:08:01 +05:30
649 changed files with 41865 additions and 23186 deletions

View File

@@ -8,7 +8,6 @@ import (
"github.com/SigNoz/signoz/cmd"
"github.com/SigNoz/signoz/pkg/analytics"
"github.com/SigNoz/signoz/pkg/auditor"
"github.com/SigNoz/signoz/pkg/authn"
"github.com/SigNoz/signoz/pkg/authz"
"github.com/SigNoz/signoz/pkg/authz/openfgaauthz"
@@ -18,15 +17,11 @@ import (
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/gateway"
"github.com/SigNoz/signoz/pkg/gateway/noopgateway"
"github.com/SigNoz/signoz/pkg/global"
"github.com/SigNoz/signoz/pkg/licensing"
"github.com/SigNoz/signoz/pkg/licensing/nooplicensing"
"github.com/SigNoz/signoz/pkg/modules/cloudintegration"
"github.com/SigNoz/signoz/pkg/modules/cloudintegration/implcloudintegration"
"github.com/SigNoz/signoz/pkg/modules/dashboard"
"github.com/SigNoz/signoz/pkg/modules/dashboard/impldashboard"
"github.com/SigNoz/signoz/pkg/modules/organization"
"github.com/SigNoz/signoz/pkg/modules/serviceaccount"
"github.com/SigNoz/signoz/pkg/querier"
"github.com/SigNoz/signoz/pkg/query-service/app"
"github.com/SigNoz/signoz/pkg/queryparser"
@@ -98,15 +93,9 @@ func runServer(ctx context.Context, config signoz.Config, logger *slog.Logger) e
func(_ licensing.Licensing) factory.ProviderFactory[gateway.Gateway, gateway.Config] {
return noopgateway.NewProviderFactory()
},
func(_ licensing.Licensing) factory.NamedMap[factory.ProviderFactory[auditor.Auditor, auditor.Config]] {
return signoz.NewAuditorProviderFactories()
},
func(ps factory.ProviderSettings, q querier.Querier, a analytics.Analytics) querier.Handler {
return querier.NewHandler(ps, q, a)
},
func(_ sqlstore.SQLStore, _ global.Global, _ zeus.Zeus, _ gateway.Gateway, _ licensing.Licensing, _ serviceaccount.Module, _ cloudintegration.Config) (cloudintegration.Module, error) {
return implcloudintegration.NewModule(), nil
},
)
if err != nil {
logger.ErrorContext(ctx, "failed to create signoz", errors.Attr(err))

View File

@@ -8,7 +8,6 @@ import (
"github.com/spf13/cobra"
"github.com/SigNoz/signoz/cmd"
"github.com/SigNoz/signoz/ee/auditor/otlphttpauditor"
"github.com/SigNoz/signoz/ee/authn/callbackauthn/oidccallbackauthn"
"github.com/SigNoz/signoz/ee/authn/callbackauthn/samlcallbackauthn"
"github.com/SigNoz/signoz/ee/authz/openfgaauthz"
@@ -17,8 +16,6 @@ import (
"github.com/SigNoz/signoz/ee/gateway/httpgateway"
enterpriselicensing "github.com/SigNoz/signoz/ee/licensing"
"github.com/SigNoz/signoz/ee/licensing/httplicensing"
"github.com/SigNoz/signoz/ee/modules/cloudintegration/implcloudintegration"
"github.com/SigNoz/signoz/ee/modules/cloudintegration/implcloudintegration/implcloudprovider"
"github.com/SigNoz/signoz/ee/modules/dashboard/impldashboard"
eequerier "github.com/SigNoz/signoz/ee/querier"
enterpriseapp "github.com/SigNoz/signoz/ee/query-service/app"
@@ -27,20 +24,15 @@ import (
enterprisezeus "github.com/SigNoz/signoz/ee/zeus"
"github.com/SigNoz/signoz/ee/zeus/httpzeus"
"github.com/SigNoz/signoz/pkg/analytics"
"github.com/SigNoz/signoz/pkg/auditor"
"github.com/SigNoz/signoz/pkg/authn"
"github.com/SigNoz/signoz/pkg/authz"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/gateway"
"github.com/SigNoz/signoz/pkg/global"
"github.com/SigNoz/signoz/pkg/licensing"
"github.com/SigNoz/signoz/pkg/modules/cloudintegration"
pkgcloudintegration "github.com/SigNoz/signoz/pkg/modules/cloudintegration/implcloudintegration"
"github.com/SigNoz/signoz/pkg/modules/dashboard"
pkgimpldashboard "github.com/SigNoz/signoz/pkg/modules/dashboard/impldashboard"
"github.com/SigNoz/signoz/pkg/modules/organization"
"github.com/SigNoz/signoz/pkg/modules/serviceaccount"
"github.com/SigNoz/signoz/pkg/querier"
"github.com/SigNoz/signoz/pkg/queryparser"
"github.com/SigNoz/signoz/pkg/signoz"
@@ -48,7 +40,6 @@ import (
"github.com/SigNoz/signoz/pkg/sqlstore"
"github.com/SigNoz/signoz/pkg/sqlstore/sqlstorehook"
"github.com/SigNoz/signoz/pkg/types/authtypes"
"github.com/SigNoz/signoz/pkg/types/cloudintegrationtypes"
"github.com/SigNoz/signoz/pkg/version"
"github.com/SigNoz/signoz/pkg/zeus"
)
@@ -134,6 +125,7 @@ func runServer(ctx context.Context, config signoz.Config, logger *slog.Logger) e
return nil, err
}
return openfgaauthz.NewProviderFactory(sqlstore, openfgaschema.NewSchema().Get(ctx), openfgaDataStore, licensing, dashboardModule), nil
},
func(store sqlstore.SQLStore, settings factory.ProviderSettings, analytics analytics.Analytics, orgGetter organization.Getter, queryParser queryparser.QueryParser, querier querier.Querier, licensing licensing.Licensing) dashboard.Module {
return impldashboard.NewModule(pkgimpldashboard.NewStore(store), settings, analytics, orgGetter, queryParser, querier, licensing)
@@ -141,32 +133,12 @@ func runServer(ctx context.Context, config signoz.Config, logger *slog.Logger) e
func(licensing licensing.Licensing) factory.ProviderFactory[gateway.Gateway, gateway.Config] {
return httpgateway.NewProviderFactory(licensing)
},
func(licensing licensing.Licensing) factory.NamedMap[factory.ProviderFactory[auditor.Auditor, auditor.Config]] {
factories := signoz.NewAuditorProviderFactories()
if err := factories.Add(otlphttpauditor.NewFactory(licensing, version.Info)); err != nil {
panic(err)
}
return factories
},
func(ps factory.ProviderSettings, q querier.Querier, a analytics.Analytics) querier.Handler {
communityHandler := querier.NewHandler(ps, q, a)
return eequerier.NewHandler(ps, q, communityHandler)
},
func(sqlStore sqlstore.SQLStore, global global.Global, zeus zeus.Zeus, gateway gateway.Gateway, licensing licensing.Licensing, serviceAccount serviceaccount.Module, config cloudintegration.Config) (cloudintegration.Module, error) {
defStore := pkgcloudintegration.NewServiceDefinitionStore()
awsCloudProviderModule, err := implcloudprovider.NewAWSCloudProvider(defStore)
if err != nil {
return nil, err
}
azureCloudProviderModule := implcloudprovider.NewAzureCloudProvider()
cloudProvidersMap := map[cloudintegrationtypes.CloudProviderType]cloudintegration.CloudProviderModule{
cloudintegrationtypes.CloudProviderTypeAWS: awsCloudProviderModule,
cloudintegrationtypes.CloudProviderTypeAzure: azureCloudProviderModule,
}
return implcloudintegration.NewModule(pkgcloudintegration.NewStore(sqlStore), global, zeus, gateway, licensing, serviceAccount, cloudProvidersMap, config)
},
)
if err != nil {
logger.ErrorContext(ctx, "failed to create signoz", errors.Attr(err))
return err

View File

@@ -82,9 +82,6 @@ sqlstore:
provider: sqlite
# The maximum number of open connections to the database.
max_open_conns: 100
# The maximum amount of time a connection may be reused.
# If max_conn_lifetime == 0, connections are not closed due to a connection's age.
max_conn_lifetime: 0
sqlite:
# The path to the SQLite database file.
path: /var/lib/signoz/signoz.db
@@ -367,41 +364,3 @@ serviceaccount:
analytics:
# toggle service account analytics
enabled: true
##################### Auditor #####################
auditor:
# Specifies the auditor provider to use.
# noop: discards all audit events (community default).
# otlphttp: exports audit events via OTLP HTTP (enterprise).
provider: noop
# The async channel capacity for audit events. Events are dropped when full (fail-open).
buffer_size: 1000
# The maximum number of events per export batch.
batch_size: 100
# The maximum time between export flushes.
flush_interval: 1s
otlphttp:
# The target scheme://host:port/path of the OTLP HTTP endpoint.
endpoint: http://localhost:4318/v1/logs
# Whether to use HTTP instead of HTTPS.
insecure: false
# The maximum duration for an export attempt.
timeout: 10s
# Additional HTTP headers sent with every export request.
headers: {}
retry:
# Whether to retry on transient failures.
enabled: true
# The initial wait time before the first retry.
initial_interval: 5s
# The upper bound on backoff interval.
max_interval: 30s
# The total maximum time spent retrying.
max_elapsed_time: 60s
##################### Cloud Integration #####################
cloudintegration:
# cloud integration agent configuration
agent:
# The version of the cloud integration agent.
version: v0.0.8

View File

@@ -190,7 +190,7 @@ services:
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
signoz:
!!merge <<: *db-depend
image: signoz/signoz:v0.119.0
image: signoz/signoz:v0.118.0
ports:
- "8080:8080" # signoz port
# - "6060:6060" # pprof port

View File

@@ -117,7 +117,7 @@ services:
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
signoz:
!!merge <<: *db-depend
image: signoz/signoz:v0.119.0
image: signoz/signoz:v0.118.0
ports:
- "8080:8080" # signoz port
volumes:

View File

@@ -181,7 +181,7 @@ services:
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
signoz:
!!merge <<: *db-depend
image: signoz/signoz:${VERSION:-v0.119.0}
image: signoz/signoz:${VERSION:-v0.118.0}
container_name: signoz
ports:
- "8080:8080" # signoz port

View File

@@ -109,7 +109,7 @@ services:
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
signoz:
!!merge <<: *db-depend
image: signoz/signoz:${VERSION:-v0.119.0}
image: signoz/signoz:${VERSION:-v0.118.0}
container_name: signoz
ports:
- "8080:8080" # signoz port

File diff suppressed because it is too large Load Diff

View File

@@ -7,12 +7,12 @@ This guide explains how to add new data sources to the SigNoz onboarding flow. T
The configuration is located at:
```
frontend/src/container/OnboardingV2Container/onboarding-configs/onboarding-config-with-links.ts
frontend/src/container/OnboardingV2Container/onboarding-configs/onboarding-config-with-links.json
```
## Structure Overview
## JSON Structure Overview
The configuration file exports a TypeScript array (`onboardingConfigWithLinks`) containing data source objects. Each object represents a selectable option in the onboarding flow. SVG logos are imported as ES modules at the top of the file.
The configuration file is a JSON array containing data source objects. Each object represents a selectable option in the onboarding flow.
## Data Source Object Keys
@@ -24,7 +24,7 @@ The configuration file exports a TypeScript array (`onboardingConfigWithLinks`)
| `label` | `string` | Display name shown to users (e.g., `"AWS EC2"`) |
| `tags` | `string[]` | Array of category tags for grouping (e.g., `["AWS"]`, `["database"]`) |
| `module` | `string` | Destination module after onboarding completion |
| `imgUrl` | `string` | Imported SVG URL **(SVG required)** (e.g., `import ec2Url from '@/assets/Logos/ec2.svg'`, then use `ec2Url`) |
| `imgUrl` | `string` | Path to the logo/icon **(SVG required)** (e.g., `"/Logos/ec2.svg"`) |
### Optional Keys
@@ -57,34 +57,36 @@ The `module` key determines where users are redirected after completing onboardi
The `question` object enables multi-step selection flows:
```ts
question: {
desc: 'What would you like to monitor?',
type: 'select',
helpText: 'Choose the telemetry type you want to collect.',
helpLink: '/docs/azure-monitoring/overview/',
helpLinkText: 'Read the guide →',
options: [
{
key: 'logging',
label: 'Logs',
imgUrl: azureVmUrl,
link: '/docs/azure-monitoring/app-service/logging/',
},
{
key: 'metrics',
label: 'Metrics',
imgUrl: azureVmUrl,
link: '/docs/azure-monitoring/app-service/metrics/',
},
{
key: 'tracing',
label: 'Traces',
imgUrl: azureVmUrl,
link: '/docs/azure-monitoring/app-service/tracing/',
},
],
},
```json
{
"question": {
"desc": "What would you like to monitor?",
"type": "select",
"helpText": "Choose the telemetry type you want to collect.",
"helpLink": "/docs/azure-monitoring/overview/",
"helpLinkText": "Read the guide →",
"options": [
{
"key": "logging",
"label": "Logs",
"imgUrl": "/Logos/azure-vm.svg",
"link": "/docs/azure-monitoring/app-service/logging/"
},
{
"key": "metrics",
"label": "Metrics",
"imgUrl": "/Logos/azure-vm.svg",
"link": "/docs/azure-monitoring/app-service/metrics/"
},
{
"key": "tracing",
"label": "Traces",
"imgUrl": "/Logos/azure-vm.svg",
"link": "/docs/azure-monitoring/app-service/tracing/"
}
]
}
}
```
### Question Keys
@@ -104,161 +106,152 @@ Options can be simple (direct link) or nested (with another question):
### Simple Option (Direct Link)
```ts
```json
{
key: 'aws-ec2-logs',
label: 'Logs',
imgUrl: ec2Url,
link: '/docs/userguide/collect_logs_from_file/',
},
"key": "aws-ec2-logs",
"label": "Logs",
"imgUrl": "/Logos/ec2.svg",
"link": "/docs/userguide/collect_logs_from_file/"
}
```
### Option with Internal Redirect
```ts
```json
{
key: 'aws-ec2-metrics-one-click',
label: 'One Click AWS',
imgUrl: ec2Url,
link: '/integrations?integration=aws-integration&service=ec2',
internalRedirect: true,
},
"key": "aws-ec2-metrics-one-click",
"label": "One Click AWS",
"imgUrl": "/Logos/ec2.svg",
"link": "/integrations?integration=aws-integration&service=ec2",
"internalRedirect": true
}
```
> **Important**: Set `internalRedirect: true` only for internal app routes (like `/integrations?...`). Docs links should NOT have this flag.
### Nested Option (Multi-step Flow)
```ts
```json
{
key: 'aws-ec2-metrics',
label: 'Metrics',
imgUrl: ec2Url,
question: {
desc: 'How would you like to set up monitoring?',
helpText: 'Choose your setup method.',
options: [...],
},
},
"key": "aws-ec2-metrics",
"label": "Metrics",
"imgUrl": "/Logos/ec2.svg",
"question": {
"desc": "How would you like to set up monitoring?",
"helpText": "Choose your setup method.",
"options": [...]
}
}
```
## Examples
### Simple Data Source (Direct Link)
```ts
import elbUrl from '@/assets/Logos/elb.svg';
// inside the onboardingConfigWithLinks array:
```json
{
dataSource: 'aws-elb',
label: 'AWS ELB',
tags: ['AWS'],
module: 'logs',
relatedSearchKeywords: [
'aws',
'aws elb',
'elb logs',
'elastic load balancer',
"dataSource": "aws-elb",
"label": "AWS ELB",
"tags": ["AWS"],
"module": "logs",
"relatedSearchKeywords": [
"aws",
"aws elb",
"elb logs",
"elastic load balancer"
],
imgUrl: elbUrl,
link: '/docs/aws-monitoring/elb/',
},
"imgUrl": "/Logos/elb.svg",
"link": "/docs/aws-monitoring/elb/"
}
```
### Data Source with Single Question Level
```ts
import azureVmUrl from '@/assets/Logos/azure-vm.svg';
// inside the onboardingConfigWithLinks array:
```json
{
dataSource: 'app-service',
label: 'App Service',
imgUrl: azureVmUrl,
tags: ['Azure'],
module: 'apm',
relatedSearchKeywords: ['azure', 'app service'],
question: {
desc: 'What telemetry data do you want to visualise?',
type: 'select',
options: [
"dataSource": "app-service",
"label": "App Service",
"imgUrl": "/Logos/azure-vm.svg",
"tags": ["Azure"],
"module": "apm",
"relatedSearchKeywords": ["azure", "app service"],
"question": {
"desc": "What telemetry data do you want to visualise?",
"type": "select",
"options": [
{
key: 'logging',
label: 'Logs',
imgUrl: azureVmUrl,
link: '/docs/azure-monitoring/app-service/logging/',
"key": "logging",
"label": "Logs",
"imgUrl": "/Logos/azure-vm.svg",
"link": "/docs/azure-monitoring/app-service/logging/"
},
{
key: 'metrics',
label: 'Metrics',
imgUrl: azureVmUrl,
link: '/docs/azure-monitoring/app-service/metrics/',
"key": "metrics",
"label": "Metrics",
"imgUrl": "/Logos/azure-vm.svg",
"link": "/docs/azure-monitoring/app-service/metrics/"
},
{
key: 'tracing',
label: 'Traces',
imgUrl: azureVmUrl,
link: '/docs/azure-monitoring/app-service/tracing/',
},
],
},
},
"key": "tracing",
"label": "Traces",
"imgUrl": "/Logos/azure-vm.svg",
"link": "/docs/azure-monitoring/app-service/tracing/"
}
]
}
}
```
### Data Source with Nested Questions (2-3 Levels)
```ts
import ec2Url from '@/assets/Logos/ec2.svg';
// inside the onboardingConfigWithLinks array:
```json
{
dataSource: 'aws-ec2',
label: 'AWS EC2',
tags: ['AWS'],
module: 'logs',
relatedSearchKeywords: ['aws', 'aws ec2', 'ec2 logs', 'ec2 metrics'],
imgUrl: ec2Url,
question: {
desc: 'What would you like to monitor for AWS EC2?',
type: 'select',
helpText: 'Choose the type of telemetry data you want to collect.',
options: [
"dataSource": "aws-ec2",
"label": "AWS EC2",
"tags": ["AWS"],
"module": "logs",
"relatedSearchKeywords": ["aws", "aws ec2", "ec2 logs", "ec2 metrics"],
"imgUrl": "/Logos/ec2.svg",
"question": {
"desc": "What would you like to monitor for AWS EC2?",
"type": "select",
"helpText": "Choose the type of telemetry data you want to collect.",
"options": [
{
key: 'aws-ec2-logs',
label: 'Logs',
imgUrl: ec2Url,
link: '/docs/userguide/collect_logs_from_file/',
"key": "aws-ec2-logs",
"label": "Logs",
"imgUrl": "/Logos/ec2.svg",
"link": "/docs/userguide/collect_logs_from_file/"
},
{
key: 'aws-ec2-metrics',
label: 'Metrics',
imgUrl: ec2Url,
question: {
desc: 'How would you like to set up EC2 Metrics monitoring?',
helpText: 'One Click uses AWS CloudWatch integration. Manual setup uses OpenTelemetry.',
helpLink: '/docs/aws-monitoring/one-click-vs-manual/',
helpLinkText: 'Read the comparison guide →',
options: [
"key": "aws-ec2-metrics",
"label": "Metrics",
"imgUrl": "/Logos/ec2.svg",
"question": {
"desc": "How would you like to set up EC2 Metrics monitoring?",
"helpText": "One Click uses AWS CloudWatch integration. Manual setup uses OpenTelemetry.",
"helpLink": "/docs/aws-monitoring/one-click-vs-manual/",
"helpLinkText": "Read the comparison guide →",
"options": [
{
key: 'aws-ec2-metrics-one-click',
label: 'One Click AWS',
imgUrl: ec2Url,
link: '/integrations?integration=aws-integration&service=ec2',
internalRedirect: true,
"key": "aws-ec2-metrics-one-click",
"label": "One Click AWS",
"imgUrl": "/Logos/ec2.svg",
"link": "/integrations?integration=aws-integration&service=ec2",
"internalRedirect": true
},
{
key: 'aws-ec2-metrics-manual',
label: 'Manual Setup',
imgUrl: ec2Url,
link: '/docs/tutorial/opentelemetry-binary-usage-in-virtual-machine/',
},
],
},
},
],
},
},
"key": "aws-ec2-metrics-manual",
"label": "Manual Setup",
"imgUrl": "/Logos/ec2.svg",
"link": "/docs/tutorial/opentelemetry-binary-usage-in-virtual-machine/"
}
]
}
}
]
}
}
```
## Best Practices
@@ -277,16 +270,11 @@ import ec2Url from '@/assets/Logos/ec2.svg';
### 3. Logos
- Place logo files in `src/assets/Logos/`
- Place logo files in `public/Logos/`
- Use SVG format
- Import the SVG at the top of the file and reference the imported variable:
```ts
import myServiceUrl from '@/assets/Logos/my-service.svg';
// then in the config object:
imgUrl: myServiceUrl,
```
- Reference as `"/Logos/your-logo.svg"`
- **Fetching Icons**: New icons can be easily fetched from [OpenBrand](https://openbrand.sh/). Use the pattern `https://openbrand.sh/?url=<TARGET_URL>`, where `<TARGET_URL>` is the URL-encoded link to the service's website. For example, to get Render's logo, use [https://openbrand.sh/?url=https%3A%2F%2Frender.com](https://openbrand.sh/?url=https%3A%2F%2Frender.com).
- **Optimize new SVGs**: Run any newly downloaded SVGs through an optimizer like [SVGOMG (svgo)](https://svgomg.net/) or use `npx svgo src/assets/Logos/your-logo.svg` to minimise their size before committing.
- **Optimize new SVGs**: Run any newly downloaded SVGs through an optimizer like [SVGOMG (svgo)](https://svgomg.net/) or use `npx svgo public/Logos/your-logo.svg` to minimise their size before committing.
### 4. Links
@@ -302,8 +290,8 @@ import ec2Url from '@/assets/Logos/ec2.svg';
## Adding a New Data Source
1. Add the logo SVG to `src/assets/Logos/` and add a top-level import in the config file (e.g., `import myServiceUrl from '@/assets/Logos/my-service.svg'`)
2. Add your data source object to the `onboardingConfigWithLinks` array, referencing the imported variable for `imgUrl`
1. Add your data source object to the JSON array
2. Ensure the logo exists in `public/Logos/`
3. Test the flow locally with `yarn dev`
4. Validation:
- Navigate to the [onboarding page](http://localhost:3301/get-started-with-signoz-cloud) on your local machine

View File

@@ -1,132 +0,0 @@
package implcloudprovider
import (
"context"
"fmt"
"net/url"
"sort"
"github.com/SigNoz/signoz/pkg/modules/cloudintegration"
"github.com/SigNoz/signoz/pkg/types/cloudintegrationtypes"
)
type awscloudprovider struct {
serviceDefinitions cloudintegrationtypes.ServiceDefinitionStore
}
func NewAWSCloudProvider(defStore cloudintegrationtypes.ServiceDefinitionStore) (cloudintegration.CloudProviderModule, error) {
return &awscloudprovider{serviceDefinitions: defStore}, nil
}
func (provider *awscloudprovider) GetConnectionArtifact(ctx context.Context, account *cloudintegrationtypes.Account, req *cloudintegrationtypes.GetConnectionArtifactRequest) (*cloudintegrationtypes.ConnectionArtifact, error) {
baseURL := fmt.Sprintf(cloudintegrationtypes.CloudFormationQuickCreateBaseURL.StringValue(), req.Config.Aws.DeploymentRegion)
u, _ := url.Parse(baseURL)
q := u.Query()
q.Set("region", req.Config.Aws.DeploymentRegion)
u.Fragment = "/stacks/quickcreate"
u.RawQuery = q.Encode()
q = u.Query()
q.Set("stackName", cloudintegrationtypes.AgentCloudFormationBaseStackName.StringValue())
q.Set("templateURL", fmt.Sprintf(cloudintegrationtypes.AgentCloudFormationTemplateS3Path.StringValue(), req.Config.AgentVersion))
q.Set("param_SigNozIntegrationAgentVersion", req.Config.AgentVersion)
q.Set("param_SigNozApiUrl", req.Credentials.SigNozAPIURL)
q.Set("param_SigNozApiKey", req.Credentials.SigNozAPIKey)
q.Set("param_SigNozAccountId", account.ID.StringValue())
q.Set("param_IngestionUrl", req.Credentials.IngestionURL)
q.Set("param_IngestionKey", req.Credentials.IngestionKey)
return &cloudintegrationtypes.ConnectionArtifact{
Aws: &cloudintegrationtypes.AWSConnectionArtifact{
ConnectionURL: u.String() + "?&" + q.Encode(), // this format is required by AWS
},
}, nil
}
func (provider *awscloudprovider) ListServiceDefinitions(ctx context.Context) ([]*cloudintegrationtypes.ServiceDefinition, error) {
return provider.serviceDefinitions.List(ctx, cloudintegrationtypes.CloudProviderTypeAWS)
}
func (provider *awscloudprovider) GetServiceDefinition(ctx context.Context, serviceID cloudintegrationtypes.ServiceID) (*cloudintegrationtypes.ServiceDefinition, error) {
serviceDef, err := provider.serviceDefinitions.Get(ctx, cloudintegrationtypes.CloudProviderTypeAWS, serviceID)
if err != nil {
return nil, err
}
// override cloud integration dashboard id
for index, dashboard := range serviceDef.Assets.Dashboards {
serviceDef.Assets.Dashboards[index].ID = cloudintegrationtypes.GetCloudIntegrationDashboardID(cloudintegrationtypes.CloudProviderTypeAWS, serviceID.StringValue(), dashboard.ID)
}
return serviceDef, nil
}
func (provider *awscloudprovider) BuildIntegrationConfig(
ctx context.Context,
account *cloudintegrationtypes.Account,
services []*cloudintegrationtypes.StorableCloudIntegrationService,
) (*cloudintegrationtypes.ProviderIntegrationConfig, error) {
// Sort services for deterministic output
sort.Slice(services, func(i, j int) bool {
return services[i].Type.StringValue() < services[j].Type.StringValue()
})
compiledMetrics := new(cloudintegrationtypes.AWSMetricsCollectionStrategy)
compiledLogs := new(cloudintegrationtypes.AWSLogsCollectionStrategy)
var compiledS3Buckets map[string][]string
for _, storedSvc := range services {
svcCfg, err := cloudintegrationtypes.NewServiceConfigFromJSON(cloudintegrationtypes.CloudProviderTypeAWS, storedSvc.Config)
if err != nil {
return nil, err
}
svcDef, err := provider.GetServiceDefinition(ctx, storedSvc.Type)
if err != nil {
return nil, err
}
strategy := svcDef.TelemetryCollectionStrategy.AWS
logsEnabled := svcCfg.IsLogsEnabled(cloudintegrationtypes.CloudProviderTypeAWS)
// S3Sync: logs come directly from configured S3 buckets, not CloudWatch subscriptions
if storedSvc.Type == cloudintegrationtypes.AWSServiceS3Sync {
if logsEnabled && svcCfg.AWS.Logs.S3Buckets != nil {
compiledS3Buckets = svcCfg.AWS.Logs.S3Buckets
}
// no need to go ahead as the code block specifically checks for the S3Sync service
continue
}
if logsEnabled && strategy.Logs != nil {
compiledLogs.Subscriptions = append(compiledLogs.Subscriptions, strategy.Logs.Subscriptions...)
}
metricsEnabled := svcCfg.IsMetricsEnabled(cloudintegrationtypes.CloudProviderTypeAWS)
if metricsEnabled && strategy.Metrics != nil {
compiledMetrics.StreamFilters = append(compiledMetrics.StreamFilters, strategy.Metrics.StreamFilters...)
}
}
collectionStrategy := new(cloudintegrationtypes.AWSTelemetryCollectionStrategy)
if len(compiledMetrics.StreamFilters) > 0 {
collectionStrategy.Metrics = compiledMetrics
}
if len(compiledLogs.Subscriptions) > 0 {
collectionStrategy.Logs = compiledLogs
}
if compiledS3Buckets != nil {
collectionStrategy.S3Buckets = compiledS3Buckets
}
return &cloudintegrationtypes.ProviderIntegrationConfig{
AWS: &cloudintegrationtypes.AWSIntegrationConfig{
EnabledRegions: account.Config.AWS.Regions,
TelemetryCollectionStrategy: collectionStrategy,
},
}, nil
}

View File

@@ -1,34 +0,0 @@
package implcloudprovider
import (
"context"
"github.com/SigNoz/signoz/pkg/modules/cloudintegration"
"github.com/SigNoz/signoz/pkg/types/cloudintegrationtypes"
)
type azurecloudprovider struct{}
func NewAzureCloudProvider() cloudintegration.CloudProviderModule {
return &azurecloudprovider{}
}
func (provider *azurecloudprovider) GetConnectionArtifact(ctx context.Context, account *cloudintegrationtypes.Account, req *cloudintegrationtypes.GetConnectionArtifactRequest) (*cloudintegrationtypes.ConnectionArtifact, error) {
panic("implement me")
}
func (provider *azurecloudprovider) ListServiceDefinitions(ctx context.Context) ([]*cloudintegrationtypes.ServiceDefinition, error) {
panic("implement me")
}
func (provider *azurecloudprovider) GetServiceDefinition(ctx context.Context, serviceID cloudintegrationtypes.ServiceID) (*cloudintegrationtypes.ServiceDefinition, error) {
panic("implement me")
}
func (provider *azurecloudprovider) BuildIntegrationConfig(
ctx context.Context,
account *cloudintegrationtypes.Account,
services []*cloudintegrationtypes.StorableCloudIntegrationService,
) (*cloudintegrationtypes.ProviderIntegrationConfig, error) {
panic("implement me")
}

View File

@@ -1,540 +0,0 @@
package implcloudintegration
import (
"context"
"fmt"
"sort"
"time"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/gateway"
"github.com/SigNoz/signoz/pkg/global"
"github.com/SigNoz/signoz/pkg/licensing"
"github.com/SigNoz/signoz/pkg/modules/cloudintegration"
"github.com/SigNoz/signoz/pkg/modules/serviceaccount"
"github.com/SigNoz/signoz/pkg/types/authtypes"
"github.com/SigNoz/signoz/pkg/types/cloudintegrationtypes"
"github.com/SigNoz/signoz/pkg/types/dashboardtypes"
"github.com/SigNoz/signoz/pkg/types/serviceaccounttypes"
"github.com/SigNoz/signoz/pkg/types/zeustypes"
"github.com/SigNoz/signoz/pkg/valuer"
"github.com/SigNoz/signoz/pkg/zeus"
)
type module struct {
store cloudintegrationtypes.Store
gateway gateway.Gateway
zeus zeus.Zeus
licensing licensing.Licensing
global global.Global
serviceAccount serviceaccount.Module
cloudProvidersMap map[cloudintegrationtypes.CloudProviderType]cloudintegration.CloudProviderModule
config cloudintegration.Config
}
func NewModule(
store cloudintegrationtypes.Store,
global global.Global,
zeus zeus.Zeus,
gateway gateway.Gateway,
licensing licensing.Licensing,
serviceAccount serviceaccount.Module,
cloudProvidersMap map[cloudintegrationtypes.CloudProviderType]cloudintegration.CloudProviderModule,
config cloudintegration.Config,
) (cloudintegration.Module, error) {
return &module{
store: store,
global: global,
zeus: zeus,
gateway: gateway,
licensing: licensing,
serviceAccount: serviceAccount,
cloudProvidersMap: cloudProvidersMap,
config: config,
}, nil
}
// GetConnectionCredentials returns credentials required to generate connection artifact. eg. apiKey, ingestionKey etc.
// It will return creds it can deduce and return empty value for others.
func (module *module) GetConnectionCredentials(ctx context.Context, orgID valuer.UUID, provider cloudintegrationtypes.CloudProviderType) (*cloudintegrationtypes.Credentials, error) {
// get license to get the deployment details
license, err := module.licensing.GetActive(ctx, orgID)
if err != nil {
return nil, errors.New(errors.TypeLicenseUnavailable, errors.CodeLicenseUnavailable, "a valid license is not available").WithAdditional("this feature requires a valid license").WithAdditional(err.Error())
}
// get deployment details from zeus, ignore error
respBytes, _ := module.zeus.GetDeployment(ctx, license.Key)
var signozAPIURL string
if len(respBytes) > 0 {
// parse deployment details, ignore error, if client is asking api url every time check for possible error
deployment, _ := zeustypes.NewGettableDeployment(respBytes)
if deployment != nil {
signozAPIURL, _ = cloudintegrationtypes.GetSigNozAPIURLFromDeployment(deployment)
}
}
// ignore error
apiKey, _ := module.getOrCreateAPIKey(ctx, orgID, provider)
// ignore error
ingestionKey, _ := module.getOrCreateIngestionKey(ctx, orgID, provider)
return cloudintegrationtypes.NewCredentials(
signozAPIURL,
apiKey,
module.global.GetConfig(ctx).IngestionURL,
ingestionKey,
), nil
}
func (module *module) CreateAccount(ctx context.Context, account *cloudintegrationtypes.Account) error {
_, err := module.licensing.GetActive(ctx, account.OrgID)
if err != nil {
return errors.New(errors.TypeLicenseUnavailable, errors.CodeLicenseUnavailable, "a valid license is not available").WithAdditional("this feature requires a valid license").WithAdditional(err.Error())
}
storableCloudIntegration, err := cloudintegrationtypes.NewStorableCloudIntegration(account)
if err != nil {
return err
}
return module.store.CreateAccount(ctx, storableCloudIntegration)
}
func (module *module) GetConnectionArtifact(ctx context.Context, account *cloudintegrationtypes.Account, req *cloudintegrationtypes.GetConnectionArtifactRequest) (*cloudintegrationtypes.ConnectionArtifact, error) {
_, err := module.licensing.GetActive(ctx, account.OrgID)
if err != nil {
return nil, errors.New(errors.TypeLicenseUnavailable, errors.CodeLicenseUnavailable, "a valid license is not available").WithAdditional("this feature requires a valid license").WithAdditional(err.Error())
}
cloudProviderModule, err := module.getCloudProvider(account.Provider)
if err != nil {
return nil, err
}
req.Config.SetAgentVersion(module.config.Agent.Version)
return cloudProviderModule.GetConnectionArtifact(ctx, account, req)
}
func (module *module) GetAccount(ctx context.Context, orgID valuer.UUID, accountID valuer.UUID, provider cloudintegrationtypes.CloudProviderType) (*cloudintegrationtypes.Account, error) {
_, err := module.licensing.GetActive(ctx, orgID)
if err != nil {
return nil, errors.New(errors.TypeLicenseUnavailable, errors.CodeLicenseUnavailable, "a valid license is not available").WithAdditional("this feature requires a valid license").WithAdditional(err.Error())
}
storableAccount, err := module.store.GetAccountByID(ctx, orgID, accountID, provider)
if err != nil {
return nil, err
}
return cloudintegrationtypes.NewAccountFromStorable(storableAccount)
}
func (module *module) GetConnectedAccount(ctx context.Context, orgID, accountID valuer.UUID, provider cloudintegrationtypes.CloudProviderType) (*cloudintegrationtypes.Account, error) {
_, err := module.licensing.GetActive(ctx, orgID)
if err != nil {
return nil, errors.New(errors.TypeLicenseUnavailable, errors.CodeLicenseUnavailable, "a valid license is not available").WithAdditional("this feature requires a valid license").WithAdditional(err.Error())
}
storableAccount, err := module.store.GetConnectedAccount(ctx, orgID, accountID, provider)
if err != nil {
return nil, err
}
return cloudintegrationtypes.NewAccountFromStorable(storableAccount)
}
// ListAccounts return only agent connected accounts.
func (module *module) ListAccounts(ctx context.Context, orgID valuer.UUID, provider cloudintegrationtypes.CloudProviderType) ([]*cloudintegrationtypes.Account, error) {
_, err := module.licensing.GetActive(ctx, orgID)
if err != nil {
return nil, errors.New(errors.TypeLicenseUnavailable, errors.CodeLicenseUnavailable, "a valid license is not available").WithAdditional("this feature requires a valid license").WithAdditional(err.Error())
}
storableAccounts, err := module.store.ListConnectedAccounts(ctx, orgID, provider)
if err != nil {
return nil, err
}
return cloudintegrationtypes.NewAccountsFromStorables(storableAccounts)
}
func (module *module) AgentCheckIn(ctx context.Context, orgID valuer.UUID, provider cloudintegrationtypes.CloudProviderType, req *cloudintegrationtypes.AgentCheckInRequest) (*cloudintegrationtypes.AgentCheckInResponse, error) {
_, err := module.licensing.GetActive(ctx, orgID)
if err != nil {
return nil, errors.New(errors.TypeLicenseUnavailable, errors.CodeLicenseUnavailable, "a valid license is not available").WithAdditional("this feature requires a valid license").WithAdditional(err.Error())
}
connectedAccount, err := module.store.GetConnectedAccountByProviderAccountID(ctx, orgID, req.ProviderAccountID, provider)
if err != nil && !errors.Ast(err, errors.TypeNotFound) {
return nil, err
}
// If a different integration is already connected to this provider account ID, reject the check-in.
// Allow re-check-in from the same integration (e.g. agent restarting).
if connectedAccount != nil && connectedAccount.ID != req.CloudIntegrationID {
errMessage := fmt.Sprintf("provider account id %s is already connected to cloud integration id %s", req.ProviderAccountID, connectedAccount.ID)
return nil, errors.New(errors.TypeAlreadyExists, cloudintegrationtypes.ErrCodeCloudIntegrationAlreadyConnected, errMessage)
}
account, err := module.store.GetAccountByID(ctx, orgID, req.CloudIntegrationID, provider)
if err != nil {
return nil, err
}
// If account has been removed (disconnected), return a minimal response with empty integration config.
// The agent uses this response to clean up resources
if account.RemovedAt != nil {
return cloudintegrationtypes.NewAgentCheckInResponse(
req.ProviderAccountID,
account.ID.StringValue(),
new(cloudintegrationtypes.ProviderIntegrationConfig),
account.RemovedAt,
), nil
}
// update account with cloud provider account id and agent report (heartbeat)
account.Update(&req.ProviderAccountID, cloudintegrationtypes.NewAgentReport(req.Data))
err = module.store.UpdateAccount(ctx, account)
if err != nil {
return nil, err
}
// Get account as domain object for config access (enabled regions, etc.)
domainAccount, err := cloudintegrationtypes.NewAccountFromStorable(account)
if err != nil {
return nil, err
}
cloudProvider, err := module.getCloudProvider(provider)
if err != nil {
return nil, err
}
storedServices, err := module.store.ListServices(ctx, req.CloudIntegrationID)
if err != nil {
return nil, err
}
// Delegate integration config building entirely to the provider module
integrationConfig, err := cloudProvider.BuildIntegrationConfig(ctx, domainAccount, storedServices)
if err != nil {
return nil, err
}
return cloudintegrationtypes.NewAgentCheckInResponse(
req.ProviderAccountID,
account.ID.StringValue(),
integrationConfig,
account.RemovedAt,
), nil
}
func (module *module) UpdateAccount(ctx context.Context, account *cloudintegrationtypes.Account) error {
_, err := module.licensing.GetActive(ctx, account.OrgID)
if err != nil {
return errors.New(errors.TypeLicenseUnavailable, errors.CodeLicenseUnavailable, "a valid license is not available").WithAdditional("this feature requires a valid license").WithAdditional(err.Error())
}
storableAccount, err := cloudintegrationtypes.NewStorableCloudIntegration(account)
if err != nil {
return err
}
return module.store.UpdateAccount(ctx, storableAccount)
}
func (module *module) DisconnectAccount(ctx context.Context, orgID valuer.UUID, accountID valuer.UUID, provider cloudintegrationtypes.CloudProviderType) error {
_, err := module.licensing.GetActive(ctx, orgID)
if err != nil {
return errors.New(errors.TypeLicenseUnavailable, errors.CodeLicenseUnavailable, "a valid license is not available").WithAdditional("this feature requires a valid license").WithAdditional(err.Error())
}
return module.store.RemoveAccount(ctx, orgID, accountID, provider)
}
func (module *module) ListServicesMetadata(ctx context.Context, orgID valuer.UUID, provider cloudintegrationtypes.CloudProviderType, integrationID valuer.UUID) ([]*cloudintegrationtypes.ServiceMetadata, error) {
_, err := module.licensing.GetActive(ctx, orgID)
if err != nil {
return nil, errors.New(errors.TypeLicenseUnavailable, errors.CodeLicenseUnavailable, "a valid license is not available").WithAdditional("this feature requires a valid license").WithAdditional(err.Error())
}
cloudProvider, err := module.getCloudProvider(provider)
if err != nil {
return nil, err
}
serviceDefinitions, err := cloudProvider.ListServiceDefinitions(ctx)
if err != nil {
return nil, err
}
enabledServiceIDs := map[string]bool{}
if !integrationID.IsZero() {
storedServices, err := module.store.ListServices(ctx, integrationID)
if err != nil {
return nil, err
}
for _, svc := range storedServices {
serviceConfig, err := cloudintegrationtypes.NewServiceConfigFromJSON(provider, svc.Config)
if err != nil {
return nil, err
}
if serviceConfig.IsServiceEnabled(provider) {
enabledServiceIDs[svc.Type.StringValue()] = true
}
}
}
resp := make([]*cloudintegrationtypes.ServiceMetadata, 0, len(serviceDefinitions))
for _, serviceDefinition := range serviceDefinitions {
resp = append(resp, cloudintegrationtypes.NewServiceMetadata(*serviceDefinition, enabledServiceIDs[serviceDefinition.ID]))
}
return resp, nil
}
func (module *module) GetService(ctx context.Context, orgID valuer.UUID, serviceID cloudintegrationtypes.ServiceID, provider cloudintegrationtypes.CloudProviderType, cloudIntegrationID valuer.UUID) (*cloudintegrationtypes.Service, error) {
_, err := module.licensing.GetActive(ctx, orgID)
if err != nil {
return nil, errors.New(errors.TypeLicenseUnavailable, errors.CodeLicenseUnavailable, "a valid license is not available").WithAdditional("this feature requires a valid license").WithAdditional(err.Error())
}
cloudProvider, err := module.getCloudProvider(provider)
if err != nil {
return nil, err
}
serviceDefinition, err := cloudProvider.GetServiceDefinition(ctx, serviceID)
if err != nil {
return nil, err
}
var integrationService *cloudintegrationtypes.CloudIntegrationService
if !cloudIntegrationID.IsZero() {
storedService, err := module.store.GetServiceByServiceID(ctx, cloudIntegrationID, serviceID)
if err != nil && !errors.Ast(err, errors.TypeNotFound) {
return nil, err
}
if storedService != nil {
serviceConfig, err := cloudintegrationtypes.NewServiceConfigFromJSON(provider, storedService.Config)
if err != nil {
return nil, err
}
integrationService = cloudintegrationtypes.NewCloudIntegrationServiceFromStorable(storedService, serviceConfig)
}
}
return cloudintegrationtypes.NewService(*serviceDefinition, integrationService), nil
}
func (module *module) CreateService(ctx context.Context, orgID valuer.UUID, service *cloudintegrationtypes.CloudIntegrationService, provider cloudintegrationtypes.CloudProviderType) error {
_, err := module.licensing.GetActive(ctx, orgID)
if err != nil {
return errors.New(errors.TypeLicenseUnavailable, errors.CodeLicenseUnavailable, "a valid license is not available").WithAdditional("this feature requires a valid license").WithAdditional(err.Error())
}
cloudProvider, err := module.getCloudProvider(provider)
if err != nil {
return err
}
serviceDefinition, err := cloudProvider.GetServiceDefinition(ctx, service.Type)
if err != nil {
return err
}
configJSON, err := service.Config.ToJSON(provider, service.Type, &serviceDefinition.SupportedSignals)
if err != nil {
return err
}
return module.store.CreateService(ctx, cloudintegrationtypes.NewStorableCloudIntegrationService(service, string(configJSON)))
}
func (module *module) UpdateService(ctx context.Context, orgID valuer.UUID, integrationService *cloudintegrationtypes.CloudIntegrationService, provider cloudintegrationtypes.CloudProviderType) error {
_, err := module.licensing.GetActive(ctx, orgID)
if err != nil {
return errors.New(errors.TypeLicenseUnavailable, errors.CodeLicenseUnavailable, "a valid license is not available").WithAdditional("this feature requires a valid license").WithAdditional(err.Error())
}
cloudProvider, err := module.getCloudProvider(provider)
if err != nil {
return err
}
serviceDefinition, err := cloudProvider.GetServiceDefinition(ctx, integrationService.Type)
if err != nil {
return err
}
configJSON, err := integrationService.Config.ToJSON(provider, integrationService.Type, &serviceDefinition.SupportedSignals)
if err != nil {
return err
}
storableService := cloudintegrationtypes.NewStorableCloudIntegrationService(integrationService, string(configJSON))
return module.store.UpdateService(ctx, storableService)
}
func (module *module) GetDashboardByID(ctx context.Context, orgID valuer.UUID, id string) (*dashboardtypes.Dashboard, error) {
_, err := module.licensing.GetActive(ctx, orgID)
if err != nil {
return nil, errors.New(errors.TypeLicenseUnavailable, errors.CodeLicenseUnavailable, "a valid license is not available").WithAdditional("this feature requires a valid license").WithAdditional(err.Error())
}
_, _, _, err = cloudintegrationtypes.ParseCloudIntegrationDashboardID(id)
if err != nil {
return nil, err
}
allDashboards, err := module.listDashboards(ctx, orgID)
if err != nil {
return nil, err
}
for _, d := range allDashboards {
if d.ID == id {
return d, nil
}
}
return nil, errors.New(errors.TypeNotFound, cloudintegrationtypes.ErrCodeCloudIntegrationNotFound, "cloud integration dashboard not found")
}
func (module *module) ListDashboards(ctx context.Context, orgID valuer.UUID) ([]*dashboardtypes.Dashboard, error) {
_, err := module.licensing.GetActive(ctx, orgID)
if err != nil {
return nil, errors.New(errors.TypeLicenseUnavailable, errors.CodeLicenseUnavailable, "a valid license is not available").WithAdditional("this feature requires a valid license").WithAdditional(err.Error())
}
return module.listDashboards(ctx, orgID)
}
func (module *module) Collect(ctx context.Context, orgID valuer.UUID) (map[string]any, error) {
stats := make(map[string]any)
// get connected accounts for AWS
awsAccountsCount, err := module.store.CountConnectedAccounts(ctx, orgID, cloudintegrationtypes.CloudProviderTypeAWS)
if err == nil {
stats["cloudintegration.aws.connectedaccounts.count"] = awsAccountsCount
}
// NOTE: not adding stats for services for now.
// TODO: add more cloud providers when supported
return stats, nil
}
func (module *module) getCloudProvider(provider cloudintegrationtypes.CloudProviderType) (cloudintegration.CloudProviderModule, error) {
if cloudProviderModule, ok := module.cloudProvidersMap[provider]; ok {
return cloudProviderModule, nil
}
return nil, errors.NewInvalidInputf(cloudintegrationtypes.ErrCodeCloudProviderInvalidInput, "invalid cloud provider: %s", provider.StringValue())
}
func (module *module) getOrCreateIngestionKey(ctx context.Context, orgID valuer.UUID, provider cloudintegrationtypes.CloudProviderType) (string, error) {
keyName := cloudintegrationtypes.NewIngestionKeyName(provider)
result, err := module.gateway.SearchIngestionKeysByName(ctx, orgID, keyName, 1, 10)
if err != nil {
return "", errors.WrapInternalf(err, errors.CodeInternal, "couldn't search ingestion keys")
}
// ideally there should be only one key per cloud integration provider
if len(result.Keys) > 0 {
return result.Keys[0].Value, nil
}
createdIngestionKey, err := module.gateway.CreateIngestionKey(ctx, orgID, keyName, []string{"integration"}, time.Time{})
if err != nil {
return "", errors.WrapInternalf(err, errors.CodeInternal, "couldn't create ingestion key")
}
return createdIngestionKey.Value, nil
}
func (module *module) getOrCreateAPIKey(ctx context.Context, orgID valuer.UUID, provider cloudintegrationtypes.CloudProviderType) (string, error) {
domain := module.serviceAccount.Config().Email.Domain
serviceAccount := serviceaccounttypes.NewServiceAccount("integration", domain, serviceaccounttypes.ServiceAccountStatusActive, orgID)
serviceAccount, err := module.serviceAccount.GetOrCreate(ctx, orgID, serviceAccount)
if err != nil {
return "", err
}
err = module.serviceAccount.SetRoleByName(ctx, orgID, serviceAccount.ID, authtypes.SigNozViewerRoleName)
if err != nil {
return "", err
}
factorAPIKey, err := serviceAccount.NewFactorAPIKey(provider.StringValue(), 0)
if err != nil {
return "", err
}
factorAPIKey, err = module.serviceAccount.GetOrCreateFactorAPIKey(ctx, factorAPIKey)
if err != nil {
return "", err
}
return factorAPIKey.Key, nil
}
func (module *module) listDashboards(ctx context.Context, orgID valuer.UUID) ([]*dashboardtypes.Dashboard, error) {
var allDashboards []*dashboardtypes.Dashboard
for provider := range module.cloudProvidersMap {
cloudProvider, err := module.getCloudProvider(provider)
if err != nil {
return nil, err
}
connectedAccounts, err := module.store.ListConnectedAccounts(ctx, orgID, provider)
if err != nil {
return nil, err
}
for _, storableAccount := range connectedAccounts {
storedServices, err := module.store.ListServices(ctx, storableAccount.ID)
if err != nil {
return nil, err
}
for _, storedSvc := range storedServices {
serviceConfig, err := cloudintegrationtypes.NewServiceConfigFromJSON(provider, storedSvc.Config)
if err != nil || !serviceConfig.IsMetricsEnabled(provider) {
continue
}
svcDef, err := cloudProvider.GetServiceDefinition(ctx, storedSvc.Type)
if err != nil || svcDef == nil {
continue
}
dashboards := cloudintegrationtypes.GetDashboardsFromAssets(
storedSvc.Type.StringValue(),
orgID,
provider,
storableAccount.CreatedAt,
svcDef.Assets,
)
allDashboards = append(allDashboards, dashboards...)
}
}
}
sort.Slice(allDashboards, func(i, j int) bool {
return allDashboards[i].ID < allDashboards[j].ID
})
return allDashboards, nil
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/SigNoz/signoz/ee/licensing/httplicensing"
"github.com/SigNoz/signoz/ee/query-service/usage"
"github.com/SigNoz/signoz/pkg/alertmanager"
"github.com/SigNoz/signoz/pkg/global"
"github.com/SigNoz/signoz/pkg/http/middleware"
baseapp "github.com/SigNoz/signoz/pkg/query-service/app"
@@ -48,6 +49,7 @@ func NewAPIHandler(opts APIHandlerOptions, signoz *signoz.SigNoz, config signoz.
CloudIntegrationsController: opts.CloudIntegrationsController,
LogsParsingPipelineController: opts.LogsParsingPipelineController,
FluxInterval: opts.FluxInterval,
AlertmanagerAPI: alertmanager.NewAPI(signoz.Alertmanager),
LicensingAPI: httplicensing.NewLicensingAPI(signoz.Licensing),
Signoz: signoz,
QueryParserAPI: queryparser.NewAPI(signoz.Instrumentation.ToProviderSettings(), signoz.QueryParser),

View File

@@ -7,10 +7,6 @@ import (
"github.com/SigNoz/signoz/ee/query-service/constants"
"github.com/SigNoz/signoz/ee/query-service/model"
"github.com/SigNoz/signoz/pkg/flagger"
"github.com/SigNoz/signoz/pkg/types/authtypes"
"github.com/SigNoz/signoz/pkg/types/featuretypes"
"github.com/SigNoz/signoz/pkg/valuer"
)
type DayWiseBreakdown struct {
@@ -49,17 +45,15 @@ type details struct {
BillTotal float64 `json:"billTotal"`
}
type billingData struct {
BillingPeriodStart int64 `json:"billingPeriodStart"`
BillingPeriodEnd int64 `json:"billingPeriodEnd"`
Details details `json:"details"`
Discount float64 `json:"discount"`
SubscriptionStatus string `json:"subscriptionStatus"`
}
type billingDetails struct {
Status string `json:"status"`
Data billingData `json:"data"`
Status string `json:"status"`
Data struct {
BillingPeriodStart int64 `json:"billingPeriodStart"`
BillingPeriodEnd int64 `json:"billingPeriodEnd"`
Details details `json:"details"`
Discount float64 `json:"discount"`
SubscriptionStatus string `json:"subscriptionStatus"`
} `json:"data"`
}
func (ah *APIHandler) getBilling(w http.ResponseWriter, r *http.Request) {
@@ -70,33 +64,6 @@ func (ah *APIHandler) getBilling(w http.ResponseWriter, r *http.Request) {
return
}
claims, err := authtypes.ClaimsFromContext(r.Context())
if err != nil {
RespondError(w, model.InternalError(err), nil)
return
}
orgID := valuer.MustNewUUID(claims.OrgID)
evalCtx := featuretypes.NewFlaggerEvaluationContext(orgID)
useZeus := ah.Signoz.Flagger.BooleanOrEmpty(r.Context(), flagger.FeatureGetMetersFromZeus, evalCtx)
if useZeus {
data, err := ah.Signoz.Zeus.GetMeters(r.Context(), licenseKey)
if err != nil {
RespondError(w, model.InternalError(err), nil)
return
}
var billing billingData
if err := json.Unmarshal(data, &billing); err != nil {
RespondError(w, model.InternalError(err), nil)
return
}
ah.Respond(w, billing)
return
}
billingURL := fmt.Sprintf("%s/usage?licenseKey=%s", constants.LicenseSignozIo, licenseKey)
hClient := &http.Client{}
@@ -112,11 +79,13 @@ func (ah *APIHandler) getBilling(w http.ResponseWriter, r *http.Request) {
return
}
// decode response body
var billingResponse billingDetails
if err := json.NewDecoder(billingResp.Body).Decode(&billingResponse); err != nil {
RespondError(w, model.InternalError(err), nil)
return
}
// TODO(srikanthccv):Fetch the current day usage and add it to the response
ah.Respond(w, billingResponse.Data)
}

View File

@@ -10,6 +10,7 @@ import (
"go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux"
"go.opentelemetry.io/otel/propagation"
"github.com/SigNoz/signoz/pkg/cache/memorycache"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/queryparser"
@@ -73,12 +74,25 @@ type Server struct {
// NewServer creates and initializes Server
func NewServer(config signoz.Config, signoz *signoz.SigNoz) (*Server, error) {
cacheForTraceDetail, err := memorycache.New(context.TODO(), signoz.Instrumentation.ToProviderSettings(), cache.Config{
Provider: "memory",
Memory: cache.Memory{
NumCounters: 10 * 10000,
MaxCost: 1 << 27, // 128 MB
},
})
if err != nil {
return nil, err
}
reader := clickhouseReader.NewReader(
signoz.Instrumentation.Logger(),
signoz.SQLStore,
signoz.TelemetryStore,
signoz.Prometheus,
signoz.TelemetryStore.Cluster(),
config.Querier.FluxInterval,
cacheForTraceDetail,
signoz.Cache,
nil,
)
@@ -213,7 +227,7 @@ func (s *Server) createPublicServer(apiHandler *api.APIHandler, web web.Web) (*h
s.config.APIServer.Timeout.Default,
s.config.APIServer.Timeout.Max,
).Wrap)
r.Use(middleware.NewAudit(s.signoz.Instrumentation.Logger(), s.config.APIServer.Logging.ExcludedRoutes, s.signoz.Auditor).Wrap)
r.Use(middleware.NewAudit(s.signoz.Instrumentation.Logger(), s.config.APIServer.Logging.ExcludedRoutes, nil).Wrap)
r.Use(middleware.NewComment().Wrap)
apiHandler.RegisterRoutes(r, am)

View File

@@ -54,7 +54,6 @@ func New(ctx context.Context, providerSettings factory.ProviderSettings, config
// Set the maximum number of open connections
pgConfig.MaxConns = int32(config.Connection.MaxOpenConns)
pgConfig.MaxConnLifetime = config.Connection.MaxConnLifetime
// Use pgxpool to create a connection pool
pool, err := pgxpool.NewWithConfig(ctx, pgConfig)

View File

@@ -109,21 +109,6 @@ func (provider *Provider) GetDeployment(ctx context.Context, key string) ([]byte
return []byte(gjson.GetBytes(response, "data").String()), nil
}
func (provider *Provider) GetMeters(ctx context.Context, key string) ([]byte, error) {
response, err := provider.do(
ctx,
provider.config.URL.JoinPath("/v1/meters"),
http.MethodGet,
key,
nil,
)
if err != nil {
return nil, err
}
return []byte(gjson.GetBytes(response, "data").String()), nil
}
func (provider *Provider) PutMeters(ctx context.Context, key string, data []byte) error {
_, err := provider.do(
ctx,

View File

@@ -1,7 +1,5 @@
node_modules
build
eslint-rules/
stylelint-rules/
*.typegen.ts
i18-generate-hash.js
src/parser/TraceOperatorParser/**

View File

@@ -1,10 +1,3 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const path = require('path');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const rulesDirPlugin = require('eslint-plugin-rulesdir');
// eslint-rules/ always points to frontend/eslint-rules/ regardless of workspace root.
rulesDirPlugin.RULES_DIR = path.join(__dirname, 'eslint-rules');
/**
* ESLint Configuration for SigNoz Frontend
*/
@@ -39,7 +32,6 @@ module.exports = {
sourceType: 'module',
},
plugins: [
'rulesdir', // Local custom rules
'react', // React-specific rules
'@typescript-eslint', // TypeScript linting
'simple-import-sort', // Auto-sort imports
@@ -64,9 +56,6 @@ module.exports = {
},
},
rules: {
// Asset migration — base-path safety
'rulesdir/no-unsupported-asset-pattern': 'error',
// Code quality rules
'prefer-const': 'error', // Enforces const for variables never reassigned
'no-var': 'error', // Disallows var, enforces let/const

View File

@@ -1,9 +0,0 @@
const path = require('path');
module.exports = {
plugins: [path.join(__dirname, 'stylelint-rules/no-unsupported-asset-url.js')],
customSyntax: 'postcss-scss',
rules: {
'local/no-unsupported-asset-url': true,
},
};

View File

@@ -1,390 +0,0 @@
'use strict';
/**
* ESLint rule: no-unsupported-asset-pattern
*
* Enforces that all asset references (SVG, PNG, etc.) go through Vite's module
* pipeline via ES imports (`import fooUrl from '@/assets/...'`) rather than
* hard-coded strings or public/ paths.
*
* Why this matters: when the app is served from a sub-path (base-path deployment),
* Vite rewrites ES import URLs automatically. String literals and public/ references
* bypass that rewrite and break at runtime.
*
* Covers four AST patterns:
* 1. Literal — plain string: "/Icons/logo.svg"
* 2. TemplateLiteral — template string: `/Icons/${name}.svg`
* 3. BinaryExpression — concatenation: "/Icons/" + name + ".svg"
* 4. ImportDeclaration / ImportExpression — static & dynamic imports
*/
const {
hasAssetExtension,
containsAssetExtension,
extractUrlPath,
isAbsolutePath,
isPublicRelative,
isRelativePublicDir,
isValidAssetImport,
isExternalUrl,
} = require('./shared/asset-patterns');
// Known public/ sub-directories that should never appear in dynamic asset paths.
const PUBLIC_DIR_SEGMENTS = ['/Icons/', '/Images/', '/Logos/', '/svgs/'];
/**
* Recursively extracts the static string parts from a binary `+` expression or
* template literal. Returns `[null]` for any dynamic (non-string) node so
* callers can detect that the prefix became unknowable.
*
* Example: `"/Icons/" + iconName + ".svg"` → ["/Icons/", null, ".svg"]
*/
function collectBinaryStringParts(node) {
if (node.type === 'Literal' && typeof node.value === 'string')
return [node.value];
if (node.type === 'BinaryExpression' && node.operator === '+') {
return [
...collectBinaryStringParts(node.left),
...collectBinaryStringParts(node.right),
];
}
if (node.type === 'TemplateLiteral') {
return node.quasis.map((q) => q.value.raw);
}
// Unknown / dynamic node — signals "prefix is no longer fully static"
return [null];
}
module.exports = {
meta: {
type: 'problem',
docs: {
description:
'Disallow Vite-unsafe asset reference patterns that break runtime base-path deployments',
category: 'Asset Migration',
recommended: true,
},
schema: [],
messages: {
absoluteString:
'Absolute asset path "{{ value }}" is not base-path-safe. ' +
"Use an ES import instead: import fooUrl from '@/assets/...' and reference the variable.",
templateLiteral:
'Dynamic asset path with absolute prefix is not base-path-safe. ' +
"Use new URL('./asset.svg', import.meta.url).href for dynamic asset paths.",
absoluteImport:
'Asset imported via absolute path is not supported. ' +
"Use import fooUrl from '@/assets/...' instead.",
publicImport:
"Assets in public/ bypass Vite's module pipeline — their URLs are not base-path-aware and will break when the app is served from a sub-path (e.g. /app/). " +
"Use an ES import instead: import fooUrl from '@/assets/...' so Vite injects the correct base path.",
relativePublicString:
'Relative public-dir path "{{ value }}" is not base-path-safe. ' +
"Use an ES import instead: import fooUrl from '@/assets/...' and reference the variable.",
invalidAssetImport:
"Asset '{{ src }}' must be imported from src/assets/ using either '@/assets/...' " +
'or a relative path into src/assets/.',
},
},
create(context) {
return {
/**
* Catches plain string literals used as asset paths, e.g.:
* src="/Icons/logo.svg" or url("../public/Images/bg.png")
*
* Import declaration sources are skipped here — handled by ImportDeclaration.
* Also unwraps CSS `url(...)` wrappers before checking.
*/
Literal(node) {
if (node.parent && node.parent.type === 'ImportDeclaration') {
return;
}
const value = node.value;
if (typeof value !== 'string') return;
if (isExternalUrl(value)) return;
if (isAbsolutePath(value) && containsAssetExtension(value)) {
context.report({
node,
messageId: 'absoluteString',
data: { value },
});
return;
}
if (isRelativePublicDir(value) && containsAssetExtension(value)) {
context.report({
node,
messageId: 'relativePublicString',
data: { value },
});
return;
}
// Catches relative paths that start with "public/" e.g. 'public/Logos/aws-dark.svg'.
// isRelativePublicDir only covers known sub-dirs (Icons/, Logos/, etc.),
// so this handles the case where the full "public/" prefix is written explicitly.
if (isPublicRelative(value) && containsAssetExtension(value)) {
context.report({
node,
messageId: 'relativePublicString',
data: { value },
});
return;
}
// Also check the path inside a CSS url("...") wrapper
const urlPath = extractUrlPath(value);
if (urlPath && isExternalUrl(urlPath)) return;
if (urlPath && isAbsolutePath(urlPath) && containsAssetExtension(urlPath)) {
context.report({
node,
messageId: 'absoluteString',
data: { value: urlPath },
});
return;
}
if (
urlPath &&
isRelativePublicDir(urlPath) &&
containsAssetExtension(urlPath)
) {
context.report({
node,
messageId: 'relativePublicString',
data: { value: urlPath },
});
return;
}
if (
urlPath &&
isPublicRelative(urlPath) &&
containsAssetExtension(urlPath)
) {
context.report({
node,
messageId: 'relativePublicString',
data: { value: urlPath },
});
}
},
/**
* Catches template literals used as asset paths, e.g.:
* `/Icons/${name}.svg`
* `url('/Images/${bg}.png')`
*/
TemplateLiteral(node) {
const quasis = node.quasis;
if (!quasis || quasis.length === 0) return;
const firstQuasi = quasis[0].value.raw;
if (isExternalUrl(firstQuasi)) return;
const hasAssetExt = quasis.some((q) => containsAssetExtension(q.value.raw));
if (isAbsolutePath(firstQuasi) && hasAssetExt) {
context.report({
node,
messageId: 'templateLiteral',
});
return;
}
if (isRelativePublicDir(firstQuasi) && hasAssetExt) {
context.report({
node,
messageId: 'relativePublicString',
data: { value: firstQuasi },
});
return;
}
// Expression-first template with known public-dir segment: `${base}/Icons/foo.svg`
const hasPublicSegment = quasis.some((q) =>
PUBLIC_DIR_SEGMENTS.some((seg) => q.value.raw.includes(seg)),
);
if (hasPublicSegment && hasAssetExt) {
context.report({
node,
messageId: 'templateLiteral',
});
return;
}
// No-interpolation template (single quasi): treat like a plain string
// and also unwrap any css url(...) wrapper.
if (quasis.length === 1) {
// Check the raw string first (no url() wrapper)
if (isPublicRelative(firstQuasi) && hasAssetExt) {
context.report({
node,
messageId: 'relativePublicString',
data: { value: firstQuasi },
});
return;
}
const urlPath = extractUrlPath(firstQuasi);
if (urlPath && isExternalUrl(urlPath)) return;
if (urlPath && isAbsolutePath(urlPath) && hasAssetExtension(urlPath)) {
context.report({
node,
messageId: 'templateLiteral',
});
return;
}
if (
urlPath &&
isRelativePublicDir(urlPath) &&
hasAssetExtension(urlPath)
) {
context.report({
node,
messageId: 'relativePublicString',
data: { value: urlPath },
});
return;
}
if (urlPath && isPublicRelative(urlPath) && hasAssetExtension(urlPath)) {
context.report({
node,
messageId: 'relativePublicString',
data: { value: urlPath },
});
}
return;
}
// CSS url() with an absolute path inside a multi-quasi template, e.g.:
// `url('/Icons/${name}.svg')`
if (firstQuasi.includes('url(') && hasAssetExt) {
const urlMatch = firstQuasi.match(/^url\(\s*['"]?\//);
if (urlMatch) {
context.report({
node,
messageId: 'templateLiteral',
});
}
}
},
/**
* Catches string concatenation used to build asset paths, e.g.:
* "/Icons/" + name + ".svg"
*
* Collects the leading static parts (before the first dynamic value)
* to determine the path prefix. If any part carries a known asset
* extension, the expression is flagged.
*/
BinaryExpression(node) {
if (node.operator !== '+') return;
const parts = collectBinaryStringParts(node);
// Collect only the leading static parts; stop at the first dynamic (null) part
const prefixParts = [];
for (const part of parts) {
if (part === null) break;
prefixParts.push(part);
}
const staticPrefix = prefixParts.join('');
if (isExternalUrl(staticPrefix)) return;
const hasExt = parts.some(
(part) => part !== null && containsAssetExtension(part),
);
if (isAbsolutePath(staticPrefix) && hasExt) {
context.report({
node,
messageId: 'templateLiteral',
});
return;
}
if (isPublicRelative(staticPrefix) && hasExt) {
context.report({
node,
messageId: 'relativePublicString',
data: { value: staticPrefix },
});
return;
}
if (isRelativePublicDir(staticPrefix) && hasExt) {
context.report({
node,
messageId: 'relativePublicString',
data: { value: staticPrefix },
});
}
},
/**
* Catches static asset imports that don't go through src/assets/, e.g.:
* import logo from '/public/Icons/logo.svg' ← absolute path
* import logo from '../../public/logo.svg' ← relative into public/
* import logo from '../somewhere/logo.svg' ← outside src/assets/
*
* Valid pattern: import fooUrl from '@/assets/...' or relative within src/assets/
*/
ImportDeclaration(node) {
const src = node.source.value;
if (typeof src !== 'string') return;
if (!hasAssetExtension(src)) return;
if (isAbsolutePath(src)) {
context.report({ node, messageId: 'absoluteImport' });
return;
}
if (isPublicRelative(src)) {
context.report({ node, messageId: 'publicImport' });
return;
}
if (!isValidAssetImport(src)) {
context.report({
node,
messageId: 'invalidAssetImport',
data: { src },
});
}
},
/**
* Same checks as ImportDeclaration but for dynamic imports:
* const logo = await import('/Icons/logo.svg')
*
* Only literal sources are checked; fully dynamic expressions are ignored
* since their paths cannot be statically analysed.
*/
ImportExpression(node) {
const src = node.source;
if (!src || src.type !== 'Literal' || typeof src.value !== 'string') return;
const value = src.value;
if (!hasAssetExtension(value)) return;
if (isAbsolutePath(value)) {
context.report({ node, messageId: 'absoluteImport' });
return;
}
if (isPublicRelative(value)) {
context.report({ node, messageId: 'publicImport' });
return;
}
if (!isValidAssetImport(value)) {
context.report({
node,
messageId: 'invalidAssetImport',
data: { src: value },
});
}
},
};
},
};

View File

@@ -1,3 +0,0 @@
{
"type": "commonjs"
}

View File

@@ -1,121 +0,0 @@
'use strict';
const ALLOWED_ASSET_EXTENSIONS = [
'.svg',
'.png',
'.webp',
'.jpg',
'.jpeg',
'.gif',
];
/**
* Returns true if the string ends with an asset extension.
* e.g. "/Icons/foo.svg" → true, "/Icons/foo.svg.bak" → false
*/
function hasAssetExtension(str) {
if (typeof str !== 'string') return false;
return ALLOWED_ASSET_EXTENSIONS.some((ext) => str.endsWith(ext));
}
// Like hasAssetExtension but also matches mid-string with boundary check,
// e.g. "/foo.svg?v=1" → true, "/icons.svg-dir/" → true (- is non-alphanumeric boundary)
function containsAssetExtension(str) {
if (typeof str !== 'string') return false;
return ALLOWED_ASSET_EXTENSIONS.some((ext) => {
const idx = str.indexOf(ext);
if (idx === -1) return false;
const afterIdx = idx + ext.length;
// Broad boundary (any non-alphanumeric) is intentional — the real guard against
// false positives is the upstream conditions (isAbsolutePath, isRelativePublicDir, etc.)
// that must pass before this is reached. "/icons.svg-dir/" → true (- is a boundary).
return afterIdx >= str.length || /[^a-zA-Z0-9]/.test(str[afterIdx]);
});
}
/**
* Extracts the asset path from a CSS url() wrapper.
* Handles single quotes, double quotes, unquoted, and whitespace variations.
* e.g.
* "url('/Icons/foo.svg')" → "/Icons/foo.svg"
* "url( '../assets/bg.png' )" → "../assets/bg.png"
* "url(/Icons/foo.svg)" → "/Icons/foo.svg"
* Returns null if the string is not a url() wrapper.
*/
function extractUrlPath(str) {
if (typeof str !== 'string') return null;
// Match url( [whitespace] [quote?] path [quote?] [whitespace] )
// Capture group: [^'")\s]+ matches path until quote, closing paren, or whitespace
const match = str.match(/^url\(\s*['"]?([^'")\s]+)['"]?\s*\)$/);
return match ? match[1] : null;
}
/**
* Returns true if the string is an absolute path (starts with /).
* Absolute paths in url() bypass <base href> and fail under any URL prefix.
*/
function isAbsolutePath(str) {
if (typeof str !== 'string') return false;
return str.startsWith('/') && !str.startsWith('//');
}
/**
* Returns true if the path imports from the public/ directory.
* Relative imports into public/ cause asset duplication in dist/.
*/
function isPublicRelative(str) {
if (typeof str !== 'string') return false;
return str.includes('/public/') || str.startsWith('public/');
}
/**
* Returns true if the string is a relative reference into a known public-dir folder.
* e.g. "Icons/foo.svg", `Logos/aws-dark.svg`, "Images/bg.png"
* These bypass Vite's module pipeline even without a leading slash.
*/
const PUBLIC_DIR_SEGMENTS = ['Icons/', 'Images/', 'Logos/', 'svgs/'];
function isRelativePublicDir(str) {
if (typeof str !== 'string') return false;
return PUBLIC_DIR_SEGMENTS.some((seg) => str.startsWith(seg));
}
/**
* Returns true if an asset import path is valid (goes through Vite's module pipeline).
* Valid: @/assets/..., any relative path containing /assets/, or node_modules packages.
* Invalid: absolute paths, public/ dir, or relative paths outside src/assets/.
*/
function isValidAssetImport(str) {
if (typeof str !== 'string') return false;
if (str.startsWith('@/assets/')) return true;
if (str.includes('/assets/')) return true;
// Not starting with . or / means it's a node_modules package — always valid
if (!str.startsWith('.') && !str.startsWith('/')) return true;
return false;
}
/**
* Returns true if the string is an external URL.
* Used to avoid false positives on CDN/API URLs with asset extensions.
*/
function isExternalUrl(str) {
if (typeof str !== 'string') return false;
return (
str.startsWith('http://') ||
str.startsWith('https://') ||
str.startsWith('//')
);
}
module.exports = {
ALLOWED_ASSET_EXTENSIONS,
PUBLIC_DIR_SEGMENTS,
hasAssetExtension,
containsAssetExtension,
extractUrlPath,
isAbsolutePath,
isPublicRelative,
isRelativePublicDir,
isValidAssetImport,
isExternalUrl,
};

View File

@@ -62,29 +62,6 @@
<link data-react-helmet="true" rel="shortcut icon" href="/favicon.ico" />
</head>
<body data-theme="default">
<script>
// Apply theme class synchronously before React renders to prevent flash.
// Mirrors the logic in ThemeProvider (hooks/useDarkMode/index.tsx).
(function () {
try {
var theme = localStorage.getItem('THEME');
var autoSwitch = localStorage.getItem('THEME_AUTO_SWITCH') === 'true';
if (autoSwitch) {
theme = window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark'
: 'light';
}
if (theme === 'light') {
document.body.classList.add('lightMode');
} else {
// Default to dark when no preference is stored
document.body.classList.add('dark', 'darkMode');
}
} catch (e) {
document.body.classList.add('dark', 'darkMode');
}
})();
</script>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>

View File

@@ -15,7 +15,6 @@ const config: Config.InitialOptions = {
'<rootDir>/__mocks__/fileMock.ts',
'^@/(.*)$': '<rootDir>/src/$1',
'\\.(css|less|scss)$': '<rootDir>/__mocks__/cssMock.ts',
'\\.module\\.mjs$': '<rootDir>/__mocks__/cssMock.ts',
'\\.md$': '<rootDir>/__mocks__/cssMock.ts',
'^uplot$': '<rootDir>/__mocks__/uplotMock.ts',
'^@signozhq/resizable$': '<rootDir>/__mocks__/resizableMock.tsx',
@@ -45,7 +44,7 @@ const config: Config.InitialOptions = {
'^.+\\.(js|jsx)$': 'babel-jest',
},
transformIgnorePatterns: [
'node_modules/(?!(lodash-es|react-dnd|core-dnd|@react-dnd|dnd-core|react-dnd-html5-backend|axios|@signozhq/design-tokens|@signozhq/table|@signozhq/calendar|@signozhq/input|@signozhq/popover|@signozhq/button|@signozhq/*|date-fns|d3-interpolate|d3-color|api|@codemirror|@lezer|@marijn|@grafana|nuqs)/)',
'node_modules/(?!(lodash-es|react-dnd|core-dnd|@react-dnd|dnd-core|react-dnd-html5-backend|axios|@signozhq/design-tokens|@signozhq/table|@signozhq/calendar|@signozhq/input|@signozhq/popover|@signozhq/button|@signozhq/sonner|@signozhq/*|date-fns|d3-interpolate|d3-color|api|@codemirror|@lezer|@marijn|@grafana|nuqs)/)',
],
setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
testPathIgnorePatterns: ['/node_modules/', '/public/'],

View File

@@ -24,30 +24,6 @@ window.matchMedia =
};
};
// Patch getComputedStyle to handle CSS parsing errors from @signozhq/* packages.
// These packages inject CSS at import time via style-inject / vite-plugin-css-injected-by-js.
// jsdom's nwsapi cannot parse some of the injected selectors (e.g. Tailwind's :animate-in),
// causing SyntaxErrors during getComputedStyle / getByRole calls.
const _origGetComputedStyle = window.getComputedStyle;
window.getComputedStyle = function (
elt: Element,
pseudoElt?: string | null,
): CSSStyleDeclaration {
try {
return _origGetComputedStyle.call(window, elt, pseudoElt);
} catch {
// Return a minimal CSSStyleDeclaration so callers (testing-library, Radix UI)
// see the element as visible and without animations.
return ({
display: '',
visibility: '',
opacity: '1',
animationName: 'none',
getPropertyValue: () => '',
} as unknown) as CSSStyleDeclaration;
}
};
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());

View File

@@ -10,10 +10,9 @@
"preview": "vite preview",
"prettify": "prettier --write .",
"fmt": "prettier --check .",
"lint": "eslint ./src && stylelint \"src/**/*.scss\"",
"lint": "eslint ./src",
"lint:generated": "eslint ./src/api/generated --fix",
"lint:fix": "eslint ./src --fix",
"lint:styles": "stylelint \"src/**/*.scss\"",
"jest": "jest",
"jest:coverage": "jest --coverage",
"jest:watch": "jest --watch",
@@ -48,13 +47,14 @@
"@radix-ui/react-tooltip": "1.0.7",
"@sentry/react": "8.41.0",
"@sentry/vite-plugin": "2.22.6",
"@signozhq/badge": "0.0.2",
"@signozhq/button": "0.0.2",
"@signozhq/calendar": "0.0.0",
"@signozhq/callout": "0.0.2",
"@signozhq/checkbox": "0.0.2",
"@signozhq/combobox": "0.0.2",
"@signozhq/command": "0.0.0",
"@signozhq/design-tokens": "2.1.4",
"@signozhq/design-tokens": "2.1.1",
"@signozhq/dialog": "^0.0.2",
"@signozhq/drawer": "0.0.4",
"@signozhq/icons": "0.1.0",
@@ -62,8 +62,11 @@
"@signozhq/popover": "0.0.0",
"@signozhq/radio-group": "0.0.2",
"@signozhq/resizable": "0.0.0",
"@signozhq/sonner": "0.1.0",
"@signozhq/switch": "0.0.2",
"@signozhq/table": "0.3.7",
"@signozhq/toggle-group": "0.0.1",
"@signozhq/tooltip": "0.0.2",
"@signozhq/ui": "0.0.5",
"@tanstack/react-table": "8.21.3",
"@tanstack/react-virtual": "3.13.22",
@@ -226,7 +229,6 @@
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-react-hooks": "^4.3.0",
"eslint-plugin-rulesdir": "0.2.2",
"eslint-plugin-simple-import-sort": "^7.0.0",
"eslint-plugin-sonarjs": "^0.12.0",
"husky": "^7.0.4",
@@ -242,7 +244,6 @@
"orval": "7.18.0",
"portfinder-sync": "^0.0.2",
"postcss": "8.5.6",
"postcss-scss": "4.0.9",
"prettier": "2.2.1",
"prop-types": "15.8.1",
"react-hooks-testing-library": "0.6.0",
@@ -250,8 +251,6 @@
"redux-mock-store": "1.5.4",
"sass": "1.97.3",
"sharp": "0.34.5",
"stylelint": "17.7.0",
"stylelint-scss": "7.0.0",
"svgo": "4.0.0",
"ts-api-utils": "2.4.0",
"ts-jest": "29.4.6",

View File

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -1,97 +0,0 @@
/**
* ! Do not edit manually
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'yarn generate:api'
* SigNoz
*/
import type {
InvalidateOptions,
QueryClient,
QueryFunction,
QueryKey,
UseQueryOptions,
UseQueryResult,
} from 'react-query';
import { useQuery } from 'react-query';
import type { ErrorType } from '../../../generatedAPIInstance';
import { GeneratedAPIInstance } from '../../../generatedAPIInstance';
import type { GetAlerts200, RenderErrorResponseDTO } from '../sigNoz.schemas';
/**
* This endpoint returns alerts for the organization
* @summary Get alerts
*/
export const getAlerts = (signal?: AbortSignal) => {
return GeneratedAPIInstance<GetAlerts200>({
url: `/api/v1/alerts`,
method: 'GET',
signal,
});
};
export const getGetAlertsQueryKey = () => {
return [`/api/v1/alerts`] as const;
};
export const getGetAlertsQueryOptions = <
TData = Awaited<ReturnType<typeof getAlerts>>,
TError = ErrorType<RenderErrorResponseDTO>
>(options?: {
query?: UseQueryOptions<Awaited<ReturnType<typeof getAlerts>>, TError, TData>;
}) => {
const { query: queryOptions } = options ?? {};
const queryKey = queryOptions?.queryKey ?? getGetAlertsQueryKey();
const queryFn: QueryFunction<Awaited<ReturnType<typeof getAlerts>>> = ({
signal,
}) => getAlerts(signal);
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
Awaited<ReturnType<typeof getAlerts>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type GetAlertsQueryResult = NonNullable<
Awaited<ReturnType<typeof getAlerts>>
>;
export type GetAlertsQueryError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Get alerts
*/
export function useGetAlerts<
TData = Awaited<ReturnType<typeof getAlerts>>,
TError = ErrorType<RenderErrorResponseDTO>
>(options?: {
query?: UseQueryOptions<Awaited<ReturnType<typeof getAlerts>>, TError, TData>;
}): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getGetAlertsQueryOptions(options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
query.queryKey = queryOptions.queryKey;
return query;
}
/**
* @summary Get alerts
*/
export const invalidateGetAlerts = async (
queryClient: QueryClient,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getGetAlertsQueryKey() },
options,
);
return queryClient;
};

View File

@@ -1,646 +0,0 @@
/**
* ! Do not edit manually
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'yarn generate:api'
* SigNoz
*/
import type {
InvalidateOptions,
MutationFunction,
QueryClient,
QueryFunction,
QueryKey,
UseMutationOptions,
UseMutationResult,
UseQueryOptions,
UseQueryResult,
} from 'react-query';
import { useMutation, useQuery } from 'react-query';
import type { BodyType, ErrorType } from '../../../generatedAPIInstance';
import { GeneratedAPIInstance } from '../../../generatedAPIInstance';
import type {
ConfigReceiverDTO,
CreateChannel201,
DeleteChannelByIDPathParameters,
GetChannelByID200,
GetChannelByIDPathParameters,
ListChannels200,
RenderErrorResponseDTO,
UpdateChannelByIDPathParameters,
} from '../sigNoz.schemas';
/**
* This endpoint lists all notification channels for the organization
* @summary List notification channels
*/
export const listChannels = (signal?: AbortSignal) => {
return GeneratedAPIInstance<ListChannels200>({
url: `/api/v1/channels`,
method: 'GET',
signal,
});
};
export const getListChannelsQueryKey = () => {
return [`/api/v1/channels`] as const;
};
export const getListChannelsQueryOptions = <
TData = Awaited<ReturnType<typeof listChannels>>,
TError = ErrorType<RenderErrorResponseDTO>
>(options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listChannels>>,
TError,
TData
>;
}) => {
const { query: queryOptions } = options ?? {};
const queryKey = queryOptions?.queryKey ?? getListChannelsQueryKey();
const queryFn: QueryFunction<Awaited<ReturnType<typeof listChannels>>> = ({
signal,
}) => listChannels(signal);
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
Awaited<ReturnType<typeof listChannels>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type ListChannelsQueryResult = NonNullable<
Awaited<ReturnType<typeof listChannels>>
>;
export type ListChannelsQueryError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary List notification channels
*/
export function useListChannels<
TData = Awaited<ReturnType<typeof listChannels>>,
TError = ErrorType<RenderErrorResponseDTO>
>(options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listChannels>>,
TError,
TData
>;
}): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getListChannelsQueryOptions(options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
query.queryKey = queryOptions.queryKey;
return query;
}
/**
* @summary List notification channels
*/
export const invalidateListChannels = async (
queryClient: QueryClient,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getListChannelsQueryKey() },
options,
);
return queryClient;
};
/**
* This endpoint creates a notification channel
* @summary Create notification channel
*/
export const createChannel = (
configReceiverDTO: BodyType<ConfigReceiverDTO>,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<CreateChannel201>({
url: `/api/v1/channels`,
method: 'POST',
headers: { 'Content-Type': 'application/json' },
data: configReceiverDTO,
signal,
});
};
export const getCreateChannelMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof createChannel>>,
TError,
{ data: BodyType<ConfigReceiverDTO> },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof createChannel>>,
TError,
{ data: BodyType<ConfigReceiverDTO> },
TContext
> => {
const mutationKey = ['createChannel'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof createChannel>>,
{ data: BodyType<ConfigReceiverDTO> }
> = (props) => {
const { data } = props ?? {};
return createChannel(data);
};
return { mutationFn, ...mutationOptions };
};
export type CreateChannelMutationResult = NonNullable<
Awaited<ReturnType<typeof createChannel>>
>;
export type CreateChannelMutationBody = BodyType<ConfigReceiverDTO>;
export type CreateChannelMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Create notification channel
*/
export const useCreateChannel = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof createChannel>>,
TError,
{ data: BodyType<ConfigReceiverDTO> },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof createChannel>>,
TError,
{ data: BodyType<ConfigReceiverDTO> },
TContext
> => {
const mutationOptions = getCreateChannelMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* This endpoint deletes a notification channel by ID
* @summary Delete notification channel
*/
export const deleteChannelByID = ({ id }: DeleteChannelByIDPathParameters) => {
return GeneratedAPIInstance<void>({
url: `/api/v1/channels/${id}`,
method: 'DELETE',
});
};
export const getDeleteChannelByIDMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteChannelByID>>,
TError,
{ pathParams: DeleteChannelByIDPathParameters },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof deleteChannelByID>>,
TError,
{ pathParams: DeleteChannelByIDPathParameters },
TContext
> => {
const mutationKey = ['deleteChannelByID'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof deleteChannelByID>>,
{ pathParams: DeleteChannelByIDPathParameters }
> = (props) => {
const { pathParams } = props ?? {};
return deleteChannelByID(pathParams);
};
return { mutationFn, ...mutationOptions };
};
export type DeleteChannelByIDMutationResult = NonNullable<
Awaited<ReturnType<typeof deleteChannelByID>>
>;
export type DeleteChannelByIDMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Delete notification channel
*/
export const useDeleteChannelByID = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteChannelByID>>,
TError,
{ pathParams: DeleteChannelByIDPathParameters },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof deleteChannelByID>>,
TError,
{ pathParams: DeleteChannelByIDPathParameters },
TContext
> => {
const mutationOptions = getDeleteChannelByIDMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* This endpoint returns a notification channel by ID
* @summary Get notification channel by ID
*/
export const getChannelByID = (
{ id }: GetChannelByIDPathParameters,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<GetChannelByID200>({
url: `/api/v1/channels/${id}`,
method: 'GET',
signal,
});
};
export const getGetChannelByIDQueryKey = ({
id,
}: GetChannelByIDPathParameters) => {
return [`/api/v1/channels/${id}`] as const;
};
export const getGetChannelByIDQueryOptions = <
TData = Awaited<ReturnType<typeof getChannelByID>>,
TError = ErrorType<RenderErrorResponseDTO>
>(
{ id }: GetChannelByIDPathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getChannelByID>>,
TError,
TData
>;
},
) => {
const { query: queryOptions } = options ?? {};
const queryKey = queryOptions?.queryKey ?? getGetChannelByIDQueryKey({ id });
const queryFn: QueryFunction<Awaited<ReturnType<typeof getChannelByID>>> = ({
signal,
}) => getChannelByID({ id }, signal);
return {
queryKey,
queryFn,
enabled: !!id,
...queryOptions,
} as UseQueryOptions<
Awaited<ReturnType<typeof getChannelByID>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type GetChannelByIDQueryResult = NonNullable<
Awaited<ReturnType<typeof getChannelByID>>
>;
export type GetChannelByIDQueryError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Get notification channel by ID
*/
export function useGetChannelByID<
TData = Awaited<ReturnType<typeof getChannelByID>>,
TError = ErrorType<RenderErrorResponseDTO>
>(
{ id }: GetChannelByIDPathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getChannelByID>>,
TError,
TData
>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getGetChannelByIDQueryOptions({ id }, options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
query.queryKey = queryOptions.queryKey;
return query;
}
/**
* @summary Get notification channel by ID
*/
export const invalidateGetChannelByID = async (
queryClient: QueryClient,
{ id }: GetChannelByIDPathParameters,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getGetChannelByIDQueryKey({ id }) },
options,
);
return queryClient;
};
/**
* This endpoint updates a notification channel by ID
* @summary Update notification channel
*/
export const updateChannelByID = (
{ id }: UpdateChannelByIDPathParameters,
configReceiverDTO: BodyType<ConfigReceiverDTO>,
) => {
return GeneratedAPIInstance<void>({
url: `/api/v1/channels/${id}`,
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
data: configReceiverDTO,
});
};
export const getUpdateChannelByIDMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof updateChannelByID>>,
TError,
{
pathParams: UpdateChannelByIDPathParameters;
data: BodyType<ConfigReceiverDTO>;
},
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof updateChannelByID>>,
TError,
{
pathParams: UpdateChannelByIDPathParameters;
data: BodyType<ConfigReceiverDTO>;
},
TContext
> => {
const mutationKey = ['updateChannelByID'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof updateChannelByID>>,
{
pathParams: UpdateChannelByIDPathParameters;
data: BodyType<ConfigReceiverDTO>;
}
> = (props) => {
const { pathParams, data } = props ?? {};
return updateChannelByID(pathParams, data);
};
return { mutationFn, ...mutationOptions };
};
export type UpdateChannelByIDMutationResult = NonNullable<
Awaited<ReturnType<typeof updateChannelByID>>
>;
export type UpdateChannelByIDMutationBody = BodyType<ConfigReceiverDTO>;
export type UpdateChannelByIDMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Update notification channel
*/
export const useUpdateChannelByID = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof updateChannelByID>>,
TError,
{
pathParams: UpdateChannelByIDPathParameters;
data: BodyType<ConfigReceiverDTO>;
},
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof updateChannelByID>>,
TError,
{
pathParams: UpdateChannelByIDPathParameters;
data: BodyType<ConfigReceiverDTO>;
},
TContext
> => {
const mutationOptions = getUpdateChannelByIDMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* This endpoint tests a notification channel by sending a test notification
* @summary Test notification channel
*/
export const testChannel = (
configReceiverDTO: BodyType<ConfigReceiverDTO>,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<void>({
url: `/api/v1/channels/test`,
method: 'POST',
headers: { 'Content-Type': 'application/json' },
data: configReceiverDTO,
signal,
});
};
export const getTestChannelMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof testChannel>>,
TError,
{ data: BodyType<ConfigReceiverDTO> },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof testChannel>>,
TError,
{ data: BodyType<ConfigReceiverDTO> },
TContext
> => {
const mutationKey = ['testChannel'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof testChannel>>,
{ data: BodyType<ConfigReceiverDTO> }
> = (props) => {
const { data } = props ?? {};
return testChannel(data);
};
return { mutationFn, ...mutationOptions };
};
export type TestChannelMutationResult = NonNullable<
Awaited<ReturnType<typeof testChannel>>
>;
export type TestChannelMutationBody = BodyType<ConfigReceiverDTO>;
export type TestChannelMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Test notification channel
*/
export const useTestChannel = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof testChannel>>,
TError,
{ data: BodyType<ConfigReceiverDTO> },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof testChannel>>,
TError,
{ data: BodyType<ConfigReceiverDTO> },
TContext
> => {
const mutationOptions = getTestChannelMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* Deprecated: use /api/v1/channels/test instead
* @deprecated
* @summary Test notification channel (deprecated)
*/
export const testChannelDeprecated = (
configReceiverDTO: BodyType<ConfigReceiverDTO>,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<void>({
url: `/api/v1/testChannel`,
method: 'POST',
headers: { 'Content-Type': 'application/json' },
data: configReceiverDTO,
signal,
});
};
export const getTestChannelDeprecatedMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof testChannelDeprecated>>,
TError,
{ data: BodyType<ConfigReceiverDTO> },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof testChannelDeprecated>>,
TError,
{ data: BodyType<ConfigReceiverDTO> },
TContext
> => {
const mutationKey = ['testChannelDeprecated'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof testChannelDeprecated>>,
{ data: BodyType<ConfigReceiverDTO> }
> = (props) => {
const { data } = props ?? {};
return testChannelDeprecated(data);
};
return { mutationFn, ...mutationOptions };
};
export type TestChannelDeprecatedMutationResult = NonNullable<
Awaited<ReturnType<typeof testChannelDeprecated>>
>;
export type TestChannelDeprecatedMutationBody = BodyType<ConfigReceiverDTO>;
export type TestChannelDeprecatedMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @deprecated
* @summary Test notification channel (deprecated)
*/
export const useTestChannelDeprecated = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof testChannelDeprecated>>,
TError,
{ data: BodyType<ConfigReceiverDTO> },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof testChannelDeprecated>>,
TError,
{ data: BodyType<ConfigReceiverDTO> },
TContext
> => {
const mutationOptions = getTestChannelDeprecatedMutationOptions(options);
return useMutation(mutationOptions);
};

View File

@@ -28,7 +28,7 @@ import type {
CloudintegrationtypesPostableAgentCheckInDTO,
CloudintegrationtypesUpdatableAccountDTO,
CloudintegrationtypesUpdatableServiceDTO,
CreateAccount201,
CreateAccount200,
CreateAccountPathParameters,
DisconnectAccountPathParameters,
GetAccount200,
@@ -36,12 +36,10 @@ import type {
GetConnectionCredentials200,
GetConnectionCredentialsPathParameters,
GetService200,
GetServiceParams,
GetServicePathParameters,
ListAccounts200,
ListAccountsPathParameters,
ListServicesMetadata200,
ListServicesMetadataParams,
ListServicesMetadataPathParameters,
RenderErrorResponseDTO,
UpdateAccountPathParameters,
@@ -262,7 +260,7 @@ export const createAccount = (
cloudintegrationtypesPostableAccountDTO: BodyType<CloudintegrationtypesPostableAccountDTO>,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<CreateAccount201>({
return GeneratedAPIInstance<CreateAccount200>({
url: `/api/v1/cloud_integrations/${cloudProvider}/accounts`,
method: 'POST',
headers: { 'Content-Type': 'application/json' },
@@ -942,25 +940,19 @@ export const invalidateGetConnectionCredentials = async (
*/
export const listServicesMetadata = (
{ cloudProvider }: ListServicesMetadataPathParameters,
params?: ListServicesMetadataParams,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<ListServicesMetadata200>({
url: `/api/v1/cloud_integrations/${cloudProvider}/services`,
method: 'GET',
params,
signal,
});
};
export const getListServicesMetadataQueryKey = (
{ cloudProvider }: ListServicesMetadataPathParameters,
params?: ListServicesMetadataParams,
) => {
return [
`/api/v1/cloud_integrations/${cloudProvider}/services`,
...(params ? [params] : []),
] as const;
export const getListServicesMetadataQueryKey = ({
cloudProvider,
}: ListServicesMetadataPathParameters) => {
return [`/api/v1/cloud_integrations/${cloudProvider}/services`] as const;
};
export const getListServicesMetadataQueryOptions = <
@@ -968,7 +960,6 @@ export const getListServicesMetadataQueryOptions = <
TError = ErrorType<RenderErrorResponseDTO>
>(
{ cloudProvider }: ListServicesMetadataPathParameters,
params?: ListServicesMetadataParams,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listServicesMetadata>>,
@@ -980,12 +971,11 @@ export const getListServicesMetadataQueryOptions = <
const { query: queryOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ??
getListServicesMetadataQueryKey({ cloudProvider }, params);
queryOptions?.queryKey ?? getListServicesMetadataQueryKey({ cloudProvider });
const queryFn: QueryFunction<
Awaited<ReturnType<typeof listServicesMetadata>>
> = ({ signal }) => listServicesMetadata({ cloudProvider }, params, signal);
> = ({ signal }) => listServicesMetadata({ cloudProvider }, signal);
return {
queryKey,
@@ -1013,7 +1003,6 @@ export function useListServicesMetadata<
TError = ErrorType<RenderErrorResponseDTO>
>(
{ cloudProvider }: ListServicesMetadataPathParameters,
params?: ListServicesMetadataParams,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listServicesMetadata>>,
@@ -1024,7 +1013,6 @@ export function useListServicesMetadata<
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getListServicesMetadataQueryOptions(
{ cloudProvider },
params,
options,
);
@@ -1043,11 +1031,10 @@ export function useListServicesMetadata<
export const invalidateListServicesMetadata = async (
queryClient: QueryClient,
{ cloudProvider }: ListServicesMetadataPathParameters,
params?: ListServicesMetadataParams,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getListServicesMetadataQueryKey({ cloudProvider }, params) },
{ queryKey: getListServicesMetadataQueryKey({ cloudProvider }) },
options,
);
@@ -1060,24 +1047,21 @@ export const invalidateListServicesMetadata = async (
*/
export const getService = (
{ cloudProvider, serviceId }: GetServicePathParameters,
params?: GetServiceParams,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<GetService200>({
url: `/api/v1/cloud_integrations/${cloudProvider}/services/${serviceId}`,
method: 'GET',
params,
signal,
});
};
export const getGetServiceQueryKey = (
{ cloudProvider, serviceId }: GetServicePathParameters,
params?: GetServiceParams,
) => {
export const getGetServiceQueryKey = ({
cloudProvider,
serviceId,
}: GetServicePathParameters) => {
return [
`/api/v1/cloud_integrations/${cloudProvider}/services/${serviceId}`,
...(params ? [params] : []),
] as const;
};
@@ -1086,7 +1070,6 @@ export const getGetServiceQueryOptions = <
TError = ErrorType<RenderErrorResponseDTO>
>(
{ cloudProvider, serviceId }: GetServicePathParameters,
params?: GetServiceParams,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getService>>,
@@ -1098,12 +1081,11 @@ export const getGetServiceQueryOptions = <
const { query: queryOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ??
getGetServiceQueryKey({ cloudProvider, serviceId }, params);
queryOptions?.queryKey ?? getGetServiceQueryKey({ cloudProvider, serviceId });
const queryFn: QueryFunction<Awaited<ReturnType<typeof getService>>> = ({
signal,
}) => getService({ cloudProvider, serviceId }, params, signal);
}) => getService({ cloudProvider, serviceId }, signal);
return {
queryKey,
@@ -1129,7 +1111,6 @@ export function useGetService<
TError = ErrorType<RenderErrorResponseDTO>
>(
{ cloudProvider, serviceId }: GetServicePathParameters,
params?: GetServiceParams,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getService>>,
@@ -1140,7 +1121,6 @@ export function useGetService<
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getGetServiceQueryOptions(
{ cloudProvider, serviceId },
params,
options,
);
@@ -1159,11 +1139,10 @@ export function useGetService<
export const invalidateGetService = async (
queryClient: QueryClient,
{ cloudProvider, serviceId }: GetServicePathParameters,
params?: GetServiceParams,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getGetServiceQueryKey({ cloudProvider, serviceId }, params) },
{ queryKey: getGetServiceQueryKey({ cloudProvider, serviceId }) },
options,
);

View File

@@ -1,482 +0,0 @@
/**
* ! Do not edit manually
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'yarn generate:api'
* SigNoz
*/
import type {
InvalidateOptions,
MutationFunction,
QueryClient,
QueryFunction,
QueryKey,
UseMutationOptions,
UseMutationResult,
UseQueryOptions,
UseQueryResult,
} from 'react-query';
import { useMutation, useQuery } from 'react-query';
import type { BodyType, ErrorType } from '../../../generatedAPIInstance';
import { GeneratedAPIInstance } from '../../../generatedAPIInstance';
import type {
AlertmanagertypesPostableRoutePolicyDTO,
CreateRoutePolicy201,
DeleteRoutePolicyByIDPathParameters,
GetAllRoutePolicies200,
GetRoutePolicyByID200,
GetRoutePolicyByIDPathParameters,
RenderErrorResponseDTO,
UpdateRoutePolicy200,
UpdateRoutePolicyPathParameters,
} from '../sigNoz.schemas';
/**
* This endpoint lists all route policies for the organization
* @summary List route policies
*/
export const getAllRoutePolicies = (signal?: AbortSignal) => {
return GeneratedAPIInstance<GetAllRoutePolicies200>({
url: `/api/v1/route_policies`,
method: 'GET',
signal,
});
};
export const getGetAllRoutePoliciesQueryKey = () => {
return [`/api/v1/route_policies`] as const;
};
export const getGetAllRoutePoliciesQueryOptions = <
TData = Awaited<ReturnType<typeof getAllRoutePolicies>>,
TError = ErrorType<RenderErrorResponseDTO>
>(options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getAllRoutePolicies>>,
TError,
TData
>;
}) => {
const { query: queryOptions } = options ?? {};
const queryKey = queryOptions?.queryKey ?? getGetAllRoutePoliciesQueryKey();
const queryFn: QueryFunction<
Awaited<ReturnType<typeof getAllRoutePolicies>>
> = ({ signal }) => getAllRoutePolicies(signal);
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
Awaited<ReturnType<typeof getAllRoutePolicies>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type GetAllRoutePoliciesQueryResult = NonNullable<
Awaited<ReturnType<typeof getAllRoutePolicies>>
>;
export type GetAllRoutePoliciesQueryError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary List route policies
*/
export function useGetAllRoutePolicies<
TData = Awaited<ReturnType<typeof getAllRoutePolicies>>,
TError = ErrorType<RenderErrorResponseDTO>
>(options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getAllRoutePolicies>>,
TError,
TData
>;
}): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getGetAllRoutePoliciesQueryOptions(options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
query.queryKey = queryOptions.queryKey;
return query;
}
/**
* @summary List route policies
*/
export const invalidateGetAllRoutePolicies = async (
queryClient: QueryClient,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getGetAllRoutePoliciesQueryKey() },
options,
);
return queryClient;
};
/**
* This endpoint creates a route policy
* @summary Create route policy
*/
export const createRoutePolicy = (
alertmanagertypesPostableRoutePolicyDTO: BodyType<AlertmanagertypesPostableRoutePolicyDTO>,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<CreateRoutePolicy201>({
url: `/api/v1/route_policies`,
method: 'POST',
headers: { 'Content-Type': 'application/json' },
data: alertmanagertypesPostableRoutePolicyDTO,
signal,
});
};
export const getCreateRoutePolicyMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof createRoutePolicy>>,
TError,
{ data: BodyType<AlertmanagertypesPostableRoutePolicyDTO> },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof createRoutePolicy>>,
TError,
{ data: BodyType<AlertmanagertypesPostableRoutePolicyDTO> },
TContext
> => {
const mutationKey = ['createRoutePolicy'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof createRoutePolicy>>,
{ data: BodyType<AlertmanagertypesPostableRoutePolicyDTO> }
> = (props) => {
const { data } = props ?? {};
return createRoutePolicy(data);
};
return { mutationFn, ...mutationOptions };
};
export type CreateRoutePolicyMutationResult = NonNullable<
Awaited<ReturnType<typeof createRoutePolicy>>
>;
export type CreateRoutePolicyMutationBody = BodyType<AlertmanagertypesPostableRoutePolicyDTO>;
export type CreateRoutePolicyMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Create route policy
*/
export const useCreateRoutePolicy = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof createRoutePolicy>>,
TError,
{ data: BodyType<AlertmanagertypesPostableRoutePolicyDTO> },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof createRoutePolicy>>,
TError,
{ data: BodyType<AlertmanagertypesPostableRoutePolicyDTO> },
TContext
> => {
const mutationOptions = getCreateRoutePolicyMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* This endpoint deletes a route policy by ID
* @summary Delete route policy
*/
export const deleteRoutePolicyByID = ({
id,
}: DeleteRoutePolicyByIDPathParameters) => {
return GeneratedAPIInstance<void>({
url: `/api/v1/route_policies/${id}`,
method: 'DELETE',
});
};
export const getDeleteRoutePolicyByIDMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteRoutePolicyByID>>,
TError,
{ pathParams: DeleteRoutePolicyByIDPathParameters },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof deleteRoutePolicyByID>>,
TError,
{ pathParams: DeleteRoutePolicyByIDPathParameters },
TContext
> => {
const mutationKey = ['deleteRoutePolicyByID'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof deleteRoutePolicyByID>>,
{ pathParams: DeleteRoutePolicyByIDPathParameters }
> = (props) => {
const { pathParams } = props ?? {};
return deleteRoutePolicyByID(pathParams);
};
return { mutationFn, ...mutationOptions };
};
export type DeleteRoutePolicyByIDMutationResult = NonNullable<
Awaited<ReturnType<typeof deleteRoutePolicyByID>>
>;
export type DeleteRoutePolicyByIDMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Delete route policy
*/
export const useDeleteRoutePolicyByID = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteRoutePolicyByID>>,
TError,
{ pathParams: DeleteRoutePolicyByIDPathParameters },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof deleteRoutePolicyByID>>,
TError,
{ pathParams: DeleteRoutePolicyByIDPathParameters },
TContext
> => {
const mutationOptions = getDeleteRoutePolicyByIDMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* This endpoint returns a route policy by ID
* @summary Get route policy by ID
*/
export const getRoutePolicyByID = (
{ id }: GetRoutePolicyByIDPathParameters,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<GetRoutePolicyByID200>({
url: `/api/v1/route_policies/${id}`,
method: 'GET',
signal,
});
};
export const getGetRoutePolicyByIDQueryKey = ({
id,
}: GetRoutePolicyByIDPathParameters) => {
return [`/api/v1/route_policies/${id}`] as const;
};
export const getGetRoutePolicyByIDQueryOptions = <
TData = Awaited<ReturnType<typeof getRoutePolicyByID>>,
TError = ErrorType<RenderErrorResponseDTO>
>(
{ id }: GetRoutePolicyByIDPathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getRoutePolicyByID>>,
TError,
TData
>;
},
) => {
const { query: queryOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getGetRoutePolicyByIDQueryKey({ id });
const queryFn: QueryFunction<
Awaited<ReturnType<typeof getRoutePolicyByID>>
> = ({ signal }) => getRoutePolicyByID({ id }, signal);
return {
queryKey,
queryFn,
enabled: !!id,
...queryOptions,
} as UseQueryOptions<
Awaited<ReturnType<typeof getRoutePolicyByID>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type GetRoutePolicyByIDQueryResult = NonNullable<
Awaited<ReturnType<typeof getRoutePolicyByID>>
>;
export type GetRoutePolicyByIDQueryError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Get route policy by ID
*/
export function useGetRoutePolicyByID<
TData = Awaited<ReturnType<typeof getRoutePolicyByID>>,
TError = ErrorType<RenderErrorResponseDTO>
>(
{ id }: GetRoutePolicyByIDPathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getRoutePolicyByID>>,
TError,
TData
>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getGetRoutePolicyByIDQueryOptions({ id }, options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
query.queryKey = queryOptions.queryKey;
return query;
}
/**
* @summary Get route policy by ID
*/
export const invalidateGetRoutePolicyByID = async (
queryClient: QueryClient,
{ id }: GetRoutePolicyByIDPathParameters,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getGetRoutePolicyByIDQueryKey({ id }) },
options,
);
return queryClient;
};
/**
* This endpoint updates a route policy by ID
* @summary Update route policy
*/
export const updateRoutePolicy = (
{ id }: UpdateRoutePolicyPathParameters,
alertmanagertypesPostableRoutePolicyDTO: BodyType<AlertmanagertypesPostableRoutePolicyDTO>,
) => {
return GeneratedAPIInstance<UpdateRoutePolicy200>({
url: `/api/v1/route_policies/${id}`,
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
data: alertmanagertypesPostableRoutePolicyDTO,
});
};
export const getUpdateRoutePolicyMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof updateRoutePolicy>>,
TError,
{
pathParams: UpdateRoutePolicyPathParameters;
data: BodyType<AlertmanagertypesPostableRoutePolicyDTO>;
},
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof updateRoutePolicy>>,
TError,
{
pathParams: UpdateRoutePolicyPathParameters;
data: BodyType<AlertmanagertypesPostableRoutePolicyDTO>;
},
TContext
> => {
const mutationKey = ['updateRoutePolicy'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof updateRoutePolicy>>,
{
pathParams: UpdateRoutePolicyPathParameters;
data: BodyType<AlertmanagertypesPostableRoutePolicyDTO>;
}
> = (props) => {
const { pathParams, data } = props ?? {};
return updateRoutePolicy(pathParams, data);
};
return { mutationFn, ...mutationOptions };
};
export type UpdateRoutePolicyMutationResult = NonNullable<
Awaited<ReturnType<typeof updateRoutePolicy>>
>;
export type UpdateRoutePolicyMutationBody = BodyType<AlertmanagertypesPostableRoutePolicyDTO>;
export type UpdateRoutePolicyMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Update route policy
*/
export const useUpdateRoutePolicy = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof updateRoutePolicy>>,
TError,
{
pathParams: UpdateRoutePolicyPathParameters;
data: BodyType<AlertmanagertypesPostableRoutePolicyDTO>;
},
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof updateRoutePolicy>>,
TError,
{
pathParams: UpdateRoutePolicyPathParameters;
data: BodyType<AlertmanagertypesPostableRoutePolicyDTO>;
},
TContext
> => {
const mutationOptions = getUpdateRoutePolicyMutationOptions(options);
return useMutation(mutationOptions);
};

File diff suppressed because it is too large Load Diff

View File

@@ -20,15 +20,12 @@ import { useMutation, useQuery } from 'react-query';
import type { BodyType, ErrorType } from '../../../generatedAPIInstance';
import { GeneratedAPIInstance } from '../../../generatedAPIInstance';
import type {
ChangePasswordPathParameters,
CreateInvite201,
CreateResetPasswordToken201,
CreateResetPasswordTokenPathParameters,
DeleteUserPathParameters,
GetMyUser200,
GetMyUserDeprecated200,
GetResetPasswordToken200,
GetResetPasswordTokenDeprecated200,
GetResetPasswordTokenDeprecatedPathParameters,
GetResetPasswordTokenPathParameters,
GetRolesByUserID200,
GetRolesByUserIDPathParameters,
@@ -57,35 +54,133 @@ import type {
} from '../sigNoz.schemas';
/**
* This endpoint returns the reset password token by id
* @deprecated
* @summary Get reset password token
* This endpoint changes the password by id
* @summary Change password
*/
export const getResetPasswordTokenDeprecated = (
{ id }: GetResetPasswordTokenDeprecatedPathParameters,
export const changePassword = (
{ id }: ChangePasswordPathParameters,
typesChangePasswordRequestDTO: BodyType<TypesChangePasswordRequestDTO>,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<GetResetPasswordTokenDeprecated200>({
return GeneratedAPIInstance<void>({
url: `/api/v1/changePassword/${id}`,
method: 'POST',
headers: { 'Content-Type': 'application/json' },
data: typesChangePasswordRequestDTO,
signal,
});
};
export const getChangePasswordMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof changePassword>>,
TError,
{
pathParams: ChangePasswordPathParameters;
data: BodyType<TypesChangePasswordRequestDTO>;
},
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof changePassword>>,
TError,
{
pathParams: ChangePasswordPathParameters;
data: BodyType<TypesChangePasswordRequestDTO>;
},
TContext
> => {
const mutationKey = ['changePassword'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof changePassword>>,
{
pathParams: ChangePasswordPathParameters;
data: BodyType<TypesChangePasswordRequestDTO>;
}
> = (props) => {
const { pathParams, data } = props ?? {};
return changePassword(pathParams, data);
};
return { mutationFn, ...mutationOptions };
};
export type ChangePasswordMutationResult = NonNullable<
Awaited<ReturnType<typeof changePassword>>
>;
export type ChangePasswordMutationBody = BodyType<TypesChangePasswordRequestDTO>;
export type ChangePasswordMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Change password
*/
export const useChangePassword = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof changePassword>>,
TError,
{
pathParams: ChangePasswordPathParameters;
data: BodyType<TypesChangePasswordRequestDTO>;
},
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof changePassword>>,
TError,
{
pathParams: ChangePasswordPathParameters;
data: BodyType<TypesChangePasswordRequestDTO>;
},
TContext
> => {
const mutationOptions = getChangePasswordMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* This endpoint returns the reset password token by id
* @summary Get reset password token
*/
export const getResetPasswordToken = (
{ id }: GetResetPasswordTokenPathParameters,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<GetResetPasswordToken200>({
url: `/api/v1/getResetPasswordToken/${id}`,
method: 'GET',
signal,
});
};
export const getGetResetPasswordTokenDeprecatedQueryKey = ({
export const getGetResetPasswordTokenQueryKey = ({
id,
}: GetResetPasswordTokenDeprecatedPathParameters) => {
}: GetResetPasswordTokenPathParameters) => {
return [`/api/v1/getResetPasswordToken/${id}`] as const;
};
export const getGetResetPasswordTokenDeprecatedQueryOptions = <
TData = Awaited<ReturnType<typeof getResetPasswordTokenDeprecated>>,
export const getGetResetPasswordTokenQueryOptions = <
TData = Awaited<ReturnType<typeof getResetPasswordToken>>,
TError = ErrorType<RenderErrorResponseDTO>
>(
{ id }: GetResetPasswordTokenDeprecatedPathParameters,
{ id }: GetResetPasswordTokenPathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getResetPasswordTokenDeprecated>>,
Awaited<ReturnType<typeof getResetPasswordToken>>,
TError,
TData
>;
@@ -94,11 +189,11 @@ export const getGetResetPasswordTokenDeprecatedQueryOptions = <
const { query: queryOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getGetResetPasswordTokenDeprecatedQueryKey({ id });
queryOptions?.queryKey ?? getGetResetPasswordTokenQueryKey({ id });
const queryFn: QueryFunction<
Awaited<ReturnType<typeof getResetPasswordTokenDeprecated>>
> = ({ signal }) => getResetPasswordTokenDeprecated({ id }, signal);
Awaited<ReturnType<typeof getResetPasswordToken>>
> = ({ signal }) => getResetPasswordToken({ id }, signal);
return {
queryKey,
@@ -106,39 +201,35 @@ export const getGetResetPasswordTokenDeprecatedQueryOptions = <
enabled: !!id,
...queryOptions,
} as UseQueryOptions<
Awaited<ReturnType<typeof getResetPasswordTokenDeprecated>>,
Awaited<ReturnType<typeof getResetPasswordToken>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type GetResetPasswordTokenDeprecatedQueryResult = NonNullable<
Awaited<ReturnType<typeof getResetPasswordTokenDeprecated>>
export type GetResetPasswordTokenQueryResult = NonNullable<
Awaited<ReturnType<typeof getResetPasswordToken>>
>;
export type GetResetPasswordTokenDeprecatedQueryError = ErrorType<RenderErrorResponseDTO>;
export type GetResetPasswordTokenQueryError = ErrorType<RenderErrorResponseDTO>;
/**
* @deprecated
* @summary Get reset password token
*/
export function useGetResetPasswordTokenDeprecated<
TData = Awaited<ReturnType<typeof getResetPasswordTokenDeprecated>>,
export function useGetResetPasswordToken<
TData = Awaited<ReturnType<typeof getResetPasswordToken>>,
TError = ErrorType<RenderErrorResponseDTO>
>(
{ id }: GetResetPasswordTokenDeprecatedPathParameters,
{ id }: GetResetPasswordTokenPathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getResetPasswordTokenDeprecated>>,
Awaited<ReturnType<typeof getResetPasswordToken>>,
TError,
TData
>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getGetResetPasswordTokenDeprecatedQueryOptions(
{ id },
options,
);
const queryOptions = getGetResetPasswordTokenQueryOptions({ id }, options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
@@ -150,16 +241,15 @@ export function useGetResetPasswordTokenDeprecated<
}
/**
* @deprecated
* @summary Get reset password token
*/
export const invalidateGetResetPasswordTokenDeprecated = async (
export const invalidateGetResetPasswordToken = async (
queryClient: QueryClient,
{ id }: GetResetPasswordTokenDeprecatedPathParameters,
{ id }: GetResetPasswordTokenPathParameters,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getGetResetPasswordTokenDeprecatedQueryKey({ id }) },
{ queryKey: getGetResetPasswordTokenQueryKey({ id }) },
options,
);
@@ -1317,189 +1407,6 @@ export const useUpdateUser = <
return useMutation(mutationOptions);
};
/**
* This endpoint returns the existing reset password token for a user.
* @summary Get reset password token for a user
*/
export const getResetPasswordToken = (
{ id }: GetResetPasswordTokenPathParameters,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<GetResetPasswordToken200>({
url: `/api/v2/users/${id}/reset_password_tokens`,
method: 'GET',
signal,
});
};
export const getGetResetPasswordTokenQueryKey = ({
id,
}: GetResetPasswordTokenPathParameters) => {
return [`/api/v2/users/${id}/reset_password_tokens`] as const;
};
export const getGetResetPasswordTokenQueryOptions = <
TData = Awaited<ReturnType<typeof getResetPasswordToken>>,
TError = ErrorType<RenderErrorResponseDTO>
>(
{ id }: GetResetPasswordTokenPathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getResetPasswordToken>>,
TError,
TData
>;
},
) => {
const { query: queryOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getGetResetPasswordTokenQueryKey({ id });
const queryFn: QueryFunction<
Awaited<ReturnType<typeof getResetPasswordToken>>
> = ({ signal }) => getResetPasswordToken({ id }, signal);
return {
queryKey,
queryFn,
enabled: !!id,
...queryOptions,
} as UseQueryOptions<
Awaited<ReturnType<typeof getResetPasswordToken>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type GetResetPasswordTokenQueryResult = NonNullable<
Awaited<ReturnType<typeof getResetPasswordToken>>
>;
export type GetResetPasswordTokenQueryError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Get reset password token for a user
*/
export function useGetResetPasswordToken<
TData = Awaited<ReturnType<typeof getResetPasswordToken>>,
TError = ErrorType<RenderErrorResponseDTO>
>(
{ id }: GetResetPasswordTokenPathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getResetPasswordToken>>,
TError,
TData
>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getGetResetPasswordTokenQueryOptions({ id }, options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
query.queryKey = queryOptions.queryKey;
return query;
}
/**
* @summary Get reset password token for a user
*/
export const invalidateGetResetPasswordToken = async (
queryClient: QueryClient,
{ id }: GetResetPasswordTokenPathParameters,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getGetResetPasswordTokenQueryKey({ id }) },
options,
);
return queryClient;
};
/**
* This endpoint creates or regenerates a reset password token for a user. If a valid token exists, it is returned. If expired, a new one is created.
* @summary Create or regenerate reset password token for a user
*/
export const createResetPasswordToken = ({
id,
}: CreateResetPasswordTokenPathParameters) => {
return GeneratedAPIInstance<CreateResetPasswordToken201>({
url: `/api/v2/users/${id}/reset_password_tokens`,
method: 'PUT',
});
};
export const getCreateResetPasswordTokenMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof createResetPasswordToken>>,
TError,
{ pathParams: CreateResetPasswordTokenPathParameters },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof createResetPasswordToken>>,
TError,
{ pathParams: CreateResetPasswordTokenPathParameters },
TContext
> => {
const mutationKey = ['createResetPasswordToken'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof createResetPasswordToken>>,
{ pathParams: CreateResetPasswordTokenPathParameters }
> = (props) => {
const { pathParams } = props ?? {};
return createResetPasswordToken(pathParams);
};
return { mutationFn, ...mutationOptions };
};
export type CreateResetPasswordTokenMutationResult = NonNullable<
Awaited<ReturnType<typeof createResetPasswordToken>>
>;
export type CreateResetPasswordTokenMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Create or regenerate reset password token for a user
*/
export const useCreateResetPasswordToken = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof createResetPasswordToken>>,
TError,
{ pathParams: CreateResetPasswordTokenPathParameters },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof createResetPasswordToken>>,
TError,
{ pathParams: CreateResetPasswordTokenPathParameters },
TContext
> => {
const mutationOptions = getCreateResetPasswordTokenMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* This endpoint returns the user roles by user id
* @summary Get user roles
@@ -1943,84 +1850,3 @@ export const useUpdateMyUserV2 = <
return useMutation(mutationOptions);
};
/**
* This endpoint updates the password of the user I belong to
* @summary Updates my password
*/
export const updateMyPassword = (
typesChangePasswordRequestDTO: BodyType<TypesChangePasswordRequestDTO>,
) => {
return GeneratedAPIInstance<void>({
url: `/api/v2/users/me/factor_password`,
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
data: typesChangePasswordRequestDTO,
});
};
export const getUpdateMyPasswordMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof updateMyPassword>>,
TError,
{ data: BodyType<TypesChangePasswordRequestDTO> },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof updateMyPassword>>,
TError,
{ data: BodyType<TypesChangePasswordRequestDTO> },
TContext
> => {
const mutationKey = ['updateMyPassword'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof updateMyPassword>>,
{ data: BodyType<TypesChangePasswordRequestDTO> }
> = (props) => {
const { data } = props ?? {};
return updateMyPassword(data);
};
return { mutationFn, ...mutationOptions };
};
export type UpdateMyPasswordMutationResult = NonNullable<
Awaited<ReturnType<typeof updateMyPassword>>
>;
export type UpdateMyPasswordMutationBody = BodyType<TypesChangePasswordRequestDTO>;
export type UpdateMyPasswordMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Updates my password
*/
export const useUpdateMyPassword = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof updateMyPassword>>,
TError,
{ data: BodyType<TypesChangePasswordRequestDTO> },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof updateMyPassword>>,
TError,
{ data: BodyType<TypesChangePasswordRequestDTO> },
TContext
> => {
const mutationOptions = getUpdateMyPasswordMutationOptions(options);
return useMutation(mutationOptions);
};

View File

@@ -0,0 +1,27 @@
import axios from 'api';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/user/changeMyPassword';
const changeMyPassword = async (
props: Props,
): Promise<SuccessResponseV2<PayloadProps>> => {
try {
const response = await axios.post<PayloadProps>(
`/changePassword/${props.userId}`,
{
...props,
},
);
return {
httpStatusCode: response.status,
data: response.data,
};
} catch (error) {
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
}
};
export default changeMyPassword;

View File

@@ -0,0 +1,28 @@
import axios from 'api';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import {
GetResetPasswordToken,
PayloadProps,
Props,
} from 'types/api/user/getResetPasswordToken';
const getResetPasswordToken = async (
props: Props,
): Promise<SuccessResponseV2<GetResetPasswordToken>> => {
try {
const response = await axios.get<PayloadProps>(
`/getResetPasswordToken/${props.userId}`,
);
return {
httpStatusCode: response.status,
data: response.data.data,
};
} catch (error) {
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
}
};
export default getResetPasswordToken;

View File

@@ -10,6 +10,7 @@
// PR for reference: https://github.com/SigNoz/signoz/pull/9694
// -------------------------------------------------------------------------
import '@signozhq/badge';
import '@signozhq/button';
import '@signozhq/calendar';
import '@signozhq/callout';
@@ -24,6 +25,9 @@ import '@signozhq/input';
import '@signozhq/popover';
import '@signozhq/radio-group';
import '@signozhq/resizable';
import '@signozhq/sonner';
import '@signozhq/switch';
import '@signozhq/table';
import '@signozhq/toggle-group';
import '@signozhq/tooltip';
import '@signozhq/ui';

View File

@@ -2,6 +2,13 @@
display: flex;
justify-content: space-between;
align-items: center;
background: var(--l3-background);
border: 1px solid var(--l1-border);
background: var(--bg-ink-300);
border: 1px solid var(--bg-slate-400);
}
.lightMode {
.reset-button {
background: var(--bg-vanilla-100);
border-color: var(--bg-vanilla-300);
}
}

View File

@@ -3,7 +3,7 @@
justify-content: center;
align-items: center;
height: 100vh;
background-color: var(--l2-background); // Background
background-color: var(--bg-ink-400, #121317); // Dark theme background
.app-loading-content {
display: flex;
@@ -28,7 +28,7 @@
.brand-title {
font-size: 20px;
font-weight: 600;
color: var(--l1-foreground); // Primary text
color: var(--bg-vanilla-100, #ffffff); // White text for dark theme
margin: 0;
}
}
@@ -37,7 +37,7 @@
margin-bottom: 24px;
.ant-typography {
color: var(--l2-foreground); // Secondary text
color: var(--bg-vanilla-400, #c0c1c3); // Light gray text for dark theme
}
}
@@ -46,7 +46,7 @@
width: 150px;
height: 12px;
border-radius: 2px;
color: var(--primary-background); // Primary blue color
color: var(--bg-robin-500, #4e74f8); // Primary blue color
border: 2px solid;
position: relative;
}
@@ -67,6 +67,38 @@
}
}
// Light theme styles - more specific selector
.app-loading-container.lightMode {
background-color: var(
--bg-vanilla-100,
#ffffff
) !important; // White background for light theme
.app-loading-content {
.brand {
.brand-title {
color: var(--bg-ink-400, #121317) !important; // Dark text for light theme
}
}
.brand-tagline {
.ant-typography {
color: var(
--bg-ink-300,
#6b7280
) !important; // Dark gray text for light theme
}
}
.loader {
color: var(
--bg-robin-500,
#4e74f8
) !important; // Keep primary blue color for consistency
}
}
}
.perilin-bg {
position: absolute;
top: 0;
@@ -80,12 +112,41 @@
mask-image: radial-gradient(
circle at 50% 0,
color-mix(in srgb, var(--background) 10%, transparent) 0,
transparent 100%
rgba(11, 12, 14, 0.1) 0,
rgba(11, 12, 14, 0) 100%
);
-webkit-mask-image: radial-gradient(
circle at 50% 0,
color-mix(in srgb, var(--background) 10%, transparent) 0,
transparent 100%
rgba(11, 12, 14, 0.1) 0,
rgba(11, 12, 14, 0) 100%
);
}
// Dark theme styles - ensure dark theme is properly applied
.app-loading-container.dark {
background-color: var(--bg-ink-400, #121317) !important; // Dark background
.app-loading-content {
.brand {
.brand-title {
color: var(
--bg-vanilla-100,
#ffffff
) !important; // White text for dark theme
}
}
.brand-tagline {
.ant-typography {
color: var(
--bg-vanilla-400,
#c0c1c3
) !important; // Light gray text for dark theme
}
}
.loader {
color: var(--bg-robin-500, #4e74f8) !important; // Primary blue color
}
}
}

View File

@@ -47,7 +47,7 @@ describe('AppLoading', () => {
// Check for brand logo
const logo = screen.getByAltText(SIGNOZ_TEXT);
expect(logo).toBeInTheDocument();
expect(logo).toHaveAttribute('src', 'test-file-stub');
expect(logo).toHaveAttribute('src');
// Check for brand title
const title = screen.getByText(SIGNOZ_TEXT);

View File

@@ -4,13 +4,12 @@
animation: horizontal-shaking 300ms ease-out;
.error-content {
background: color-mix(in srgb, var(--bg-cherry-500) 10%, transparent);
border: 1px solid color-mix(in srgb, var(--bg-cherry-500) 20%, transparent);
background: rgba(229, 72, 77, 0.1);
border: 1px solid rgba(229, 72, 77, 0.2);
border-radius: 4px;
&__summary-section {
border-bottom: 1px solid
color-mix(in srgb, var(--bg-cherry-500) 20%, transparent);
border-bottom: 1px solid rgba(229, 72, 77, 0.2);
}
&__summary {
@@ -32,7 +31,7 @@
}
&__error-code {
color: var(--bg-cherry-100);
color: #fadadb;
font-size: 13px;
font-weight: 500;
line-height: 1;
@@ -40,7 +39,7 @@
}
&__error-message {
color: var(--bg-cherry-300);
color: #f5b6b8;
font-size: 13px;
font-weight: 400;
line-height: 20px;
@@ -52,13 +51,13 @@
}
&__message-badge-label-text {
color: var(--bg-cherry-100);
color: #fadadb;
}
&__message-badge-line {
background-image: radial-gradient(
circle,
color-mix(in srgb, var(--bg-cherry-500) 30%, transparent) 1px,
rgba(229, 72, 77, 0.3) 1px,
transparent 2px
);
}
@@ -72,23 +71,23 @@
}
&__message-item {
color: var(--bg-cherry-300);
color: #f5b6b8;
font-size: 13px;
font-weight: 400;
line-height: 20px;
letter-spacing: -0.065px;
&::before {
background: var(--bg-cherry-300);
background: #f5b6b8;
}
}
&__scroll-hint {
background: color-mix(in srgb, var(--bg-cherry-500) 20%, transparent);
background: rgba(229, 72, 77, 0.2);
}
&__scroll-hint-text {
color: var(--bg-cherry-100);
color: #fadadb;
}
}
@@ -101,28 +100,27 @@
.lightMode {
.auth-error-container {
.error-content {
background: rgba(229, 72, 77, 0.1);
border-color: rgba(229, 72, 77, 0.2);
&__error-code {
color: var(--l2-foreground);
color: var(--bg-ink-100);
}
&__error-message {
color: var(--l1-foreground);
}
&__message-badge-label-text {
color: var(--l2-foreground);
color: var(--bg-ink-400);
}
&__message-item {
color: var(--l1-foreground);
color: var(--bg-ink-400);
&::before {
background: var(--l3-background);
background: var(--bg-ink-400);
}
}
&__scroll-hint-text {
color: var(--l2-foreground);
color: var(--bg-ink-100);
}
}
}

View File

@@ -16,8 +16,8 @@
justify-content: center;
gap: 16px;
padding: 12px;
background: var(--l2-background);
border: 1px solid var(--l1-border);
background: var(--bg-ink-400);
border: 1px solid var(--bg-ink-200);
border-radius: 4px;
}
@@ -32,7 +32,7 @@
width: 6px;
height: 6px;
border-radius: 9999px;
background: var(--bg-forest-500);
background: #25e192;
flex-shrink: 0;
}
@@ -49,7 +49,7 @@
font-size: 11px;
font-weight: 400;
line-height: 1;
color: var(--l2-foreground);
color: var(--text-neutral-dark-100);
text-align: center;
}
@@ -67,16 +67,16 @@
.auth-footer-link-icon {
flex-shrink: 0;
color: var(--l1-foreground);
color: var(--text-neutral-dark-50);
}
.auth-footer-link-status {
.auth-footer-text {
color: var(--bg-forest-500);
color: #25e192;
}
.auth-footer-link-icon {
color: var(--bg-forest-500);
color: #25e192;
}
}
@@ -84,12 +84,14 @@
width: 4px;
height: 4px;
border-radius: 50%;
background: var(--l3-background);
background: var(--bg-ink-200);
flex-shrink: 0;
}
.lightMode {
.auth-footer-content {
background: var(--bg-base-white);
border-color: var(--bg-vanilla-300);
box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.08);
}
@@ -106,4 +108,8 @@
.auth-footer-link-icon {
color: var(--text-neutral-light-100);
}
.auth-footer-separator {
background: var(--bg-vanilla-300);
}
}

View File

@@ -30,7 +30,7 @@
font-size: 15.4px;
font-weight: 500;
line-height: 17.5px;
color: var(--l1-foreground);
color: var(--text-neutral-dark-50);
white-space: nowrap;
}
@@ -41,7 +41,7 @@
gap: 8px;
height: 32px;
padding: 10px 16px;
background: var(--l2-background);
background: var(--bg-ink-400);
border: none;
border-radius: 2px;
cursor: pointer;
@@ -52,13 +52,13 @@
font-size: 11px;
font-weight: 500;
line-height: 1;
color: var(--l2-foreground);
color: var(--text-neutral-dark-100);
text-align: center;
}
svg {
flex-shrink: 0;
color: var(--l2-foreground);
color: var(--text-neutral-dark-100);
}
&:hover {
@@ -67,8 +67,16 @@
}
.lightMode {
.auth-header-logo-text {
color: var(--text-neutral-light-100);
}
.auth-header-help-button {
background: var(--l2-background);
border: 1px solid var(--l1-border);
background: var(--bg-vanilla-200);
span,
svg {
color: var(--text-neutral-light-200);
}
}
}

View File

@@ -4,7 +4,7 @@
position: relative;
min-height: 100vh;
width: 100%;
background: var(--l1-background);
background: var(--bg-neutral-dark-1000);
display: flex;
flex-direction: column;
}
@@ -43,13 +43,13 @@
.masked-dots {
mask-image: radial-gradient(
circle at 50% 0%,
color-mix(in srgb, var(--background) 10%, transparent) 0%,
transparent 56.77%
rgba(11, 12, 14, 0.1) 0%,
rgba(11, 12, 14, 0) 56.77%
);
-webkit-mask-image: radial-gradient(
circle at 50% 0%,
color-mix(in srgb, var(--background) 10%, transparent) 0%,
transparent 56.77%
rgba(11, 12, 14, 0.1) 0%,
rgba(11, 12, 14, 0) 56.77%
);
}
@@ -65,7 +65,7 @@
border-radius: 956px;
background: radial-gradient(
ellipse at center -500px,
color-mix(in srgb, var(--primary-background) 30%, transparent) 0%,
rgba(78, 116, 248, 0.3) 0%,
transparent 70%
);
opacity: 0.3;
@@ -85,8 +85,8 @@
height: 100%;
background-image: repeating-linear-gradient(
to bottom,
var(--l1-border) 0px,
var(--l1-border) 4px,
var(--bg-ink-200) 0px,
var(--bg-ink-200) 4px,
transparent 4px,
transparent 8px
);
@@ -145,19 +145,19 @@
}
.lightMode {
.auth-page-wrapper {
background: var(--bg-base-white);
}
.bg-dot-pattern {
background: radial-gradient(
circle,
var(--l3-background) 1px,
transparent 1px
);
background: radial-gradient(circle, rgba(35, 38, 46, 1) 1px, transparent 1px);
background-size: 12px 12px;
}
.auth-page-gradient {
background: radial-gradient(
ellipse at center top,
color-mix(in srgb, var(--primary-background) 12%, transparent) 0%,
rgba(78, 116, 248, 0.12) 0%,
transparent 60%
);
opacity: 0.8;
@@ -167,4 +167,15 @@
filter: blur(300px);
}
}
.auth-page-line-left,
.auth-page-line-right {
background-image: repeating-linear-gradient(
to bottom,
var(--bg-vanilla-300) 0px,
var(--bg-vanilla-300) 4px,
transparent 4px,
transparent 8px
);
}
}

View File

@@ -21,8 +21,8 @@
min-width: 164px;
border-radius: 2px;
border: 1px solid var(--l1-border);
background: var(--l3-background);
border: 1px solid var(--bg-slate-400);
background: var(--bg-ink-300);
}
}
}
@@ -31,3 +31,16 @@
flex-shrink: 0;
}
}
.lightMode {
.celery-overview-filters {
.celery-filters {
.config-select-option {
.ant-select-selector {
border: 1px solid var(--bg-vanilla-300);
background: var(--bg-vanilla-100);
}
}
}
}
}

View File

@@ -27,10 +27,10 @@
font-size: 12px;
line-height: 18px;
background: var(--l1-background);
background: var(--bg-ink-500);
border-bottom: none;
color: var(--l2-foreground);
color: var(--Vanilla-400, #c0c1c3);
font-family: Inter;
font-size: 11px;
font-style: normal;
@@ -47,8 +47,8 @@
padding: 12px;
font-size: 13px;
line-height: 20px;
color: var(--l1-foreground);
background: var(--l1-background);
color: var(--bg-vanilla-100);
background: var(--bg-ink-500);
}
.progress-container {
@@ -59,7 +59,7 @@
}
.ant-table-tbody > tr:hover > td {
background: color-mix(in srgb, var(--l1-foreground) 4%, transparent);
background: rgba(255, 255, 255, 0.04);
}
.ant-table-cell:first-child {
@@ -89,7 +89,7 @@
position: relative;
bottom: 0;
width: 100%;
background: var(--l1-background);
background: var(--bg-ink-500);
padding: 4px;
margin: 0;
@@ -100,11 +100,48 @@
border-radius: 4px;
&-active {
background: var(--primary-background);
border-color: var(--primary-background);
background: var(--bg-robin-500);
border-color: var(--bg-robin-500);
a {
color: var(--primary-foreground) !important;
color: var(--bg-ink-500) !important;
}
}
}
}
}
}
.lightMode {
.celery-overview-table-container {
.celery-overview-table {
.ant-table {
.ant-table-thead > tr > th {
background: var(--bg-vanilla-100);
color: var(--text-ink-300);
}
.ant-table-cell {
background: var(--bg-vanilla-100);
color: var(--bg-ink-500);
}
.ant-table-tbody > tr:hover > td {
background: rgba(0, 0, 0, 0.04);
}
}
.ant-pagination {
background: var(--bg-vanilla-100);
.ant-pagination-item {
&-active {
background: var(--bg-robin-500);
border-color: var(--bg-robin-500);
a {
color: var(--bg-vanilla-100) !important;
}
}
}
}

View File

@@ -18,8 +18,21 @@
min-width: 164px;
border-radius: 2px;
border: 1px solid var(--l1-border);
background: var(--l3-background);
border: 1px solid var(--bg-slate-400);
background: var(--bg-ink-300);
}
}
}
}
.lightMode {
.celery-task-filters {
.celery-filters {
.config-select-option {
.ant-select-selector {
border: 1px solid var(--bg-vanilla-300);
background: var(--bg-vanilla-100);
}
}
}
}

View File

@@ -1,7 +1,7 @@
.celery-task-detail-drawer {
.ant-drawer-wrapper-body {
background: var(--l1-background);
border: 1px solid var(--l1-border);
background: var(--bg-ink-500);
border: 1px solid var(--bg-ink-300);
}
.ant-drawer-body {
@@ -11,17 +11,17 @@
border: none;
.ant-card-body {
height: 100%;
background: var(--l1-background);
background: var(--bg-ink-500);
.ant-table {
background: var(--l1-background);
background: var(--bg-ink-500);
}
}
}
}
.ant-drawer-header {
border-bottom: 1px solid var(--l1-border);
border-bottom: 1px solid var(--bg-ink-300);
.ant-drawer-header-title {
.ant-drawer-close {
position: absolute;
@@ -29,7 +29,7 @@
}
button > svg {
color: var(--l1-foreground);
color: var(--bg-vanilla-100);
}
.ant-drawer-title {
@@ -38,7 +38,7 @@
align-items: flex-start;
.title {
color: var(--l1-foreground);
color: var(--bg-vanilla-100);
font-family: Inter;
font-size: 18px;
font-style: normal;
@@ -48,7 +48,7 @@
}
.subtitle {
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
font-family: Inter;
font-size: 12px;
font-style: normal;
@@ -60,10 +60,10 @@
}
.ant-drawer-footer {
border-top: 1px solid var(--l1-border);
border-top: 1px solid var(--bg-ink-300);
.footer-text {
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
font-family: Inter;
font-size: 14px;
font-style: normal;
@@ -72,3 +72,51 @@
}
}
}
.lightMode {
.celery-task-detail-drawer {
.ant-drawer-wrapper-body {
background: var(--bg-vanilla-100);
border: 1px solid var(--bg-vanilla-300);
}
.ant-drawer-body {
.ant-card {
.ant-card-body {
background: var(--bg-vanilla-100);
.ant-table {
background: var(--bg-vanilla-100);
}
}
}
}
.ant-drawer-header {
border-bottom: 1px solid var(--bg-vanilla-300);
.ant-drawer-header-title {
button > svg {
color: var(--bg-ink-500);
}
.ant-drawer-title {
.title {
color: var(--bg-ink-400);
}
.subtitle {
color: var(--bg-ink-300);
}
}
}
}
.ant-drawer-footer {
border-top: 1px solid var(--bg-vanilla-300);
.footer-text {
color: var(--bg-ink-400);
}
}
}
}

View File

@@ -40,8 +40,13 @@
display: flex;
justify-content: center;
align-items: center;
border: 1px solid var(--l1-border);
background: linear-gradient(0deg, transparent 0%, transparent 100%), #0b0c0e;
border: 1px solid var(--bg-slate-500);
background: linear-gradient(
0deg,
rgba(171, 189, 255, 0) 0%,
rgba(171, 189, 255, 0) 100%
),
#0b0c0e;
.ant-card-body {
height: 100%;
@@ -142,13 +147,13 @@
gap: 16px;
align-items: center;
border: 1px dashed var(--l1-border);
border: 1px dashed var(--bg-slate-50);
border-radius: 4px;
padding: 6px 24px 6px 12px;
width: max-content;
.configure-option-Info-text {
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
font-size: 12px;
font-weight: 400;
}
@@ -156,7 +161,7 @@
.row-panel {
border-radius: 4px;
background: color-mix(in srgb, var(--card) 40%, transparent);
background: rgba(18, 19, 23, 0.4);
padding: 8px;
display: flex;
gap: 6px;
@@ -175,12 +180,12 @@
align-items: center;
.row-icon {
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
cursor: pointer;
}
.section-title {
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
font-family: Inter;
font-size: 14px;
font-style: normal;
@@ -193,7 +198,7 @@
}
.celery-task-states {
border-bottom: 1px solid var(--l1-border);
border-bottom: 1px solid var(--bg-ink-200);
&__tab {
min-width: 140px;
@@ -202,11 +207,11 @@
position: relative;
&:not([data-last-tab='true']) {
border-right: 1px solid var(--l1-border);
border-right: 1px solid var(--bg-ink-200);
}
&--selected {
background-color: var(--l3-background);
background-color: rgba(38, 38, 38, 0.5);
}
}
@@ -220,7 +225,7 @@
&__label {
font-family: 'Inter';
font-size: 14px;
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
line-height: 20px;
font-weight: 500;
}
@@ -228,7 +233,7 @@
&__value {
font-family: 'Geist Mono';
font-size: 24px;
color: var(--l1-foreground);
color: var(--bg-vanilla-100);
line-height: 32px;
}
@@ -238,15 +243,46 @@
height: 2px;
bottom: 0;
left: 0;
background-color: var(--l1-foreground);
background-color: var(--bg-vanilla-100);
}
}
.lightMode {
.celery-task-graph-grid-container {
.celery-task-graph-worker-count {
border: 1px solid var(--bg-vanilla-300);
background: unset;
}
.row-panel .row-panel-section .section-title {
color: var(--bg-ink-400);
}
}
.celery-task-states {
border-bottom: 1px solid var(--bg-vanilla-300);
&__tab {
&:not([data-last-tab='true']) {
border-right: 1px solid var(--bg-vanilla-300);
}
&--selected {
background-color: var(--bg-vanilla-200);
}
}
&__label {
color: var(--bg-ink-500);
}
&__value {
color: var(--bg-slate-100);
}
&__indicator {
background-color: var(--bg-ink-400);
}
}
.configure-option-Info {

View File

@@ -26,7 +26,7 @@
}
}
&--negative {
background: color-mix(in srgb, var(--bg-cherry-500) 10%, transparent);
background: rgba(229, 72, 77, 0.1);
.change-percentage-pill {
&__icon {

View File

@@ -1,7 +1,7 @@
.changelog-modal {
.ant-modal-content {
padding: unset;
background-color: var(--l2-background);
background-color: var(--bg-ink-400, #121317);
.ant-modal-header {
margin-bottom: unset;
@@ -16,12 +16,12 @@
display: flex;
align-items: center;
gap: 8px;
background-color: var(--l2-background);
background-color: var(--bg-ink-400, #121317);
padding: 16px;
font-size: 14px;
line-height: 20px;
color: var(--l1-foreground);
border-bottom: 1px solid var(--l1-border);
color: var(--text-vanilla-100, #fff);
border-bottom: 1px solid var(--bg-slate-500, #161922);
}
&-footer.scroll-available {
@@ -32,14 +32,14 @@
&-footer {
position: relative;
border: 1px solid var(--l1-border);
border: 1px solid var(--bg-slate-500, #161922);
padding: 12px;
display: flex;
align-items: center;
justify-content: space-between;
&-label {
color: var(--text-robin-400);
color: var(--text-robin-400, #7190f9);
font-size: 14px;
line-height: 24px;
position: relative;
@@ -54,7 +54,7 @@
width: 6px;
height: 6px;
border-radius: 100%;
background-color: var(--primary-background);
background-color: var(--bg-robin-500, #7190f9);
}
}
@@ -77,7 +77,7 @@
.scroll-btn {
all: unset;
padding: 4px 12px 4px 10px;
background-color: var(--l1-border);
background-color: var(--bg-slate-400, #1d212d);
border-radius: 20px;
cursor: pointer;
display: flex;
@@ -87,17 +87,17 @@
transition: background-color 0.1s;
&:hover {
background-color: var(--l1-border);
background-color: var(--bg-slate-200, #2c3140);
}
&:active {
background-color: var(--l1-border);
background-color: var(--bg-slate-600, #1c1f2a);
}
span {
font-size: 12px;
line-height: 18px;
color: var(--l2-foreground);
color: var(--text-vanilla-400, #c0c1c3);
}
// add animation to the chevrons down icon
@@ -112,7 +112,7 @@
max-height: calc(100vh - 300px);
overflow-y: auto;
padding: 16px 16px 18px 16px;
border: 1px solid var(--l1-border);
border: 1px solid var(--bg-slate-500, #161922);
border-top-width: 0;
border-bottom-width: 0;
}
@@ -127,3 +127,36 @@
opacity: 0.5;
}
}
.lightMode {
.changelog-modal {
.ant-modal-content {
background-color: var(--bg-vanilla-100);
border-color: var(--bg-vanilla-300);
}
&-title {
background: var(--bg-vanilla-100);
color: var(--bg-ink-500);
border-color: var(--bg-vanilla-300);
}
&-content {
border-color: var(--bg-vanilla-300);
}
&-footer {
border-color: var(--bg-vanilla-300);
.scroll-btn-container {
.scroll-btn {
background-color: var(--bg-vanilla-300);
span {
color: var(--text-ink-500);
}
}
}
}
}
}

View File

@@ -34,7 +34,7 @@ const mockChangelog: ChangelogSchema = {
id: 1,
documentId: 'doc1',
ext: '.webp',
url: 'assets/uploads/feature1.webp',
url: '/uploads/feature1.webp',
mime: 'image/webp',
alternativeText: null,
},

View File

@@ -15,13 +15,13 @@
&-section-title {
font-size: 14px;
line-height: 20px;
color: var(--l1-foreground);
color: var(--text-vanilla-400, #c0c1c3);
}
.changelog-release-date {
font-size: 14px;
line-height: 20px;
color: var(--l1-foreground);
color: var(--text-vanilla-400, #c0c1c3);
display: block;
margin-bottom: 12px;
}
@@ -38,7 +38,7 @@
top: 6px;
bottom: -30px;
width: 1px;
background-color: var(--l1-border);
background-color: var(--bg-slate-400, #1d212d);
.inner-ball {
position: absolute;
@@ -47,7 +47,7 @@
height: 6px;
border-radius: 100%;
transform: translateX(-50%);
background-color: var(--primary-background);
background-color: var(--bg-robin-500, #7190f9);
}
}
@@ -69,7 +69,7 @@
top: 10px;
width: 20px;
height: 2px;
background-color: var(--primary-background);
background-color: var(--bg-robin-500, #7190f9);
transform: translate(-100%, -50%);
}
}
@@ -79,20 +79,19 @@
p {
font-size: 14px;
line-height: 20px;
color: var(--l1-foreground);
color: var(--text-vanilla-400, #c0c1c3);
}
code {
padding: 2px 4px;
background-color: var(--l1-border);
background-color: var(--bg-slate-500, #161922);
border-radius: 6px;
font-size: 95%;
vertical-align: middle;
border: 1px solid var(--l1-border);
color: var(--l1-foreground);
border: 1px solid var(--bg-slate-600, #1c1f2a);
}
a {
color: var(--text-robin-500);
color: var(--text-robin-500, #7190f9);
font-weight: 600;
text-decoration: underline;
@@ -103,7 +102,7 @@
& :is(h1, h2, h3, h4, h5, h6, &-section-title) {
font-weight: 600;
color: var(--l1-foreground);
color: var(--text-vanilla-100, #fff);
}
h1 {
@@ -123,7 +122,7 @@
width: 100%;
overflow: hidden;
border-radius: 4px;
border: 1px solid var(--l1-border);
border: 1px solid var(--bg-slate-400, #1d212d);
margin-bottom: 28px;
}
@@ -131,3 +130,25 @@
margin: 12px 0;
}
}
.lightMode {
.changelog-renderer {
.changelog-release-date {
color: var(--text-ink-500);
}
&-line {
background-color: var(--bg-vanilla-300);
}
& :is(h1, h2, h3, h4, h5, h6, p, li, &-section-title) {
color: var(--text-ink-500);
}
code {
background-color: var(--bg-vanilla-300);
border: 1px solid var(--bg-vanilla-300);
color: var(--text-ink-500);
}
}
}

View File

@@ -18,7 +18,7 @@
font-weight: var(--label-base-400-font-weight);
line-height: var(--label-base-400-line-height);
letter-spacing: -0.065px;
color: var(--l1-foreground);
color: var(--bg-base-white);
margin: 0;
}
@@ -54,7 +54,7 @@
height: 32px;
color: var(--l1-foreground);
background-color: var(--l2-background);
border-color: var(--l1-border);
border-color: var(--border);
font-size: var(--paragraph-base-400-font-size);
border-radius: 2px;
width: 100%;
@@ -96,3 +96,11 @@
gap: var(--spacing-4);
flex-shrink: 0;
}
.lightMode {
.create-sa-modal {
[data-slot='dialog-title'] {
color: var(--bg-base-black);
}
}
}

View File

@@ -4,7 +4,7 @@ import { Button } from '@signozhq/button';
import { DialogFooter, DialogWrapper } from '@signozhq/dialog';
import { X } from '@signozhq/icons';
import { Input } from '@signozhq/input';
import { toast } from '@signozhq/ui';
import { toast } from '@signozhq/sonner';
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
import {
invalidateListServiceAccounts,

View File

@@ -1,12 +1,11 @@
import { toast } from '@signozhq/ui';
import { toast } from '@signozhq/sonner';
import { rest, server } from 'mocks-server/server';
import { NuqsTestingAdapter } from 'nuqs/adapters/testing';
import { render, screen, userEvent, waitFor } from 'tests/test-utils';
import CreateServiceAccountModal from '../CreateServiceAccountModal';
jest.mock('@signozhq/ui', () => ({
...jest.requireActual('@signozhq/ui'),
jest.mock('@signozhq/sonner', () => ({
toast: { success: jest.fn(), error: jest.fn() },
}));

View File

@@ -9,17 +9,16 @@
align-items: center;
justify-content: center;
flex-shrink: 0;
color: var(--secondary-foreground);
background-color: var(--secondary-background);
border: 1px solid var(--secondary-border);
color: var(--foreground);
border: 1px solid var(--border);
border-radius: 2px;
box-shadow: none;
padding: 10px;
height: 33px;
&:hover:not(:disabled) {
color: var(--primary-foreground);
background: var(--primary-background);
color: var(--bg-vanilla-100);
background: var(--primary);
}
&:disabled {
@@ -30,7 +29,7 @@
.timeSelection-input {
&:hover {
border-color: var(--l1-border) !important;
border-color: #1d212d !important;
}
}
@@ -99,7 +98,7 @@
justify-content: center;
padding: 4px;
cursor: default;
color: var(--l2-foreground) !important;
color: var(--bg-vanilla-400, #c0c1c3) !important;
font-size: 14px;
font-style: normal;
font-weight: 400;
@@ -147,10 +146,14 @@
color: rgba($color: #000000, $alpha: 0.4);
}
}
.info-text {
color: var(--bg-slate-400) !important;
}
}
.date-time-popover__footer {
border-top: 1px solid var(--l1-border);
border-top: 1px solid var(--bg-ink-200);
padding: 8px 14px;
.timezone-container {
display: flex;
@@ -202,7 +205,7 @@
display: flex;
align-items: center;
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
gap: 6px;
.timezone {
@@ -210,10 +213,10 @@
align-items: center;
gap: 4px;
border-radius: 2px;
background: color-mix(in srgb, var(--bg-robin-200) 4%, transparent);
background: rgba(171, 189, 255, 0.04);
cursor: pointer;
padding: 0px 4px;
color: var(--l1-foreground);
color: var(--bg-vanilla-100);
border: none;
}
}
@@ -225,8 +228,8 @@
justify-content: center;
padding: 0 4px;
border-radius: 2px;
color: var(--l2-foreground);
background-color: var(--l3-background);
color: var(--bg-vanilla-400);
background-color: var(--bg-ink-200);
font-size: 9px;
font-weight: 400;
line-height: 12px;
@@ -246,8 +249,8 @@
width: 36px;
font-size: 11px;
color: var(--l2-foreground);
background-color: var(--l3-background);
color: var(--bg-vanilla-400);
background-color: var(--bg-ink-200);
cursor: pointer;
&.is-live {
@@ -269,14 +272,13 @@
@keyframes ripple {
0% {
box-shadow: 0 0 0 0
color-mix(in srgb, var(--warning-background) 40%, transparent);
box-shadow: 0 0 0 0 rgba(245, 158, 11, 0.4);
}
60% {
box-shadow: 0 0 0 6px transparent;
box-shadow: 0 0 0 6px rgba(245, 158, 11, 0);
}
100% {
box-shadow: 0 0 0 0 transparent;
box-shadow: 0 0 0 0 rgba(245, 158, 11, 0);
}
}
@@ -286,8 +288,8 @@
justify-content: center;
padding: 0 4px;
border-radius: 2px;
background: color-mix(in srgb, var(--bg-robin-200) 4%, transparent);
color: var(--l1-foreground);
background: rgba(171, 189, 255, 0.04);
color: var(--bg-vanilla-100);
font-size: 12px;
font-weight: 400;
line-height: 16px;
@@ -297,16 +299,23 @@
width: 20px;
&:hover {
background: color-mix(in srgb, var(--bg-robin-200) 8%, transparent);
background: rgba(171, 189, 255, 0.08);
}
}
.lightMode {
.date-time-popover__footer {
border-color: var(--bg-vanilla-400);
}
.timezone-container {
color: var(--bg-ink-400);
.timezone {
color: var(--bg-ink-100);
background: rgb(179 179 179 / 15%);
&__icon {
stroke: var(--l1-foreground);
stroke: var(--bg-ink-100);
}
}
}
@@ -314,16 +323,23 @@
.custom-time-picker {
.timeSelection-input {
&:hover {
border-color: var(--l1-border) !important;
border-color: var(--bg-vanilla-300) !important;
}
}
}
.timezone-badge {
color: var(--bg-ink-100);
background: rgb(179 179 179 / 15%);
}
.time-input-prefix {
background-color: var(--bg-vanilla-300);
color: var(--bg-ink-400);
}
.time-input-suffix-icon-badge {
color: var(--bg-ink-100);
background: rgb(179 179 179 / 15%);
&:hover {

View File

@@ -656,13 +656,15 @@ function CustomTimePicker({
zoomOutDisabled ? 'Zoom out time range is limited to 1 month' : 'Zoom out'
}
>
<Button
className="zoom-out-btn"
onClick={handleZoomOut}
disabled={zoomOutDisabled}
data-testid="zoom-out-btn"
prefixIcon={<ZoomOut size={14} />}
/>
<span>
<Button
className="zoom-out-btn"
onClick={handleZoomOut}
disabled={zoomOutDisabled}
data-testid="zoom-out-btn"
prefixIcon={<ZoomOut size={14} />}
/>
</span>
</Tooltip>
)}
</div>

View File

@@ -3,7 +3,11 @@ $font-family: 'Inter';
$item-spacing: 8px;
:root {
--border-color: var(--l1-border);
--border-color: var(--bg-slate-400);
}
.lightMode {
--border-color: var(--bg-vanilla-400);
}
// Mixins
@@ -20,7 +24,7 @@ $item-spacing: 8px;
.timezone-picker {
width: 532px;
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
font-family: $font-family;
&__search {
@@ -42,7 +46,7 @@ $item-spacing: 8px;
background: transparent;
border: none;
outline: none;
color: var(--l1-foreground);
color: var(--bg-vanilla-100);
font-size: 14px;
line-height: 20px;
letter-spacing: -0.07px;
@@ -52,19 +56,19 @@ $item-spacing: 8px;
}
&::placeholder {
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
}
}
&__esc-key {
@include text-style-base;
font-size: 8px;
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
letter-spacing: -0.04px;
border-radius: 2.286px;
border: 1.143px solid var(--l1-border);
border: 1.143px solid var(--bg-ink-200);
border-bottom-width: 2.286px;
background: var(--l2-background);
background: var(--bg-ink-400);
padding: 0 1px;
}
@@ -82,14 +86,14 @@ $item-spacing: 8px;
background: transparent;
border: none;
width: -webkit-fill-available;
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
font-family: $font-family;
&:hover,
&.selected {
border-radius: 2px;
background: color-mix(in srgb, var(--bg-robin-200) 4%, transparent);
color: var(--l1-foreground);
background: rgba(171, 189, 255, 0.04);
color: var(--bg-vanilla-100);
}
&.has-divider {
@@ -113,7 +117,7 @@ $item-spacing: 8px;
}
&__offset {
color: var(--l1-foreground);
color: var(--bg-vanilla-100);
font-size: 12px;
line-height: 16px;
letter-spacing: -0.06px;
@@ -134,14 +138,28 @@ $item-spacing: 8px;
.timezone-picker {
&__search {
.search-icon {
stroke: var(--l1-foreground);
stroke: var(--bg-ink-400);
}
}
&__input {
color: var(--bg-ink-100);
}
&__esc-key {
background-color: var(--bg-vanilla-100);
border-color: var(--bg-vanilla-400);
color: var(--bg-ink-400);
}
&__item {
color: var(--bg-ink-400);
}
&__offset {
color: var(--bg-ink-100);
}
}
.timezone-name-wrapper {
&__selected-icon {
.check-icon {
stroke: var(--l1-foreground);
stroke: var(--bg-ink-100);
}
}
}

View File

@@ -1,10 +1,10 @@
.details-drawer {
.ant-drawer-wrapper-body {
border-left: 1px solid var(--l1-border);
border-left: 1px solid var(--bg-slate-500);
}
.ant-drawer-header {
background: var(--l2-background);
border-bottom: 1px solid var(--l1-border);
background: var(--bg-ink-400);
border-bottom: 1px solid var(--bg-slate-500);
.ant-drawer-header-title {
display: flex;
@@ -14,12 +14,12 @@
margin-inline-end: 0px;
padding: 0px;
padding-right: 16px;
border-right: 1px solid var(--l1-border);
border-right: 1px solid var(--bg-slate-500);
}
.ant-drawer-title {
padding-left: 16px;
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
font-family: Inter;
font-size: 14px;
font-style: normal;
@@ -31,7 +31,7 @@
}
.ant-drawer-body {
padding: 16px;
background: var(--l2-background);
background: var(--bg-ink-400);
&::-webkit-scrollbar {
width: 0.1rem;
@@ -50,11 +50,11 @@
flex-shrink: 0;
padding: 7px 20px;
border-radius: 2px 0px 0px 2px;
border: 1px solid var(--l1-border);
background: var(--l2-background);
border: 1px solid var(--bg-slate-400);
background: var(--bg-ink-400);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
color: var(--l1-foreground);
color: #fff;
font-family: Inter;
font-size: 12px;
font-style: normal;
@@ -75,7 +75,7 @@
}
.ant-tabs-tab-active {
background: var(--l3-background);
background: var(--bg-slate-400);
}
.ant-tabs-tab + .ant-tabs-tab {
@@ -91,3 +91,44 @@
}
}
}
.lightMode {
.details-drawer {
.ant-drawer-wrapper-body {
border-left: 1px solid var(--bg-vanilla-300);
}
.ant-drawer-header {
background: var(--bg-vanilla-200);
border-bottom: 1px solid var(--bg-vanilla-300);
.ant-drawer-header-title {
.ant-drawer-close {
border-right: 1px solid var(--bg-vanilla-300);
}
.ant-drawer-title {
color: var(--bg-ink-400);
}
}
}
.ant-drawer-body {
background: var(--bg-vanilla-200);
}
.details-drawer-tabs {
.ant-tabs-tab {
border: 1px solid var(--bg-vanilla-300);
background: var(--bg-vanilla-300);
color: var(--bg-ink-400);
}
.ant-tabs-tab-active {
background: var(--bg-vanilla-200);
}
.ant-tabs-tab + .ant-tabs-tab {
border-left: none;
}
}
}
}

View File

@@ -1,7 +1,7 @@
.download-popover {
.ant-popover-inner {
border-radius: 4px;
border: 1px solid var(--l1-border);
border: 1px solid var(--l3-border);
background: linear-gradient(
139deg,
var(--l2-background) 0%,
@@ -46,7 +46,7 @@
.horizontal-line {
height: 1px;
background: var(--l1-border);
background: var(--l3-border);
}
.export-button {
@@ -57,3 +57,30 @@
}
}
}
.lightMode {
.download-popover {
.ant-popover-inner {
border: 1px solid var(--l2-border);
background: linear-gradient(
139deg,
var(--background) 0%,
var(--l1-background) 98.68%
);
box-shadow: 4px 10px 16px 2px rgba(255, 255, 255, 0.2);
}
.export-options-container {
.title {
color: var(--l2-foreground);
}
:global(.ant-radio-wrapper) {
color: var(--foreground);
}
.horizontal-line {
background: var(--l2-border);
}
}
}
}

View File

@@ -32,7 +32,7 @@
&__input {
height: 32px;
background: var(--l2-background);
border-color: var(--l1-border);
border-color: var(--border);
color: var(--l1-foreground);
box-shadow: none;
@@ -49,7 +49,7 @@
padding: var(--padding-1) var(--padding-2);
border-radius: 2px;
background: var(--l2-background);
border: 1px solid var(--l1-border);
border: 1px solid var(--border);
&--disabled {
cursor: not-allowed;
@@ -122,7 +122,7 @@
width: 100%;
height: 56px;
padding: 0 var(--padding-4);
border-top: 1px solid var(--l1-border);
border-top: 1px solid var(--border);
flex-shrink: 0;
background: var(--card);
}
@@ -142,7 +142,7 @@
&__footer-divider {
width: 1px;
height: 21px;
background: var(--l1-border);
background: var(--border);
flex-shrink: 0;
}
@@ -175,7 +175,7 @@
}
&--danger {
color: var(--accent-cherry);
color: var(--destructive);
}
&--warning {
@@ -186,7 +186,7 @@
.delete-dialog {
background: var(--l2-background);
border: 1px solid var(--l1-border);
border: 1px solid var(--l2-border);
[data-slot='dialog-title'] {
color: var(--l1-foreground);
@@ -216,10 +216,10 @@
.reset-link-dialog {
background: var(--l2-background);
border: 1px solid var(--l1-border);
border: 1px solid var(--l2-border);
[data-slot='dialog-header'] {
border-color: var(--l1-border);
border-color: var(--l2-border);
color: var(--l1-foreground);
}
@@ -250,7 +250,7 @@
height: 32px;
overflow: hidden;
background: var(--l2-background);
border: 1px solid var(--l1-border);
border: 1px solid var(--border);
border-radius: 2px;
}
@@ -280,7 +280,7 @@
border-top: none;
border-right: none;
border-bottom: none;
border-left: 1px solid var(--l1-border);
border-left: 1px solid var(--border);
min-width: 64px;
}
}

View File

@@ -1,17 +1,17 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import { useCopyToClipboard } from 'react-use';
import { Badge } from '@signozhq/badge';
import { Button } from '@signozhq/button';
import { DrawerWrapper } from '@signozhq/drawer';
import { LockKeyhole, RefreshCw, Trash2, X } from '@signozhq/icons';
import { Input } from '@signozhq/input';
import { Badge, toast } from '@signozhq/ui';
import { toast } from '@signozhq/sonner';
import { Skeleton, Tooltip } from 'antd';
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
import type { RenderErrorResponseDTO } from 'api/generated/services/sigNoz.schemas';
import {
useCreateResetPasswordToken,
getResetPasswordToken,
useDeleteUser,
useGetResetPasswordToken,
useGetUser,
useUpdateMyUserV2,
useUpdateUser,
@@ -55,27 +55,6 @@ function getDeleteTooltip(
return undefined;
}
function getInviteButtonLabel(
isLoading: boolean,
existingToken: { expiresAt?: Date } | undefined,
isExpired: boolean,
notFound: boolean,
): string {
if (isLoading) {
return 'Checking invite...';
}
if (existingToken && !isExpired) {
return 'Copy Invite Link';
}
if (isExpired) {
return 'Regenerate Invite Link';
}
if (notFound) {
return 'Generate Invite Link';
}
return 'Copy Invite Link';
}
function toSaveApiError(err: unknown): APIError {
return (
convertToApiError(err as AxiosError<RenderErrorResponseDTO>) ??
@@ -104,11 +83,9 @@ function EditMemberDrawer({
const [localRole, setLocalRole] = useState('');
const [isSaving, setIsSaving] = useState(false);
const [saveErrors, setSaveErrors] = useState<SaveError[]>([]);
const [isGeneratingLink, setIsGeneratingLink] = useState(false);
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
const [resetLink, setResetLink] = useState<string | null>(null);
const [resetLinkExpiresAt, setResetLinkExpiresAt] = useState<string | null>(
null,
);
const [showResetLinkDialog, setShowResetLinkDialog] = useState(false);
const [hasCopiedResetLink, setHasCopiedResetLink] = useState(false);
const [linkType, setLinkType] = useState<'invite' | 'reset' | null>(null);
@@ -144,27 +121,6 @@ function EditMemberDrawer({
applyDiff,
} = useMemberRoleManager(member?.id ?? '', open && !!member?.id);
// Token status query for invited users
const {
data: tokenQueryData,
isLoading: isLoadingTokenStatus,
isError: tokenNotFound,
} = useGetResetPasswordToken(
{ id: member?.id ?? '' },
{ query: { enabled: open && !!member?.id && isInvited } },
);
const existingToken = tokenQueryData?.data;
const isTokenExpired =
existingToken != null &&
new Date(String(existingToken.expiresAt)) < new Date();
// Create/regenerate token mutation
const {
mutateAsync: createTokenMutation,
isLoading: isGeneratingLink,
} = useCreateResetPasswordToken();
const fetchedDisplayName =
fetchedUser?.data?.displayName ?? member?.name ?? '';
const fetchedUserId = fetchedUser?.data?.id;
@@ -382,21 +338,12 @@ function EditMemberDrawer({
if (!member) {
return;
}
setIsGeneratingLink(true);
try {
const response = await createTokenMutation({
pathParams: { id: member.id },
});
const response = await getResetPasswordToken({ id: member.id });
if (response?.data?.token) {
const link = `${window.location.origin}/password-reset?token=${response.data.token}`;
setResetLink(link);
setResetLinkExpiresAt(
response.data.expiresAt
? formatTimezoneAdjustedTimestamp(
String(response.data.expiresAt),
DATE_TIME_FORMATS.DASH_DATETIME,
)
: null,
);
setHasCopiedResetLink(false);
setLinkType(isInvited ? 'invite' : 'reset');
setShowResetLinkDialog(true);
@@ -412,8 +359,10 @@ function EditMemberDrawer({
err as AxiosError<RenderErrorResponseDTO, unknown> | null,
);
showErrorModal(errMsg as APIError);
} finally {
setIsGeneratingLink(false);
}
}, [member, isInvited, onClose, showErrorModal, createTokenMutation]);
}, [member, isInvited, onClose, showErrorModal]);
const [copyState, copyToClipboard] = useCopyToClipboard();
const handleCopyResetLink = useCallback((): void => {
@@ -619,19 +568,12 @@ function EditMemberDrawer({
<Button
className="edit-member-drawer__footer-btn edit-member-drawer__footer-btn--warning"
onClick={handleGenerateResetLink}
disabled={isGeneratingLink || isRootUser || isLoadingTokenStatus}
disabled={isGeneratingLink || isRootUser}
>
<RefreshCw size={12} />
{isGeneratingLink
? 'Generating...'
: isInvited
? getInviteButtonLabel(
isLoadingTokenStatus,
existingToken,
isTokenExpired,
tokenNotFound,
)
: 'Generate Password Reset Link'}
{isGeneratingLink && 'Generating...'}
{!isGeneratingLink && isInvited && 'Copy Invite Link'}
{!isGeneratingLink && !isInvited && 'Generate Password Reset Link'}
</Button>
</span>
</Tooltip>
@@ -681,7 +623,6 @@ function EditMemberDrawer({
open={showResetLinkDialog}
linkType={linkType}
resetLink={resetLink}
expiresAt={resetLinkExpiresAt}
hasCopied={hasCopiedResetLink}
onClose={(): void => {
setShowResetLinkDialog(false);

View File

@@ -6,7 +6,6 @@ interface ResetLinkDialogProps {
open: boolean;
linkType: 'invite' | 'reset' | null;
resetLink: string | null;
expiresAt: string | null;
hasCopied: boolean;
onClose: () => void;
onCopy: () => void;
@@ -16,7 +15,6 @@ function ResetLinkDialog({
open,
linkType,
resetLink,
expiresAt,
hasCopied,
onClose,
onCopy,
@@ -55,11 +53,6 @@ function ResetLinkDialog({
{hasCopied ? 'Copied!' : 'Copy'}
</Button>
</div>
{expiresAt && (
<p className="reset-link-dialog__description">
This link expires on {expiresAt}.
</p>
)}
</div>
</DialogWrapper>
);

View File

@@ -1,10 +1,9 @@
import type { ReactNode } from 'react';
import { toast } from '@signozhq/ui';
import { toast } from '@signozhq/sonner';
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
import {
useCreateResetPasswordToken,
getResetPasswordToken,
useDeleteUser,
useGetResetPasswordToken,
useGetUser,
useSetRoleByUserID,
useUpdateMyUserV2,
@@ -56,16 +55,14 @@ jest.mock('api/generated/services/users', () => ({
useUpdateUser: jest.fn(),
useUpdateMyUserV2: jest.fn(),
useSetRoleByUserID: jest.fn(),
useGetResetPasswordToken: jest.fn(),
useCreateResetPasswordToken: jest.fn(),
getResetPasswordToken: jest.fn(),
}));
jest.mock('api/ErrorResponseHandlerForGeneratedAPIs', () => ({
convertToApiError: jest.fn(),
}));
jest.mock('@signozhq/ui', () => ({
...jest.requireActual('@signozhq/ui'),
jest.mock('@signozhq/sonner', () => ({
toast: {
success: jest.fn(),
error: jest.fn(),
@@ -85,7 +82,7 @@ jest.mock('react-use', () => ({
const ROLES_ENDPOINT = '*/api/v1/roles';
const mockDeleteMutate = jest.fn();
const mockCreateTokenMutateAsync = jest.fn();
const mockGetResetPasswordToken = jest.mocked(getResetPasswordToken);
const showErrorModal = jest.fn();
jest.mock('providers/ErrorModalProvider', () => ({
@@ -187,31 +184,6 @@ describe('EditMemberDrawer', () => {
mutate: mockDeleteMutate,
isLoading: false,
});
// Token query: valid token for invited members
(useGetResetPasswordToken as jest.Mock).mockReturnValue({
data: {
data: {
token: 'invite-tok-valid',
id: 'token-1',
expiresAt: new Date(Date.now() + 86400000).toISOString(),
},
},
isLoading: false,
isError: false,
});
// Create token mutation
mockCreateTokenMutateAsync.mockResolvedValue({
status: 'success',
data: {
token: 'reset-tok-abc',
id: 'user-1',
expiresAt: new Date(Date.now() + 86400000).toISOString(),
},
});
(useCreateResetPasswordToken as jest.Mock).mockReturnValue({
mutateAsync: mockCreateTokenMutateAsync,
isLoading: false,
});
});
afterEach(() => {
@@ -385,40 +357,6 @@ describe('EditMemberDrawer', () => {
expect(screen.queryByText('Last Modified')).not.toBeInTheDocument();
});
it('shows "Regenerate Invite Link" when token is expired', () => {
(useGetResetPasswordToken as jest.Mock).mockReturnValue({
data: {
data: {
token: 'old-tok',
id: 'token-1',
expiresAt: new Date(Date.now() - 86400000).toISOString(), // expired yesterday
},
},
isLoading: false,
isError: false,
});
renderDrawer({ member: invitedMember });
expect(
screen.getByRole('button', { name: /regenerate invite link/i }),
).toBeInTheDocument();
});
it('shows "Generate Invite Link" when no token exists', () => {
(useGetResetPasswordToken as jest.Mock).mockReturnValue({
data: undefined,
isLoading: false,
isError: true,
});
renderDrawer({ member: invitedMember });
expect(
screen.getByRole('button', { name: /generate invite link/i }),
).toBeInTheDocument();
});
it('calls deleteUser after confirming revoke invite for invited members', async () => {
const onComplete = jest.fn();
const user = userEvent.setup({ pointerEventsCheck: 0 });
@@ -671,7 +609,7 @@ describe('EditMemberDrawer', () => {
).not.toBeInTheDocument();
});
it('does not call createResetPasswordToken when Reset Link is clicked while disabled (root)', async () => {
it('does not call getResetPasswordToken when Reset Link is clicked while disabled (root)', async () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
renderDrawer();
@@ -679,16 +617,20 @@ describe('EditMemberDrawer', () => {
screen.getByRole('button', { name: /generate password reset link/i }),
);
expect(mockCreateTokenMutateAsync).not.toHaveBeenCalled();
expect(mockGetResetPasswordToken).not.toHaveBeenCalled();
});
});
describe('Generate Password Reset Link', () => {
beforeEach(() => {
mockCopyToClipboard.mockClear();
mockGetResetPasswordToken.mockResolvedValue({
status: 'success',
data: { token: 'reset-tok-abc', id: 'user-1' },
});
});
it('calls POST and opens the reset link dialog with the generated link and expiry', async () => {
it('calls getResetPasswordToken and opens the reset link dialog with the generated link', async () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
renderDrawer();
@@ -700,12 +642,11 @@ describe('EditMemberDrawer', () => {
const dialog = await screen.findByRole('dialog', {
name: /password reset link/i,
});
expect(mockCreateTokenMutateAsync).toHaveBeenCalledWith({
pathParams: { id: 'user-1' },
expect(mockGetResetPasswordToken).toHaveBeenCalledWith({
id: 'user-1',
});
expect(dialog).toBeInTheDocument();
expect(dialog).toHaveTextContent('reset-tok-abc');
expect(dialog).toHaveTextContent(/this link expires on/i);
});
it('copies the link to clipboard and shows "Copied!" on the button', async () => {

View File

@@ -5,7 +5,7 @@
align-items: center;
gap: 4px;
border-radius: 20px;
background: color-mix(in srgb, var(--bg-cherry-500) 20%, transparent);
background: rgba(229, 72, 77, 0.2);
padding-left: 3px;
padding-right: 8px;
cursor: pointer;
@@ -21,11 +21,11 @@
&__wrap {
background: linear-gradient(
180deg,
color-mix(in srgb, var(--background) 12%, transparent) 0.07%,
color-mix(in srgb, var(--bg-sakura-950) 24%, transparent) 50.04%,
color-mix(in srgb, var(--bg-sakura-800) 36%, transparent) 75.02%,
color-mix(in srgb, var(--bg-sakura-600) 48%, transparent) 87.51%,
color-mix(in srgb, var(--bg-sakura-500) 60%, transparent) 100%
rgba(11, 12, 14, 0.12) 0.07%,
rgba(39, 8, 14, 0.24) 50.04%,
rgba(106, 29, 44, 0.36) 75.02%,
rgba(197, 57, 85, 0.48) 87.51%,
rgba(242, 71, 105, 0.6) 100%
);
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
@@ -42,7 +42,7 @@
}
&__body {
padding: 0;
background: var(--l2-background);
background: var(--bg-ink-400);
overflow: hidden;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
@@ -72,21 +72,21 @@
text-transform: uppercase;
&,
&:hover {
color: var(--l1-foreground);
color: var(--bg-vanilla-100);
}
}
&__value {
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
pointer-events: none;
}
}
.close-button {
padding: 3px 7px;
background: var(--l2-background);
background: var(--bg-ink-400);
display: inline-flex;
align-items: center;
border-radius: 4px;
border: 1px solid var(--l1-border);
border: 1px solid var(--bg-slate-500);
box-shadow: none;
}
}
@@ -102,3 +102,17 @@
background: none !important;
}
}
.lightMode {
.error-modal {
&__body,
&__header .close-button {
background: var(--bg-vanilla-100);
}
&__header .close-button {
svg {
fill: var(--bg-vanilla-100);
}
}
}
}

View File

@@ -5,7 +5,7 @@
&__summary-section {
display: flex;
flex-direction: column;
border-bottom: 1px solid var(--l1-border);
border-bottom: 1px solid var(--bg-slate-400);
}
&__summary {
@@ -27,7 +27,7 @@
}
&__error-code {
color: var(--l1-foreground);
color: var(--bg-vanilla-100);
margin: 0;
font-size: 16px;
font-weight: 500;
@@ -37,7 +37,7 @@
&__error-message {
margin: 0;
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
font-size: 14px;
font-weight: 400;
line-height: 20px; /* 142.857% */
@@ -49,14 +49,14 @@
align-items: center;
gap: 6px;
padding: 9px 12.5px;
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
font-size: 12px;
font-weight: 400;
line-height: 18px; /* 150% */
letter-spacing: 0.12px;
border-radius: 2px;
border: 1px solid var(--l1-border);
background: var(--l3-background);
border: 1px solid var(--bg-slate-400);
background: var(--bg-ink-300);
box-shadow: none;
}
@@ -68,7 +68,7 @@
.key-value-label {
width: fit-content;
border-color: var(--l1-border);
border-color: var(--bg-slate-400);
border-radius: 20px;
overflow: hidden;
&__key {
@@ -77,7 +77,7 @@
}
&__value {
padding-right: 10px;
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
font-size: 12px;
font-weight: 500;
line-height: 18px; /* 150% */
@@ -96,7 +96,7 @@
border-radius: 50%;
}
&-text {
color: var(--l1-foreground);
color: var(--bg-vanilla-100);
font-size: 10px;
font-weight: 500;
line-height: 18px; /* 180% */
@@ -106,11 +106,7 @@
&-line {
flex: 1;
height: 8px;
background-image: radial-gradient(
circle,
var(--l3-background) 1px,
transparent 2px
);
background-image: radial-gradient(circle, #444c63 1px, transparent 2px);
background-size: 8px 11px;
background-position: top left;
padding: 6px;
@@ -133,11 +129,12 @@
&__message-item {
position: relative;
margin-bottom: 4px;
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
font-family: Geist Mono;
font-size: 12px;
font-weight: 400;
line-height: 18px;
color: var(--bg-vanilla-400);
padding: 3px 12px;
padding-left: 26px;
}
@@ -152,7 +149,7 @@
width: 2px;
height: 4px;
border-radius: 50px;
background: var(--l1-border);
background: var(--bg-slate-400);
}
&__scroll-hint {
@@ -167,7 +164,7 @@
justify-content: center;
align-items: center;
gap: 3px;
background: var(--l1-border);
background: var(--bg-slate-200);
border-radius: 20px;
box-shadow: 0px 103px 12px 0px rgba(0, 0, 0, 0.01),
0px 66px 18px 0px rgba(0, 0, 0, 0.01), 0px 37px 22px 0px rgba(0, 0, 0, 0.03),
@@ -175,7 +172,7 @@
}
&__scroll-hint-text {
color: var(--l1-foreground);
color: var(--bg-vanilla-100);
font-size: 12px;
font-weight: 400;
@@ -183,3 +180,29 @@
letter-spacing: -0.06px;
}
}
.lightMode {
.error-content {
&__error-code {
color: var(--bg-ink-100);
}
&__error-message {
color: var(--bg-ink-400);
}
&__message-item {
color: var(--bg-ink-400);
}
&__message-badge {
&-label-text {
color: var(--bg-ink-400);
}
.key-value-label__value {
color: var(--bg-ink-400);
}
}
&__docs-button {
background: var(--bg-vanilla-100);
color: var(--bg-ink-100);
}
}
}

View File

@@ -5,8 +5,9 @@
padding: 8px 16px;
height: 48px;
box-sizing: border-box;
background: var(--l1-background);
background: rgba(11, 12, 14, 0.9);
backdrop-filter: blur(20px);
border-bottom: 1px solid var(--Slate-500, #161922);
}
.header-left {
@@ -18,3 +19,11 @@
display: flex;
align-items: center;
}
.lightMode {
.header-container {
background: var(--bg-vanilla-100);
backdrop-filter: blur(20px);
border-bottom: 1px solid var(--bg-vanilla-300);
}
}

View File

@@ -1,6 +1,6 @@
import { useCallback, useEffect, useState } from 'react';
import { useLocation } from 'react-router-dom';
import { toast } from '@signozhq/ui';
import { toast } from '@signozhq/sonner';
import { Button, Input, Radio, RadioChangeEvent, Typography } from 'antd';
import logEvent from 'api/common/logEvent';
import { useGetTenantLicense } from 'hooks/useGetTenantLicense';

View File

@@ -23,7 +23,7 @@
justify-content: space-between;
.absolute-relative-time-toggler-label {
color: var(--l1-foreground);
color: var(--bg-vanilla-100);
font-size: 13px;
font-style: normal;
font-weight: 500;
@@ -40,7 +40,7 @@
.absolute-relative-time-error {
font-size: 12px;
color: var(--accent-amber);
color: var(--bg-amber-600);
}
.share-link {
@@ -57,7 +57,7 @@
.url-share-title,
.url-share-sub-title {
color: var(--l1-foreground);
color: var(--bg-vanilla-100);
font-size: 13px;
font-style: normal;
font-weight: 500;
@@ -67,7 +67,7 @@
.url-share-sub-title {
font-size: 12px;
color: var(--l3-foreground);
color: var(--bg-vanilla-300);
font-weight: 400;
line-height: 18px;
letter-spacing: -0.06px;
@@ -86,14 +86,14 @@
flex: 1;
margin: 0px !important;
border: 1px solid var(--l1-border);
border: 1px solid var(--bg-slate-400);
&:before {
display: none;
}
.ant-radio-button-checked {
background-color: var(--l3-background);
background-color: var(--bg-slate-400);
}
}
@@ -108,15 +108,15 @@
}
.feedback-tab {
background-color: var(--danger-background);
background-color: var(--bg-sakura-500);
}
.bug-tab {
background-color: var(--warning-background);
background-color: var(--bg-amber-500);
}
.feature-tab {
background-color: var(--primary-background);
background-color: var(--bg-robin-500);
}
}
@@ -125,9 +125,9 @@
padding: 6px 16px;
border-radius: 2px;
background: var(--l2-background);
background: var(--bg-ink-400);
box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.1);
border: 1px solid var(--l1-border);
border: 1px solid var(--bg-slate-400);
margin: 0 !important;
@@ -140,13 +140,13 @@
}
&-active {
background: var(--l3-background);
color: var(--l1-foreground);
background: var(--bg-slate-400);
color: var(--bg-vanilla-100);
border-bottom: none !important;
.ant-tabs-tab-btn {
color: var(--l1-foreground);
color: var(--bg-vanilla-100);
}
}
}
@@ -181,7 +181,7 @@
.feedback-modal-content-footer-info-text {
font-size: 12px;
color: var(--l2-foreground);
color: var(--bg-vanilla-400, #c0c1c3);
text-align: center;
/* button/ small */
@@ -200,3 +200,54 @@
}
}
}
.lightMode {
.share-modal-content,
.feedback-modal-container {
.absolute-relative-time-toggler-container {
.absolute-relative-time-toggler-label {
color: var(--bg-ink-400);
}
}
.share-link {
.url-share-container {
.url-share-container-header {
.url-share-title,
.url-share-sub-title {
color: var(--bg-ink-400);
}
.url-share-sub-title {
color: var(--bg-ink-300);
}
}
}
}
}
.feedback-modal-container {
.feedback-modal-tabs {
.ant-radio-button-wrapper {
flex: 1;
margin: 0px !important;
border: 1px solid var(--bg-vanilla-300);
&:before {
display: none;
}
.ant-radio-button-checked {
background-color: var(--bg-vanilla-300);
}
}
}
.feedback-modal-content-footer {
.feedback-modal-content-footer-info-text {
color: var(--bg-slate-400);
}
}
}
}

View File

@@ -1,6 +1,6 @@
// Mock dependencies before imports
import { useLocation } from 'react-router-dom';
import { toast } from '@signozhq/ui';
import { toast } from '@signozhq/sonner';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import logEvent from 'api/common/logEvent';
@@ -19,8 +19,7 @@ jest.mock('react-router-dom', () => ({
useLocation: jest.fn(),
}));
jest.mock('@signozhq/ui', () => ({
...jest.requireActual('@signozhq/ui'),
jest.mock('@signozhq/sonner', () => ({
toast: {
success: jest.fn(),
error: jest.fn(),

View File

@@ -28,7 +28,7 @@
.infra-container-card-text {
font-size: var(--font-size-sm);
color: var(--l2-foreground);
color: var(--text-vanilla-400);
line-height: 20px;
letter-spacing: -0.07px;
width: 400px;
@@ -44,7 +44,7 @@
align-items: flex-start;
gap: 12px;
border-radius: 4px;
background: color-mix(in srgb, var(--bg-robin-200) 4%, transparent);
background: rgba(171, 189, 255, 0.04);
.ant-space {
align-items: flex-start;
@@ -58,3 +58,9 @@
margin: auto;
}
}
.lightMode {
.infra-container-card-text {
color: var(--text-ink-200);
}
}

View File

@@ -9,15 +9,15 @@
gap: 8px;
padding: 12px;
border-radius: 3px;
border: 1px solid var(--l1-border);
border: 1px solid var(--bg-slate-500);
.filter-section {
flex: 1;
.ant-select-selector {
border-radius: 2px;
border: 1px solid var(--l1-border) !important;
background-color: var(--l3-background) !important;
border: 1px solid var(--bg-slate-400) !important;
background-color: var(--bg-ink-300) !important;
input {
font-size: 12px;
@@ -37,7 +37,7 @@
.ant-table {
border-radius: 3px;
border: 1px solid var(--l1-border);
border: 1px solid var(--bg-slate-500);
.ant-table-thead > tr > th {
padding: 12px;
@@ -45,10 +45,10 @@
font-size: 12px;
line-height: 18px;
background: color-mix(in srgb, var(--bg-robin-200) 1%, transparent);
background: rgba(171, 189, 255, 0.01);
border-bottom: none;
color: var(--l2-foreground);
color: var(--Vanilla-400, #c0c1c3);
font-family: Inter;
font-size: 11px;
font-style: normal;
@@ -63,23 +63,23 @@
}
.ant-table-thead > tr > th:has(.hostname-column-header) {
background: var(--l2-background);
background: var(--bg-ink-400);
}
.ant-table-cell {
padding: 12px;
font-size: 13px;
line-height: 20px;
color: var(--l1-foreground);
background: color-mix(in srgb, var(--bg-robin-200) 1%, transparent);
color: var(--bg-vanilla-100);
background: rgba(171, 189, 255, 0.01);
}
.ant-table-cell:has(.hostname-column-value) {
background: var(--l2-background);
background: var(--bg-ink-400);
}
.hostname-column-value {
color: var(--l1-foreground);
color: var(--bg-vanilla-100);
font-family: 'Geist Mono';
font-style: normal;
font-weight: 600;
@@ -105,7 +105,7 @@
}
.ant-table-tbody > tr:hover > td {
background: color-mix(in srgb, var(--l1-foreground) 4%, transparent);
background: rgba(255, 255, 255, 0.04);
}
.ant-table-cell:first-child {
@@ -143,3 +143,51 @@
}
}
}
.lightMode {
.host-metric-traces-header {
.filter-section {
border-top: 1px solid var(--bg-vanilla-300);
border-bottom: 1px solid var(--bg-vanilla-300);
.ant-select-selector {
border-color: var(--bg-vanilla-300) !important;
background-color: var(--bg-vanilla-100) !important;
color: var(--bg-ink-200);
}
}
}
.host-metric-traces-table {
.ant-table {
border-radius: 3px;
border: 1px solid var(--bg-vanilla-300);
.ant-table-thead > tr > th {
background: var(--bg-vanilla-100);
color: var(--text-ink-300);
}
.ant-table-thead > tr > th:has(.hostname-column-header) {
background: var(--bg-vanilla-100);
}
.ant-table-cell {
background: var(--bg-vanilla-100);
color: var(--bg-ink-500);
}
.ant-table-cell:has(.hostname-column-value) {
background: var(--bg-vanilla-100);
}
.hostname-column-value {
color: var(--bg-ink-300);
}
.ant-table-tbody > tr:hover > td {
background: rgba(0, 0, 0, 0.04);
}
}
}
}

View File

@@ -1,6 +1,6 @@
.host-detail-drawer {
border-left: 1px solid var(--l1-border);
background: var(--l2-background);
border-left: 1px solid var(--bg-slate-500);
background: var(--bg-ink-400);
box-shadow: -4px 10px 16px 2px rgba(0, 0, 0, 0.2);
.ant-drawer-header {
@@ -9,8 +9,8 @@
align-items: stretch;
border-bottom: 1px solid var(--l1-border);
background: var(--l2-background);
border-bottom: 1px solid var(--bg-slate-500);
background: var(--bg-ink-400);
}
.ant-drawer-close {
@@ -24,7 +24,7 @@
}
.title {
color: var(--l2-foreground);
color: var(--text-vanilla-400);
font-family: 'Geist Mono';
font-size: 14px;
font-style: normal;
@@ -38,8 +38,8 @@
align-items: center;
justify-content: center;
padding-top: var(--padding-1);
border: 1px solid var(--l1-border);
background: var(--l3-background);
border: 1px solid var(--bg-slate-400);
background: var(--bg-ink-300);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
}
@@ -58,7 +58,7 @@
}
.host-details-metadata-label {
color: var(--l2-foreground);
color: var(--text-vanilla-400);
font-family: Inter;
font-size: 11px;
font-style: normal;
@@ -97,7 +97,7 @@
.ant-card {
&.ant-card-bordered {
border: 1px solid var(--l1-border) !important;
border: 1px solid var(--bg-slate-500) !important;
}
}
}
@@ -111,8 +111,8 @@
.action-btn {
border-radius: 2px;
border: 1px solid var(--l1-border);
background: var(--l3-background);
border: 1px solid var(--bg-slate-400);
background: var(--bg-ink-300);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
@@ -127,7 +127,7 @@
align-items: center;
.views-tabs {
color: var(--l2-foreground);
color: var(--text-vanilla-400);
.view-title {
display: flex;
@@ -140,22 +140,22 @@
}
.tab {
border: 1px solid var(--l1-border);
border: 1px solid var(--bg-slate-400);
width: 114px;
}
.tab::before {
background: var(--l1-border);
background: var(--bg-slate-400);
}
.selected_view {
background: var(--l3-background);
color: var(--l1-foreground);
border: 1px solid var(--l1-border);
background: var(--bg-slate-300);
color: var(--text-vanilla-100);
border: 1px solid var(--bg-slate-400);
}
.selected_view::before {
background: var(--l1-border);
background: var(--bg-slate-400);
}
}
@@ -164,8 +164,8 @@
height: 30px;
border-radius: 2px;
border: 1px solid var(--l1-border);
background: var(--l3-background);
border: 1px solid var(--bg-slate-400);
background: var(--bg-ink-300);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
}
}
@@ -174,3 +174,60 @@
padding: 0px;
}
}
.lightMode {
.ant-drawer-header {
border-bottom: 1px solid var(--bg-vanilla-400);
background: var(--bg-vanilla-100);
}
.host-detail-drawer {
.title {
color: var(--text-ink-300);
}
.host-detail-drawer__host {
.ant-typography {
color: var(--text-ink-300);
background: transparent;
}
}
.radio-button {
border: 1px solid var(--bg-vanilla-400);
background: var(--bg-vanilla-100);
color: var(--text-ink-300);
}
.views-tabs {
.tab {
background: var(--bg-vanilla-100);
}
.selected_view {
background: var(--bg-vanilla-300);
border: 1px solid var(--bg-slate-300);
color: var(--text-ink-400);
}
.selected_view::before {
background: var(--bg-vanilla-300);
border-left: 1px solid var(--bg-slate-300);
}
}
.compass-button {
border: 1px solid var(--bg-vanilla-300);
background: var(--bg-vanilla-100);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
}
.tabs-and-search {
.action-btn {
border: 1px solid var(--bg-vanilla-400);
background: var(--bg-vanilla-100);
color: var(--text-ink-300);
}
}
}
}

View File

@@ -6,7 +6,8 @@
.ant-select-selector {
border-radius: 2px;
border: 1px solid var(--l1-border) !important;
border: 1px solid var(--bg-slate-400) !important;
background-color: var(--bg-ink-300) !important;
input {
font-size: 12px;
@@ -25,7 +26,7 @@
padding: 12px;
border-radius: 3px;
border: 1px solid var(--l1-border);
border: 1px solid var(--bg-slate-500);
}
.host-metrics-logs {
@@ -44,11 +45,11 @@
}
&::-webkit-scrollbar-thumb {
background: var(--l1-border);
background: var(--bg-slate-300);
}
&::-webkit-scrollbar-thumb:hover {
background: var(--l1-border);
background: var(--bg-slate-200);
}
.ant-row {
@@ -117,3 +118,16 @@
gap: 16px;
}
}
.lightMode {
.filter-section {
border-top: 1px solid var(--bg-vanilla-300);
border-bottom: 1px solid var(--bg-vanilla-300);
.ant-select-selector {
border-color: var(--bg-vanilla-300) !important;
background-color: var(--bg-vanilla-100) !important;
color: var(--bg-ink-200);
}
}
}

View File

@@ -17,7 +17,7 @@
gap: 8px;
padding: 12px;
border-radius: 3px;
border: 1px solid var(--l1-border);
border: 1px solid var(--bg-slate-500);
}
.host-metrics-card {
@@ -25,7 +25,7 @@
height: 300px;
padding: 10px;
border: 1px solid var(--l1-border);
border: 1px solid var(--bg-slate-500);
.ant-card-body {
padding: 0;

View File

@@ -28,7 +28,7 @@
.infra-container-card-text {
font-size: var(--font-size-sm);
color: var(--l2-foreground);
color: var(--text-vanilla-400);
line-height: 20px;
letter-spacing: -0.07px;
width: 400px;
@@ -44,7 +44,7 @@
align-items: flex-start;
gap: 12px;
border-radius: 4px;
background: color-mix(in srgb, var(--bg-robin-200) 4%, transparent);
background: rgba(171, 189, 255, 0.04);
.ant-space {
align-items: flex-start;
@@ -58,3 +58,9 @@
margin: auto;
}
}
.lightMode {
.infra-container-card-text {
color: var(--text-ink-200);
}
}

View File

@@ -1,4 +1,4 @@
import { Badge } from '@signozhq/ui';
import { Badge } from '@signozhq/badge';
type BadgeColor =
| 'vanilla'

View File

@@ -5,7 +5,7 @@
border-radius: 2px 0px 0px 2px;
.label {
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
font-size: 12px;
font-style: normal;
font-weight: 500;
@@ -21,8 +21,8 @@
padding: 0px 8px;
border-radius: 2px 0px 0px 2px;
border: 1px solid var(--l1-border);
background: var(--l3-background);
border: 1px solid var(--bg-slate-400);
background: var(--bg-ink-300);
display: flex;
justify-content: flex-start;
@@ -36,7 +36,7 @@
font-family: 'Space Mono', monospace !important;
border-radius: 2px 0px 0px 2px;
border: 1px solid var(--l1-border);
border: 1px solid var(--bg-slate-400);
border-right: none;
border-left: none;
@@ -47,7 +47,7 @@
font-size: 12px !important;
line-height: 27px;
&::placeholder {
color: var(--l2-foreground) !important;
color: var(--bg-vanilla-400) !important;
font-size: 12px !important;
}
&[type='number']::-webkit-inner-spin-button,
@@ -61,8 +61,8 @@
.close-btn {
border-radius: 0px 2px 2px 0px;
border: 1px solid var(--l1-border);
background: var(--l3-background);
border: 1px solid var(--bg-slate-400);
background: var(--bg-ink-300);
height: 38px;
width: 38px;
}
@@ -70,8 +70,8 @@
&.labelAfter {
.input {
border-radius: 0px 2px 2px 0px;
border: 1px solid var(--l1-border);
background: var(--l3-background);
border: 1px solid var(--bg-slate-400);
background: var(--bg-ink-300);
border-top-right-radius: 0px;
border-bottom-right-radius: 0px;
}
@@ -83,3 +83,31 @@
}
}
}
.lightMode {
.input-with-label {
.label {
color: var(--bg-ink-500) !important;
border: 1px solid var(--bg-vanilla-300) !important;
background: var(--bg-vanilla-100) !important;
}
.input {
border: 1px solid var(--bg-vanilla-300) !important;
background: var(--bg-vanilla-100) !important;
}
.close-btn {
border: 1px solid var(--bg-vanilla-300) !important;
background: var(--bg-vanilla-100) !important;
}
&.labelAfter {
.input {
border: 1px solid var(--bg-vanilla-300) !important;
background: var(--bg-vanilla-100) !important;
}
}
}
}

View File

@@ -19,7 +19,7 @@
font-weight: var(--label-base-400-font-weight);
line-height: var(--label-base-400-line-height);
letter-spacing: -0.065px;
color: var(--l1-foreground);
color: var(--bg-base-white);
margin: 0;
}
@@ -116,7 +116,7 @@
height: 32px;
color: var(--l1-foreground);
background-color: var(--l2-background);
border-color: var(--l1-border);
border-color: var(--border);
font-size: var(--paragraph-base-400-font-size);
&::placeholder {
@@ -149,7 +149,7 @@
.ant-select-selection-item {
font-size: var(--paragraph-base-400-font-size);
letter-spacing: -0.07px;
color: var(--l1-foreground);
color: var(--bg-base-white);
line-height: 32px;
}
}
@@ -181,7 +181,7 @@
box-shadow: none;
&:hover {
background: color-mix(in srgb, var(--bg-cherry-500) 10%, transparent);
background: rgba(229, 72, 77, 0.1);
opacity: 0.9;
}
}
@@ -196,8 +196,8 @@
}
.invite-team-members-error-callout {
background: color-mix(in srgb, var(--bg-cherry-500) 10%, transparent);
border: 1px solid color-mix(in srgb, var(--bg-cherry-500) 20%, transparent);
background: rgba(229, 72, 77, 0.1);
border: 1px solid rgba(229, 72, 77, 0.2);
border-radius: 4px;
animation: horizontal-shaking 300ms ease-out;
}
@@ -246,3 +246,19 @@
color: var(--l1-foreground);
}
}
.lightMode {
.invite-members-modal {
[data-slot='dialog-title'] {
color: var(--bg-base-black);
}
}
.team-member-role-select {
.ant-select-selector {
.ant-select-selection-item {
color: var(--bg-base-black);
}
}
}
}

View File

@@ -5,7 +5,7 @@ import { Style } from '@signozhq/design-tokens';
import { DialogFooter, DialogWrapper } from '@signozhq/dialog';
import { ChevronDown, CircleAlert, Plus, Trash2, X } from '@signozhq/icons';
import { Input } from '@signozhq/input';
import { toast } from '@signozhq/ui';
import { toast } from '@signozhq/sonner';
import { Select } from 'antd';
import inviteUsers from 'api/v1/invite/bulk/create';
import sendInvite from 'api/v1/invite/create';

View File

@@ -14,8 +14,7 @@ const makeApiError = (message: string, code = StatusCodes.CONFLICT): APIError =>
jest.mock('api/v1/invite/create');
jest.mock('api/v1/invite/bulk/create');
jest.mock('@signozhq/ui', () => ({
...jest.requireActual('@signozhq/ui'),
jest.mock('@signozhq/sonner', () => ({
toast: {
success: jest.fn(),
error: jest.fn(),

View File

@@ -8,6 +8,18 @@
}
}
.lightMode {
.facing-issue-button {
color: var(--bg-vanilla-500);
border-color: var(--bg-vanilla-300);
> .ant-btn:hover {
color: var(--bg-vanilla-500) !important;
border-color: var(--bg-vanilla-300) !important;
}
}
}
.tooltip-overlay {
text-wrap: nowrap;
.ant-tooltip-inner {

View File

@@ -1,6 +1,6 @@
.log-detail-drawer {
border-left: 1px solid var(--l1-border);
background: var(--l2-background);
border-left: 1px solid var(--bg-slate-500);
background: var(--bg-ink-400);
box-shadow: -4px 10px 16px 2px rgba(0, 0, 0, 0.2);
.log-detail-drawer__title {
@@ -30,8 +30,8 @@
align-items: stretch;
border-bottom: 1px solid var(--l1-border);
background: var(--l2-background);
border-bottom: 1px solid var(--bg-slate-500);
background: var(--bg-ink-400);
}
.ant-drawer-close {
@@ -46,7 +46,7 @@
}
.title {
color: var(--l2-foreground);
color: var(--text-vanilla-400);
font-family: Inter;
font-size: var(--font-size-sm);
font-style: normal;
@@ -60,8 +60,8 @@
align-items: center;
justify-content: center;
padding-top: var(--padding-1);
border: 1px solid var(--l1-border);
background: var(--l3-background);
border: 1px solid var(--bg-slate-400);
background: var(--bg-ink-300);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
}
@@ -91,31 +91,31 @@
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
color: var(--l2-foreground);
color: var(--text-vanilla-400);
opacity: 0.6;
}
.log-type-indicator {
height: 24px;
border: 2px solid var(--l1-border);
border: 2px solid var(--bg-slate-400);
border-radius: 5px;
margin-left: 0;
&.INFO {
border-color: var(--l1-border);
border-color: #1d212d;
}
&.WARNING {
border-color: var(--bg-amber-400);
border-color: #ffcd56;
}
&.ERROR {
border-color: var(--bg-cherry-500);
border-color: #e5484d;
}
}
.log-overflow-shadow {
background: linear-gradient(270deg, var(--card) 10.4%, transparent 100%);
background: linear-gradient(270deg, #121317 10.4%, rgba(18, 19, 23, 0) 100%);
width: 196px;
position: absolute;
@@ -131,8 +131,8 @@
.action-btn {
border-radius: 2px;
border: 1px solid var(--l1-border);
background: var(--l3-background);
border: 1px solid var(--bg-slate-400);
background: var(--bg-ink-300);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
@@ -146,7 +146,7 @@
}
.views-tabs {
color: var(--l2-foreground);
color: var(--text-vanilla-400);
.view-title {
display: flex;
@@ -159,28 +159,28 @@
}
.tab {
border: 1px solid var(--l1-border);
border: 1px solid var(--bg-slate-400);
width: 114px;
}
.tab::before {
background: var(--l1-border);
background: var(--bg-slate-400);
}
.selected_view {
background: var(--l3-background);
color: var(--l1-foreground);
border: 1px solid var(--l1-border);
background: var(--bg-slate-300);
color: var(--text-vanilla-100);
border: 1px solid var(--bg-slate-400);
}
.selected_view::before {
background: var(--l1-border);
background: var(--bg-slate-400);
}
}
.search-input {
margin-top: var(--margin-2);
border: 1px solid var(--l1-border);
border: 1px solid var(--bg-slate-400);
height: 46px;
padding: var(--padding-1) var(--padding-2);
box-shadow: none;
@@ -197,8 +197,8 @@
right: 0;
padding: 8px 16px;
text-align: left;
color: var(--l3-foreground);
background: var(--l2-background);
color: var(--text-vanilla-200);
background: var(--bg-ink-400);
z-index: 10;
.log-detail-drawer__footer-hint-content {
@@ -210,7 +210,7 @@
.log-detail-drawer__footer-hint-icon {
display: inline;
vertical-align: middle;
color: var(--l3-foreground);
color: var(--text-vanilla-200);
}
.log-detail-drawer__footer-hint-text {
@@ -232,9 +232,9 @@
min-width: 28px;
height: 28px;
border-radius: 4px;
background: var(--l2-background);
color: var(--l2-foreground);
border: 1px solid var(--l1-border);
background: var(--bg-ink-400);
color: var(--text-vanilla-400);
border: 1px solid var(--bg-ink-300);
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.08);
display: flex;
align-items: center;
@@ -244,24 +244,154 @@
.log-arrow-btn-up,
.log-arrow-btn-down {
background: var(--l2-background);
background: var(--bg-ink-400);
}
.log-arrow-btn:active,
.log-arrow-btn:focus {
background: var(--l3-background);
color: var(--l1-foreground);
background: var(--bg-ink-300);
color: var(--text-vanilla-100);
}
.log-arrow-btn[disabled] {
opacity: 0.5;
cursor: not-allowed;
background: var(--l1-background);
color: var(--l3-foreground);
background: var(--bg-ink-500);
color: var(--text-vanilla-200);
.log-arrow-btn:hover:not([disabled]) {
background: var(--l3-background);
color: var(--l1-foreground);
background: var(--bg-ink-300);
color: var(--text-vanilla-100);
}
}
}
.lightMode {
.log-arrows {
background: var(--bg-vanilla-100);
box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.04);
}
.log-arrow-btn {
background: var(--bg-vanilla-100);
color: var(--text-ink-400);
border: 1px solid var(--bg-vanilla-300);
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.04);
}
.log-arrow-btn-up,
.log-arrow-btn-down {
background: var(--bg-vanilla-100);
}
.log-arrow-btn:active,
.log-arrow-btn:focus {
background: var(--bg-vanilla-200);
color: var(--text-ink-500);
}
.log-arrow-btn:hover:not([disabled]) {
background: var(--bg-vanilla-200);
color: var(--text-ink-500);
}
.log-arrow-btn[disabled] {
background: var(--bg-vanilla-100);
color: var(--text-ink-200);
}
.ant-drawer-header {
border-bottom: 1px solid var(--bg-vanilla-400);
background: var(--bg-vanilla-100);
}
.log-detail-drawer {
.title {
color: var(--text-ink-300);
}
.log-detail-drawer__log {
.log-overflow-shadow {
background: linear-gradient(
270deg,
var(--bg-vanilla-100) 10.4%,
rgba(255, 255, 255, 0) 100%
);
}
.log-type-indicator {
border: 2px solid var(--bg-vanilla-400);
}
.ant-typography {
color: var(--text-ink-300);
background: transparent;
}
}
.radio-button {
border: 1px solid var(--bg-vanilla-400);
background: var(--bg-vanilla-100);
color: var(--text-ink-300);
}
.views-tabs {
.tab {
background: var(--bg-vanilla-100);
}
.selected_view {
background: var(--bg-vanilla-300);
border: 1px solid var(--bg-slate-300);
color: var(--text-ink-400);
}
.selected_view::before {
background: var(--bg-vanilla-300);
border-left: 1px solid var(--bg-slate-300);
}
}
.tabs-and-search {
.action-btn {
border: 1px solid var(--bg-vanilla-400);
background: var(--bg-vanilla-100);
color: var(--text-ink-300);
}
}
.search-input {
border: 1px solid var(--bg-vanilla-200);
background: var(--bg-vanilla-100);
color: var(--text-ink-300);
}
}
.log-detail-drawer__footer-hint {
position: sticky;
bottom: 0;
left: 0;
right: 0;
padding: 8px 16px;
text-align: left;
color: var(--text-vanilla-700);
background: var(--bg-vanilla-100);
z-index: 10;
.log-detail-drawer__footer-hint-content {
display: flex;
align-items: center;
gap: 4px;
}
.log-detail-drawer__footer-hint-icon {
display: inline;
vertical-align: middle;
color: var(--text-vanilla-700);
}
.log-detail-drawer__footer-hint-text {
font-size: 13px;
margin: 0;
}
}
}

View File

@@ -1,6 +1,6 @@
.query-builder-search-wrapper {
margin-top: 10px;
border: 1px solid var(--l1-border);
border: 1px solid var(--bg-slate-400);
border-bottom: none;
.ant-select-selector {

View File

@@ -6,7 +6,7 @@
}
.log-field-key,
.log-field-key-colon {
color: var(--l2-foreground);
color: var(--text-vanilla-400, #c0c1c3);
font-size: 14px;
font-style: normal;
font-weight: 400;
@@ -41,7 +41,7 @@
flex-shrink: 0;
}
.log-value {
color: var(--l2-foreground);
color: var(--text-vanilla-400, #c0c1c3);
font-size: 14px;
font-style: normal;
font-weight: 400;
@@ -104,7 +104,7 @@
.selected-log-value {
color: var(--bg-sienna-500);
border-radius: 2px;
background: color-mix(in srgb, var(--bg-sienna-500) 8%, transparent);
background: rgba(173, 127, 88, 0.08);
padding: 0px 2px;
margin-left: 7px;
font-weight: 400;
@@ -154,8 +154,8 @@
height: 32px;
width: 68px;
border-radius: 2px;
border: 1px solid var(--l1-border);
background: var(--l2-background);
border: 1px solid var(--bg-slate-400, #1d212d);
background: var(--bg-ink-400, #121317);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
.context-btn {
@@ -163,7 +163,7 @@
}
.copy-link-btn {
width: 50% !important;
border-left: 1px solid var(--l1-border) !important;
border-left: 1px solid var(--bg-slate-400, #1d212d) !important;
}
.ant-btn-default {
@@ -172,6 +172,16 @@
}
}
.lightMode {
.log-field-key,
.log-field-key-colon {
color: var(--text-slate-400);
}
.log-value {
color: var(--text-slate-400);
}
}
.dark {
.log-field-key,
.log-field-key-colon {

View File

@@ -6,8 +6,8 @@
right: 0;
cursor: pointer;
border-radius: 2px;
border: 1px solid var(--l1-border);
background: var(--l2-background);
border: 1px solid var(--bg-slate-400);
background: var(--bg-ink-400);
.ant-btn-default {
border: none;
@@ -18,13 +18,13 @@
display: flex;
&.active-tab {
background-color: var(--l1-border);
background-color: var(--bg-slate-400);
}
}
.copy-log-btn {
border-left: 1px solid var(--l1-border);
border-color: var(--l1-border) !important;
border-left: 1px solid var(--bg-slate-400);
border-color: var(--bg-slate-400) !important;
}
}
@@ -38,3 +38,15 @@
margin: 0;
z-index: 5;
}
.lightMode {
.log-line-action-buttons {
border: 1px solid var(--bg-vanilla-400);
background: var(--bg-vanilla-400);
.copy-log-btn {
border-left: 1px solid var(--bg-vanilla-400);
border-color: var(--bg-vanilla-400) !important;
}
}
}

View File

@@ -60,7 +60,7 @@
background-color: var(--bg-robin-600);
}
&.severity-info-1 {
background-color: var(--primary-background);
background-color: var(--bg-robin-500);
}
&.severity-info-2 {
background-color: var(--bg-robin-400);

View File

@@ -1,5 +1,5 @@
.text {
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
font-size: 14px;
font-style: normal;
font-weight: 400;
@@ -38,6 +38,12 @@
}
}
.lightMode {
.text {
color: var(--bg-slate-400);
}
}
.paragraph {
margin: 0;
padding: 0px !important;

View File

@@ -1,11 +1,11 @@
.format-options-popover {
.ant-popover-inner {
border-radius: 4px;
border: 1px solid var(--l1-border);
border: 1px solid var(--bg-slate-400);
background: linear-gradient(
139deg,
var(--l2-background) 0%,
var(--l1-background) 98.68%
var(--bg-ink-400) 0%,
var(--bg-ink-500) 98.68%
);
box-shadow: 4px 10px 16px 2px rgba(0, 0, 0, 0.2);
backdrop-filter: blur(20px);
@@ -35,7 +35,7 @@
}
.text {
color: var(--muted-foreground);
color: var(--bg-slate-50);
font-family: Inter;
font-size: 11px;
font-style: normal;
@@ -65,7 +65,7 @@
flex-shrink: 0;
}
.text {
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
font-family: Inter;
font-size: 13px;
font-style: normal;
@@ -76,7 +76,7 @@
}
.text:hover {
color: var(--l2-foreground);
color: var(--bg-vanilla-300);
}
}
@@ -93,7 +93,7 @@
gap: 12px;
.title {
color: var(--muted-foreground);
color: var(--bg-slate-50);
font-family: Inter;
font-size: 11px;
font-style: normal;
@@ -111,7 +111,7 @@
align-items: center;
border: none !important;
.font-value {
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
font-family: Inter;
font-size: 13px;
font-style: normal;
@@ -139,7 +139,7 @@
line-height: 18px;
letter-spacing: 0.08em;
text-align: left;
color: var(--muted-foreground);
color: var(--bg-slate-50);
}
.menu-items {
@@ -159,7 +159,7 @@
.item-label {
display: flex;
color: var(--l2-foreground);
color: var(--bg-vanilla-400, #c0c1c3);
justify-content: space-between;
align-items: center;
}
@@ -170,14 +170,14 @@
.horizontal-line {
height: 1px;
background: var(--l3-background);
background: #1d212d;
}
.max-lines-per-row {
padding: 12px;
.title {
color: var(--muted-foreground);
color: var(--bg-slate-50);
font-family: Inter;
font-size: 11px;
font-style: normal;
@@ -193,7 +193,7 @@
align-items: center;
.lucide {
color: var(--l2-foreground);
color: var(--bg-vanilla-400, #c0c1c3);
cursor: pointer;
}
}
@@ -210,8 +210,8 @@
width: auto;
border-right: none;
border-left: none;
border-top: 1px solid var(--l1-border);
border-bottom: 1px solid var(--l1-border);
border-top: 1px solid var(--bg-slate-400);
border-bottom: 1px solid var(--bg-slate-400);
text-align: center;
height: 26px;
border-radius: 0;
@@ -250,7 +250,7 @@
height: 26px;
border-radius: 0px 1px 1px 0px;
background: var(--l3-background);
background: var(--bg-ink-300, #16181d);
}
}
}
@@ -273,7 +273,7 @@
display: flex;
gap: 4px;
align-items: center;
color: var(--muted-foreground);
color: var(--bg-slate-50);
text-transform: uppercase;
font-size: 11px;
font-weight: 500;
@@ -302,7 +302,7 @@
.column-name {
padding: 4px 8px;
border-radius: 1px;
color: var(--l2-foreground);
color: var(--bg-vanilla-400, #c0c1c3);
font-family: Inter;
font-size: 13px;
font-style: normal;
@@ -311,7 +311,7 @@
letter-spacing: -0.07px;
&.selected {
background-color: var(--l3-background);
background-color: var(--bg-ink-200);
cursor: pointer;
}
}
@@ -330,7 +330,7 @@
}
.title {
color: var(--muted-foreground);
color: var(--bg-slate-50);
font-family: Inter;
font-size: 11px;
font-style: normal;
@@ -346,14 +346,14 @@
align-items: center;
.lucide {
color: var(--l2-foreground);
color: var(--bg-vanilla-400, #c0c1c3);
cursor: pointer;
}
}
.horizontal-line {
height: 1px;
background: var(--l3-background);
background: #1d212d;
}
.loading-container {
@@ -371,7 +371,7 @@
margin-top: 12px;
.column-name {
color: var(--l2-foreground);
color: var(--bg-vanilla-400, #c0c1c3);
font-family: Inter;
font-size: 13px;
font-style: normal;
@@ -387,18 +387,18 @@
cursor: pointer;
&.default-column {
color: var(--l2-foreground);
color: var(--bg-vanilla-400, #c0c1c3);
cursor: not-allowed;
}
&.no-columns-selected {
color: var(--l3-foreground);
color: var(--bg-slate-100);
font-size: 12px;
cursor: not-allowed;
}
&.add-new-column-btn {
color: var(--l2-foreground);
color: var(--bg-vanilla-400, #c0c1c3);
cursor: pointer;
}
@@ -447,7 +447,7 @@
.column-divider {
margin: 12px 0;
border-top: 2px solid var(--l1-border);
border-top: 2px solid var(--bg-slate-400);
}
}
}
@@ -458,7 +458,7 @@
.item {
.item-label {
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
}
}
}
@@ -468,11 +468,11 @@
margin-left: -5%;
border-radius: 4px;
border: 1px solid var(--l1-border);
border: 1px solid var(--bg-slate-400);
background: linear-gradient(
139deg,
color-mix(in srgb, var(--card) 80%, transparent) 0%,
color-mix(in srgb, var(--card) 90%, transparent) 98.68%
rgba(18, 19, 23, 0.8) 0%,
rgba(18, 19, 23, 0.9) 98.68%
);
box-shadow: 4px 10px 16px 2px rgba(0, 0, 0, 0.2);
@@ -490,7 +490,7 @@
.lightMode {
.format-options-popover {
.ant-popover-inner {
border: 1px solid var(--l1-border);
border: 1px solid var(--bg-vanilla-300);
background: linear-gradient(
139deg,
rgba(255, 255, 255, 0.8) 0%,
@@ -502,18 +502,18 @@
.font-size-dropdown {
.back-btn {
.text {
color: var(--l2-background);
color: var(--bg-ink-400);
}
}
.content {
.option-btn {
.text {
color: var(--l2-background);
color: var(--bg-ink-400);
}
.text:hover {
color: var(--l3-background);
color: var(--bg-ink-300);
}
}
}
@@ -522,105 +522,105 @@
.add-new-column-container {
.add-new-column-header {
.title {
color: var(--l2-foreground);
color: var(--bg-ink-100);
}
}
.add-new-column-content {
.column-format-new-options {
.column-name {
color: var(--l2-background);
color: var(--bg-ink-400);
&.selected {
background-color: var(--l3-background);
background-color: var(--bg-vanilla-400);
}
}
}
.loading-container {
color: var(--l2-background);
color: var(--bg-ink-400);
}
}
}
.font-size-container {
.title {
color: var(--l2-foreground);
color: var(--bg-ink-100);
}
.value {
.font-value {
color: var(--l2-background);
color: var(--bg-ink-400);
}
}
}
.horizontal-line {
background: var(--l3-background);
background: var(--bg-vanilla-300);
}
.item-content {
.column-divider {
border-top: 2px solid var(--l1-border);
border-top: 2px solid var(--bg-vanilla-300);
}
}
.max-lines-per-row {
.title {
color: var(--l2-foreground);
color: var(--bg-ink-200);
.lucide {
color: var(--l1-foreground);
color: var(--bg-ink-300);
}
}
.max-lines-per-row-input {
border: 1px solid var(--l1-border);
border: 1px solid var(--bg-vanilla-300);
.periscope-btn {
background: var(--l3-background);
background: var(--bg-vanilla-300);
}
}
}
.menu-container {
.title {
color: var(--l2-foreground);
color: var(--bg-ink-200);
}
.item {
.item-label {
color: var(--l2-background);
color: var(--bg-ink-400);
}
}
}
.selected-item-content-container {
.title {
color: var(--l2-foreground);
color: var(--bg-ink-200);
.lucide {
color: var(--l1-foreground);
color: var(--bg-ink-300);
}
}
.horizontal-line {
background: var(--l3-background);
background: var(--bg-vanilla-300);
}
.item-content {
.max-lines-per-row-input {
border: 1px solid var(--l1-border);
border: 1px solid var(--bg-vanilla-300);
.periscope-btn {
background: var(--l3-background);
background: var(--bg-vanilla-300);
}
}
.column-format,
.column-format-new-options {
.column-name {
color: var(--l1-foreground);
color: var(--bg-ink-300);
}
}
}
@@ -632,13 +632,13 @@
.item {
.item-label {
color: var(--l1-foreground);
color: var(--bg-ink-300);
}
}
}
.selected-item-content-container {
border: 1px solid var(--l1-border);
border: 1px solid var(--bg-vanilla-300);
background: linear-gradient(
139deg,
rgba(255, 255, 255, 0.8) 0%,

View File

@@ -1,8 +1,8 @@
.code-snippet-container {
position: relative;
// background-color: rgb(43, 43, 43);
background-color: var(--bg-ink-400);
border-color: var(--bg-ink-400);
background-color: #111a2c;
border-color: #111a2c;
}
.code-copy-btn {
@@ -16,21 +16,21 @@
button {
cursor: pointer;
background-color: color-mix(in srgb, var(--bg-ink-300) 70%, transparent);
color: var(--l1-foreground);
background-color: rgba($color: #1d1d1d, $alpha: 0.7);
color: white;
border: none;
padding: 8px;
border-radius: 3px;
transition: all 0.1s;
&:hover {
background-color: var(--bg-ink-300);
background-color: rgba($color: #1d1d1d, $alpha: 1);
}
}
&.copied {
button {
background-color: var(--bg-forest-500);
background-color: rgba($color: #52c41a, $alpha: 1);
}
}
}

View File

@@ -54,7 +54,7 @@
.ant-table-column-sorter-up.active,
.ant-table-column-sorter-down.active {
color: var(--l1-foreground);
color: var(--bg-base-white);
opacity: 1;
}
}
@@ -69,14 +69,10 @@
}
> tr.members-table-row--tinted > td {
background: color-mix(in srgb, var(--bg-robin-200) 2%, transparent);
background: rgba(171, 189, 255, 0.02);
}
> tr:hover > td {
background: color-mix(
in srgb,
var(--bg-robin-200) 4%,
transparent
) !important;
background: rgba(171, 189, 255, 0.04) !important;
}
}
@@ -170,7 +166,7 @@
strong {
font-weight: var(--font-weight-medium);
color: var(--l1-foreground);
color: var(--bg-base-white);
}
}
}
@@ -209,4 +205,12 @@
}
}
}
.members-empty-state {
&__text {
strong {
color: var(--bg-base-black);
}
}
}
}

View File

@@ -1,5 +1,5 @@
import type React from 'react';
import { Badge } from '@signozhq/ui';
import { Badge } from '@signozhq/badge';
import { Table, Tooltip } from 'antd';
import type { ColumnsType, SorterResult } from 'antd/es/table/interface';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';

View File

@@ -1,8 +1,8 @@
.mq-health-check-modal {
.ant-modal-content {
border-radius: 4px;
border: 1px solid var(--l1-border);
background: var(--l2-background);
border: 1px solid var(--bg-slate-500);
background: var(--bg-ink-400);
box-shadow: 0px -4px 16px 2px rgba(0, 0, 0, 0.2);
.ant-modal-close {
@@ -10,13 +10,13 @@
}
.ant-modal-header {
border-bottom: 1px solid var(--l1-border);
background: var(--l2-background);
border-bottom: 1px solid var(--bg-slate-500);
background: var(--bg-ink-400);
margin-bottom: 16px;
padding-bottom: 4px;
.ant-modal-title {
color: var(--l1-foreground);
color: var(--bg-vanilla-100);
font-family: Inter;
font-size: 13px;
font-style: normal;
@@ -31,7 +31,7 @@
flex-direction: column;
gap: 8px;
padding: 8px;
background: var(--l3-background);
background: var(--bg-ink-300);
.attribute-select {
align-items: center;
@@ -47,8 +47,8 @@
gap: 4px;
border-radius: 2px;
border: 1px solid var(--l1-border);
background: var(--l3-background);
border: 1px solid var(--bg-slate-400);
background: var(--bg-ink-300);
}
}
@@ -57,7 +57,7 @@
}
.tree-text {
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
font-family: 'Geist Mono';
font-size: 12px;
font-style: normal;
@@ -101,7 +101,7 @@
.success-attribute-icon {
width: 44px;
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
display: flex;
> svg {
@@ -128,7 +128,7 @@
align-items: center;
height: 100%;
padding: 8px;
background: var(--l3-background);
background: var(--bg-ink-300);
height: 156px;
}
}
@@ -147,10 +147,10 @@
border-radius: 2px;
border: none;
box-shadow: none;
background: var(--l3-background);
background: var(--bg-slate-500);
&.missing-config-btn {
background: color-mix(in srgb, var(--bg-amber-500) 10%, transparent);
background: rgba(255, 205, 86, 0.1);
color: var(--bg-amber-400);
&:hover {
@@ -162,14 +162,68 @@
display: flex;
align-items: center;
margin-right: 8px;
border-right: 1px solid
color-mix(in srgb, var(--bg-amber-400) 10%, transparent);
border-right: 1px solid rgba(255, 215, 120, 0.1);
padding-right: 8px;
}
}
.lightMode {
.mq-health-check-modal {
.ant-modal-content {
border: 1px solid var(--bg-vanilla-400);
background: var(--bg-vanilla-200);
.ant-modal-header {
border-bottom: 1px solid var(--bg-vanilla-400);
background: var(--bg-vanilla-200);
.ant-modal-title {
color: var(--bg-ink-300);
}
}
.modal-content {
background: var(--bg-vanilla-100);
.attribute-select {
.ant-select-selector {
border: 1px solid var(--bg-vanilla-300);
background: var(--bg-vanilla-200);
}
}
.tree-text {
color: var(--bg-ink-300);
}
.ant-tree {
.ant-tree-title {
.attribute-error-title {
color: var(--bg-amber-500);
.tree-text {
color: var(--bg-amber-500);
}
}
.attribute-success-title {
.success-attribute-icon {
color: var(--bg-ink-300);
}
}
}
}
}
.loader-container {
background: var(--bg-ink-300);
}
}
}
.config-btn {
background: var(--bg-vanilla-300);
&.missing-config-btn {
background: var(--bg-amber-100);
color: var(--bg-amber-500);

View File

@@ -2,8 +2,8 @@
display: inline-flex;
padding: 4px 8px;
border-radius: 20px;
border: 1px solid color-mix(in srgb, var(--bg-sienna-500) 20%, transparent);
background: color-mix(in srgb, var(--bg-sienna-500) 10%, transparent);
border: 1px solid rgba(173, 127, 88, 0.2);
background: rgba(173, 127, 88, 0.1);
justify-content: center;
align-items: center;
gap: 5px;

View File

@@ -9,25 +9,24 @@ $custom-border-color: #2c3044;
&.ant-select-focused {
.ant-select-selector {
border-color: var(--primary-background);
box-shadow: 0 0 0 2px
color-mix(in srgb, var(--primary-background) 20%, transparent);
border-color: var(--bg-robin-500);
box-shadow: 0 0 0 2px rgba(78, 116, 248, 0.2);
}
}
.ant-select-selection-placeholder {
color: color-mix(in srgb, var(--border) 45%, transparent);
color: rgba(192, 193, 195, 0.45);
}
// Base styles are for dark mode
.ant-select-selector {
background-color: var(--l2-background);
border-color: var(--l1-border);
background-color: var(--bg-ink-400);
border-color: var(--bg-slate-400);
}
.ant-select-clear {
background-color: var(--l2-background);
color: color-mix(in srgb, var(--border) 70%, transparent);
background-color: var(--bg-ink-400);
color: rgba(192, 193, 195, 0.7);
}
}
@@ -43,7 +42,7 @@ $custom-border-color: #2c3044;
.ant-select-selection-placeholder {
opacity: 1 !important;
color: var(--l2-foreground) !important;
color: var(--bg-vanilla-400) !important;
font-weight: 500;
visibility: visible !important;
pointer-events: none;
@@ -64,7 +63,7 @@ $custom-border-color: #2c3044;
left: 12px;
top: 50%;
transform: translateY(-50%);
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
z-index: 1;
pointer-events: none;
@@ -77,8 +76,8 @@ $custom-border-color: #2c3044;
max-height: 200px;
overflow: auto;
scrollbar-width: thin;
background-color: var(--l2-background);
border-color: var(--l1-border);
background-color: var(--bg-ink-400);
border-color: var(--bg-slate-400);
cursor: text;
&::-webkit-scrollbar {
@@ -91,7 +90,7 @@ $custom-border-color: #2c3044;
}
&::-webkit-scrollbar-track {
background-color: var(--l1-border);
background-color: var(--bg-slate-400);
}
}
@@ -107,57 +106,46 @@ $custom-border-color: #2c3044;
&.ant-select-focused {
.ant-select-selector {
border-color: var(--primary-background);
box-shadow: 0 0 0 2px
color-mix(in srgb, var(--primary-background) 20%, transparent);
border-color: var(--bg-robin-500);
box-shadow: 0 0 0 2px rgba(78, 116, 248, 0.2);
}
}
.ant-select-selection-placeholder {
color: color-mix(in srgb, var(--border) 45%, transparent);
color: rgba(192, 193, 195, 0.45);
}
// Customize tags in multiselect (dark mode by default)
.ant-select-selection-item {
background-color: var(--l1-border);
background-color: var(--bg-slate-400);
border-radius: 4px;
border: 1px solid $custom-border-color;
margin-right: 4px;
transition: all 0.2s;
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
// Style for active tag (keyboard navigation)
&-active {
border-color: var(--primary-background) !important;
background-color: color-mix(
in srgb,
var(--primary-background) 15%,
transparent
) !important;
outline: 2px solid
color-mix(in srgb, var(--primary-background) 20%, transparent);
border-color: var(--bg-robin-500) !important;
background-color: rgba(78, 116, 248, 0.15) !important;
outline: 2px solid rgba(78, 116, 248, 0.2);
}
// Style for selected tags (via keyboard or mouse selection)
&-selected {
border-color: var(--primary-background) !important;
background-color: color-mix(
in srgb,
var(--primary-background) 15%,
transparent
) !important;
box-shadow: 0 0 0 2px
color-mix(in srgb, var(--primary-background) 20%, transparent);
border-color: var(--bg-robin-500) !important;
background-color: rgba(78, 116, 248, 0.15) !important;
box-shadow: 0 0 0 2px rgba(78, 116, 248, 0.2);
}
.ant-select-selection-item-content {
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
}
.ant-select-selection-item-remove {
color: color-mix(in srgb, var(--border) 70%, transparent);
color: rgba(192, 193, 195, 0.7);
&:hover {
color: var(--l1-border);
color: rgba(192, 193, 195, 1);
}
}
}
@@ -182,24 +170,20 @@ $custom-border-color: #2c3044;
padding: 0;
box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.5), 0 6px 16px 0 rgba(0, 0, 0, 0.4),
0 9px 28px 8px rgba(0, 0, 0, 0.3);
background-color: var(--l2-background);
border: 1px solid var(--l1-border);
background-color: var(--bg-ink-400);
border: 1px solid var(--bg-slate-400);
.ant-select-item {
padding: 8px 12px;
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
// Make keyboard navigation visible
&-option-active {
background-color: var(--l1-border) !important;
background-color: var(--bg-slate-400) !important;
}
&-option-selected {
background-color: color-mix(
in srgb,
var(--primary-background) 15%,
transparent
) !important;
background-color: rgba(78, 116, 248, 0.15) !important;
}
}
}
@@ -215,7 +199,7 @@ $custom-border-color: #2c3044;
.empty-message {
padding: 12px;
text-align: center;
color: color-mix(in srgb, var(--border) 45%, transparent);
color: rgba(192, 193, 195, 0.45);
}
}
@@ -227,9 +211,9 @@ $custom-border-color: #2c3044;
overflow-x: hidden;
scrollbar-width: thin;
border-radius: 4px;
border: 1px solid var(--l1-border);
border: 1px solid var(--bg-slate-400);
width: 100%;
background-color: var(--l2-background);
background-color: var(--bg-ink-400);
&::-webkit-scrollbar {
width: 6px;
@@ -241,7 +225,7 @@ $custom-border-color: #2c3044;
}
&::-webkit-scrollbar-track {
background-color: var(--l1-border);
background-color: var(--bg-slate-400);
}
.no-section-options {
@@ -257,8 +241,8 @@ $custom-border-color: #2c3044;
font-weight: 500;
padding: 4px 12px;
font-size: 13px;
color: var(--l2-foreground);
background-color: var(--l1-border);
color: var(--bg-vanilla-400);
background-color: var(--bg-slate-400);
border-bottom: 1px solid $custom-border-color;
border-top: 1px solid $custom-border-color;
position: relative;
@@ -275,28 +259,20 @@ $custom-border-color: #2c3044;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
&:hover {
background-color: var(--l1-border);
background-color: var(--bg-slate-400);
}
&.selected {
background-color: color-mix(
in srgb,
var(--primary-background) 15%,
transparent
);
background-color: rgba(78, 116, 248, 0.15);
font-weight: 500;
}
&.active {
background-color: color-mix(
in srgb,
var(--primary-background) 15%,
transparent
);
border-color: var(--primary-background);
background-color: rgba(78, 116, 248, 0.15);
border-color: var(--bg-robin-500);
}
.option-content {
@@ -314,7 +290,7 @@ $custom-border-color: #2c3044;
padding: 2px 6px;
border-radius: 4px;
background-color: $custom-border-color;
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
margin-left: 8px;
}
}
@@ -331,20 +307,20 @@ $custom-border-color: #2c3044;
display: flex;
align-items: center;
padding: 8px 12px;
border-top: 1px solid var(--l1-border);
border-top: 1px solid var(--bg-slate-400);
position: sticky;
bottom: 0;
background-color: var(--l2-background);
background-color: var(--bg-ink-400);
z-index: 1;
.navigation-icons {
display: flex;
margin-right: 8px;
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
}
.navigation-text {
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
font-size: 12px;
}
@@ -386,11 +362,11 @@ $custom-border-color: #2c3044;
height: 14px;
flex-shrink: 0;
border-radius: 2.286px;
border-top: 1.143px solid var(--l1-border);
border-right: 1.143px solid var(--l1-border);
border-bottom: 2.286px solid var(--l1-border);
border-left: 1.143px solid var(--l1-border);
background: var(--l2-background);
border-top: 1.143px solid var(--bg-ink-200);
border-right: 1.143px solid var(--bg-ink-200);
border-bottom: 2.286px solid var(--bg-ink-200);
border-left: 1.143px solid var(--bg-ink-200);
background: var(--Ink-400, var(--bg-ink-400));
}
}
}
@@ -403,16 +379,16 @@ $custom-border-color: #2c3044;
overflow-x: hidden;
scrollbar-width: thin;
border-radius: 4px;
border: 1px solid var(--l1-border);
border: 1px solid var(--bg-slate-400);
width: 100%;
background-color: var(--l2-background);
background-color: var(--bg-ink-400);
.select-all-option,
.custom-value-option {
padding: 8px 12px;
border-bottom: 1px solid $custom-border-color;
margin-bottom: 8px;
background-color: var(--l1-border);
background-color: var(--bg-slate-400);
position: sticky;
top: 0;
z-index: 1;
@@ -441,8 +417,8 @@ $custom-border-color: #2c3044;
font-weight: 500;
padding: 4px 12px;
font-size: 13px;
color: var(--l2-foreground);
background-color: var(--l1-border);
color: var(--bg-vanilla-400);
background-color: var(--bg-slate-400);
border-bottom: 1px solid $custom-border-color;
border-top: 1px solid $custom-border-color;
position: relative;
@@ -456,27 +432,19 @@ $custom-border-color: #2c3044;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
&.active {
background-color: color-mix(
in srgb,
var(--primary-background) 15%,
transparent
);
border-color: var(--primary-background);
background-color: rgba(78, 116, 248, 0.15);
border-color: var(--bg-robin-500);
}
&:hover {
background-color: var(--l1-border);
background-color: var(--bg-slate-400);
}
&.selected {
background-color: color-mix(
in srgb,
var(--primary-background) 15%,
transparent
);
background-color: rgba(78, 116, 248, 0.15);
font-weight: 500;
}
@@ -515,7 +483,7 @@ $custom-border-color: #2c3044;
padding: 2px 6px;
border-radius: 4px;
background-color: $custom-border-color;
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
margin-left: 8px;
}
}
@@ -573,25 +541,21 @@ $custom-border-color: #2c3044;
.empty-message {
padding: 12px;
text-align: center;
color: color-mix(in srgb, var(--border) 45%, transparent);
color: rgba(192, 193, 195, 0.45);
}
.status-message {
padding: 8px 12px;
text-align: center;
font-style: italic;
color: color-mix(in srgb, var(--border) 65%, transparent);
color: rgba(192, 193, 195, 0.65);
border-top: 1px dashed $custom-border-color;
}
}
// Custom styles for highlight text
.highlight-text {
background-color: color-mix(
in srgb,
var(--primary-background) 20%,
transparent
);
background-color: rgba(78, 116, 248, 0.2);
padding: 0 1px;
border-radius: 2px;
font-weight: 500;
@@ -601,7 +565,7 @@ $custom-border-color: #2c3044;
.custom-option {
&.focused,
&.ant-select-item-option-active {
background-color: var(--l1-border) !important;
background-color: var(--bg-slate-400) !important;
}
}
@@ -612,7 +576,7 @@ $custom-border-color: #2c3044;
position: sticky;
top: 0;
z-index: 2;
background-color: var(--l1-border);
background-color: var(--bg-slate-400);
border-bottom: 1px solid $custom-border-color;
padding: 4px 12px;
margin: 0;
@@ -630,8 +594,7 @@ $custom-border-color: #2c3044;
// Custom scrollbar styling (shared between components)
@mixin custom-scrollbar {
scrollbar-width: thin;
scrollbar-color: color-mix(in srgb, var(--border) 30%, transparent)
color-mix(in srgb, var(--border) 60%, transparent);
scrollbar-color: rgba(192, 193, 195, 0.3) rgba(29, 33, 45, 0.6);
&::-webkit-scrollbar {
width: 6px;
@@ -639,17 +602,17 @@ $custom-border-color: #2c3044;
}
&::-webkit-scrollbar-track {
background-color: color-mix(in srgb, var(--border) 60%, transparent);
background-color: rgba(29, 33, 45, 0.6);
border-radius: 10px;
}
&::-webkit-scrollbar-thumb {
background-color: color-mix(in srgb, var(--border) 30%, transparent);
background-color: rgba(192, 193, 195, 0.3);
border-radius: 10px;
transition: background-color 0.2s ease;
&:hover {
background-color: color-mix(in srgb, var(--border) 50%, transparent);
background-color: rgba(192, 193, 195, 0.5);
}
}
}
@@ -657,8 +620,7 @@ $custom-border-color: #2c3044;
// Subtle nested scrollbar styling
@mixin nested-scrollbar {
scrollbar-width: thin;
scrollbar-color: color-mix(in srgb, var(--border) 20%, transparent)
color-mix(in srgb, var(--border) 60%, transparent);
scrollbar-color: rgba(192, 193, 195, 0.2) rgba(29, 33, 45, 0.6);
&::-webkit-scrollbar {
width: 4px;
@@ -666,16 +628,16 @@ $custom-border-color: #2c3044;
}
&::-webkit-scrollbar-track {
background-color: color-mix(in srgb, var(--border) 60%, transparent);
background-color: rgba(29, 33, 45, 0.6);
border-radius: 10px;
}
&::-webkit-scrollbar-thumb {
background-color: color-mix(in srgb, var(--border) 20%, transparent);
background-color: rgba(192, 193, 195, 0.2);
border-radius: 10px;
&:hover {
background-color: color-mix(in srgb, var(--border) 30%, transparent);
background-color: rgba(192, 193, 195, 0.3);
}
}
}
@@ -714,7 +676,7 @@ $custom-border-color: #2c3044;
.lightMode {
.custom-select {
.ant-select-selector {
background-color: var(--l1-background);
background-color: var(--bg-vanilla-100);
border-color: #e9e9e9;
}
@@ -723,7 +685,7 @@ $custom-border-color: #2c3044;
}
.ant-select-clear {
background-color: var(--l1-background);
background-color: var(--bg-vanilla-100);
color: rgba(0, 0, 0, 0.45);
}
@@ -737,7 +699,7 @@ $custom-border-color: #2c3044;
.custom-multiselect {
.ant-select-selector {
background-color: var(--l1-background);
background-color: var(--bg-vanilla-100);
border-color: #e9e9e9;
cursor: text; // Make entire selector clickable for input focus
@@ -789,37 +751,37 @@ $custom-border-color: #2c3044;
}
&-active {
border-color: var(--primary-background) !important;
background-color: var(--l3-background) !important;
border-color: var(--bg-robin-500) !important;
background-color: var(--bg-vanilla-300) !important;
}
&-selected {
border-color: var(--primary-background) !important;
background-color: var(--l3-background) !important;
border-color: #1890ff !important;
background-color: var(--bg-vanilla-300) !important;
}
}
}
.custom-select-dropdown-container,
.custom-multiselect-dropdown-container {
background-color: var(--l1-background);
border: 1px solid var(--l1-border);
background-color: var(--bg-vanilla-100);
border: 1px solid #f0f0f0;
box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12),
0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
.empty-message {
color: var(--l2-foreground);
color: rgba(0, 0, 0, 0.45);
}
.ant-select-item {
color: var(--l1-foreground);
color: rgba(0, 0, 0, 0.85);
&-option-active {
background-color: var(--l3-background) !important;
background-color: #f5f5f5 !important;
}
&-option-selected {
background-color: var(--l2-background) !important;
background-color: var(--bg-vanilla-300) !important;
}
}
}
@@ -827,7 +789,7 @@ $custom-border-color: #2c3044;
.custom-select-dropdown,
.custom-multiselect-dropdown {
border: 1px solid #f0f0f0;
background-color: var(--l1-background);
background-color: var(--bg-vanilla-100);
&::-webkit-scrollbar-thumb {
background-color: #ccc;
@@ -858,11 +820,11 @@ $custom-border-color: #2c3044;
}
&.selected {
background-color: var(--l3-background);
background-color: var(--bg-vanilla-300);
}
&.active {
background-color: var(--l3-background);
background-color: var(--bg-vanilla-300);
border-color: #91d5ff;
}
@@ -877,7 +839,7 @@ $custom-border-color: #2c3044;
.navigation-footer {
border-top: 1px solid #f0f0f0;
background-color: var(--l1-background);
background-color: var(--bg-vanilla-100);
.navigation-icons {
color: rgba(0, 0, 0, 0.45);
@@ -889,11 +851,11 @@ $custom-border-color: #2c3044;
.navigate {
.icons {
border-top: 1.143px solid var(--l2-foreground);
border-right: 1.143px solid var(--l2-foreground);
border-bottom: 2.286px solid var(--l2-foreground);
border-left: 1.143px solid var(--l2-foreground);
background: var(--l3-background);
border-top: 1.143px solid var(--bg-ink-200);
border-right: 1.143px solid var(--bg-ink-200);
border-bottom: 2.286px solid var(--bg-ink-200);
border-left: 1.143px solid var(--bg-ink-200);
background: var(--bg-vanilla-300);
}
}
}
@@ -972,7 +934,7 @@ $custom-border-color: #2c3044;
left: 12px;
top: 50%;
transform: translateY(-50%);
color: var(--l2-foreground);
color: var(--bg-vanilla-400);
font-weight: 500;
z-index: 2;
pointer-events: none;

View File

@@ -5,8 +5,8 @@
width: 100%;
border-bottom: 1px solid var(--l1-border);
border-top: 1px solid var(--l1-border);
border-bottom: 1px solid var(--bg-slate-400);
border-top: 1px solid var(--bg-slate-400);
font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
'Helvetica Neue', sans-serif;
@@ -72,8 +72,8 @@
width: 1px;
background: repeating-linear-gradient(
to bottom,
var(--l1-border),
var(--l1-border) 4px,
#1d212d,
#1d212d 4px,
transparent 4px,
transparent 8px
);
@@ -93,7 +93,7 @@
top: 12px;
width: 6px;
height: 6px;
border-left: 6px dotted var(--l1-border);
border-left: 6px dotted #1d212d;
}
/* Horizontal line pointing from vertical to the item */
@@ -106,8 +106,8 @@
height: 1px;
background: repeating-linear-gradient(
to right,
var(--l1-border),
var(--l1-border) 4px,
#1d212d,
#1d212d 4px,
transparent 4px,
transparent 8px
);
@@ -149,7 +149,7 @@
width: 44px;
padding: 8px;
border-left: 1px solid var(--l1-border);
border-left: 1px solid var(--bg-slate-400);
.query-name {
display: flex;
@@ -163,10 +163,10 @@
border-radius: 0px 2px 2px 0px;
border-radius: 2px;
border: 1px solid color-mix(in srgb, var(--bg-sakura-500) 20%, transparent);
background: color-mix(in srgb, var(--bg-sakura-500) 10%, transparent);
border: 1px solid rgba(242, 71, 105, 0.2);
background: rgba(242, 71, 105, 0.1);
color: var(--bg-sakura-400);
color: var(--Sakura-400, #f56c87);
font-family: 'Space Mono';
font-size: 12px;
font-style: normal;
@@ -188,10 +188,10 @@
border-radius: 0px 2px 2px 0px;
border-radius: 2px;
border: 1px solid color-mix(in srgb, var(--bg-sienna-500) 20%, transparent);
background: color-mix(in srgb, var(--bg-sienna-500) 10%, transparent);
border: 1px solid rgba(173, 127, 88, 0.2);
background: rgba(173, 127, 88, 0.1);
color: var(--bg-sienna-500);
color: var(--Sienna-500, #ad7f58);
font-family: 'Space Mono';
font-size: 12px;
font-style: normal;
@@ -233,7 +233,7 @@
top: 12px;
width: 6px;
height: 6px;
border-left: 6px dotted var(--l1-border);
border-left: 6px dotted #1d212d;
}
/* Horizontal line pointing from vertical to the item */
@@ -246,8 +246,8 @@
height: 1px;
background: repeating-linear-gradient(
to right,
var(--l1-border),
var(--l1-border) 4px,
#1d212d,
#1d212d 4px,
transparent 4px,
transparent 8px
);
@@ -274,8 +274,8 @@
.ant-input-group-addon {
border-top-left-radius: 0px !important;
border-top-right-radius: 0px !important;
background: var(--l3-background);
color: var(--l2-foreground);
background: var(--bg-ink-300);
color: var(--bg-vanilla-400);
font-size: 12px;
font-weight: 300;
}
@@ -315,8 +315,8 @@
width: 1px;
background: repeating-linear-gradient(
to bottom,
var(--l1-border),
var(--l1-border) 4px,
#1d212d,
#1d212d 4px,
transparent 4px,
transparent 8px
);
@@ -344,14 +344,10 @@
.options {
.query-name {
border-radius: 0px 2px 2px 0px !important;
border: 1px solid color-mix(in srgb, var(--bg-sakura-500) 20%, transparent) !important;
background: color-mix(
in srgb,
var(--bg-sakura-500) 10%,
transparent
) !important;
border: 1px solid rgba(242, 71, 105, 0.2) !important;
background: rgba(242, 71, 105, 0.1) !important;
color: var(--bg-sakura-400) !important;
color: var(--Sakura-400, #f56c87) !important;
font-family: 'Space Mono';
font-size: 14px;
font-style: normal;
@@ -366,8 +362,8 @@
.formula-name {
border-radius: 0px 2px 2px 0px;
border: 1px solid color-mix(in srgb, var(--bg-sienna-500) 20%, transparent);
background: color-mix(in srgb, var(--bg-sienna-500) 10%, transparent);
border: 1px solid rgba(173, 127, 88, 0.2);
background: rgba(173, 127, 88, 0.1);
font-family: 'Space Mono';
font-size: 14px;
@@ -387,8 +383,8 @@
width: 1px;
background: repeating-linear-gradient(
to bottom,
var(--l1-border),
var(--l1-border) 4px,
#1d212d,
#1d212d 4px,
transparent 4px,
transparent 8px
);
@@ -404,13 +400,9 @@
min-width: 120px;
border-radius: 2px;
border: 1px solid var(--l1-border);
background: var(--l1-background);
border: 1px solid var(--Slate-400, #1d212d);
background: var(--Ink-300, #16181d);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
.ant-select-selection-item {
color: var(--l1-foreground);
}
}
}
}
@@ -449,18 +441,14 @@
.ant-select-selector {
border-radius: 2px;
border: 1px solid var(--l1-border) !important;
background: var(--l1-background) !important;
border: 1px solid var(--Slate-400, #1d212d) !important;
background: var(--Ink-300, #16181d) !important;
height: 34px !important;
box-sizing: border-box !important;
.ant-select-selection-item {
color: var(--l1-foreground);
}
}
.ant-select-arrow {
color: var(--l2-foreground) !important;
color: var(--bg-vanilla-400) !important;
}
}
@@ -468,3 +456,133 @@
cursor: pointer;
}
}
.lightMode {
.query-builder-v2 {
border-bottom: 1px solid var(--bg-vanilla-300);
border-top: 1px solid var(--bg-vanilla-300);
.qb-content-section {
.qb-elements-container {
&::after {
background: repeating-linear-gradient(
to bottom,
var(--bg-vanilla-300),
var(--bg-vanilla-300) 4px,
transparent 4px,
transparent 8px
);
}
.code-mirror-where-clause,
.query-aggregation-container,
.query-add-ons,
.metrics-aggregation-section-content,
.metrics-container {
&::before {
border-left: 6px dotted var(--bg-vanilla-300);
}
/* Horizontal line pointing from vertical to the item */
&::after {
background: repeating-linear-gradient(
to right,
var(--bg-vanilla-300),
var(--bg-vanilla-300) 4px,
transparent 4px,
transparent 8px
);
}
}
}
}
.query-names-section {
border-left: 1px solid var(--bg-vanilla-300);
}
.qb-formulas-container {
.qb-formula {
.formula-container {
.ant-col {
&::before {
border-left: 6px dotted var(--bg-vanilla-300);
}
/* Horizontal line pointing from vertical to the item */
&::after {
background: repeating-linear-gradient(
to right,
var(--bg-vanilla-300),
var(--bg-vanilla-300) 4px,
transparent 4px,
transparent 8px
);
}
}
}
}
}
.qb-footer {
.qb-footer-container {
.qb-add-new-query {
&::before {
background: repeating-linear-gradient(
to bottom,
var(--bg-vanilla-300),
var(--bg-vanilla-300) 4px,
transparent 4px,
transparent 8px
);
}
}
}
}
.qb-entity-options {
.options {
.formula-name {
&::before {
background: repeating-linear-gradient(
to bottom,
var(--bg-vanilla-300),
var(--bg-vanilla-300) 4px,
transparent 4px,
transparent 8px
);
left: 15px;
}
}
}
.query-data-source {
.ant-select-selector {
border: 1px solid var(--bg-vanilla-300) !important;
background: var(--bg-vanilla-100) !important;
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1) !important;
.ant-select-selection-item {
color: var(--text-ink-400);
}
}
}
}
.qb-search-filter-container {
.ant-select-selector {
border: 1px solid var(--bg-vanilla-300) !important;
background: var(--bg-vanilla-100) !important;
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1) !important;
.ant-select-selection-item {
color: var(--text-ink-400);
}
}
.ant-select-arrow {
color: var(--bg-vanilla-400) !important;
}
}
}
}

View File

@@ -39,7 +39,7 @@
align-items: center;
gap: 6px;
color: var(--l3-foreground);
color: var(--Slate-50, #62687c);
font-family: 'Geist Mono';
font-size: 12px;
font-style: normal;
@@ -65,7 +65,7 @@
gap: 10px;
.metrics-aggregation-section-content-item-label {
color: var(--l2-foreground);
color: var(--Vanilla-400, #c0c1c3);
font-family: 'Geist Mono';
font-size: 13px;
font-style: normal;
@@ -74,7 +74,7 @@
letter-spacing: -0.07px;
&.main-label {
color: var(--l3-foreground);
color: var(--Slate-50, #62687c);
font-family: 'Geist Mono';
font-size: 12px;
font-style: normal;
@@ -100,19 +100,15 @@
.ant-select-selector {
border-radius: 2px;
border: 1.005px solid var(--l1-border);
background: var(--l1-background);
color: var(--l1-foreground);
border: 1.005px solid var(--Slate-400, #1d212d);
background: var(--Ink-300, #16181d);
color: var(--bg-vanilla-400);
font-family: 'Geist Mono';
font-size: 13px;
font-style: normal;
font-weight: 400;
line-height: 20px;
letter-spacing: -0.07px;
.ant-select-selection-item {
color: var(--l1-foreground);
}
}
.input-with-label {
@@ -149,10 +145,10 @@
.metrics-operators-select {
border-radius: 2px;
border: 1.005px solid var(--l1-border);
background: var(--l1-background);
border: 1.005px solid var(--Slate-400, #1d212d);
background: var(--Ink-300, #16181d);
color: var(--l1-foreground);
color: var(--Vanilla-400, #c0c1c3);
font-family: 'Geist Mono';
font-size: 13px;
font-style: normal;
@@ -160,3 +156,35 @@
line-height: 20px; /* 142.857% */
letter-spacing: -0.07px;
}
.lightMode {
.metrics-aggregate-section {
.metrics-aggregation-section-content {
.metrics-aggregation-section-content-item {
.metrics-aggregation-section-content-item-label {
color: var(--text-ink-200);
&.main-label {
color: var(--text-slate-100);
}
}
.metrics-aggregation-section-content-item-value {
.ant-select-selector {
border: 1px solid var(--bg-vanilla-300) !important;
background: var(--bg-vanilla-100) !important;
.ant-select-selection-item {
color: var(--text-ink-400);
}
}
}
}
}
}
.metrics-operators-select {
border: 1px solid var(--bg-vanilla-300) !important;
background: var(--bg-vanilla-100) !important;
color: var(--text-ink-100);
}
}

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