mirror of
https://github.com/SigNoz/signoz.git
synced 2026-02-07 18:32:12 +00:00
Compare commits
14 Commits
integrate-
...
ns/devenv
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
18b542b8c5 | ||
|
|
8a8550ac85 | ||
|
|
8629c959f0 | ||
|
|
10760e6e1b | ||
|
|
4f45645b32 | ||
|
|
1417e22ae4 | ||
|
|
3051d442c0 | ||
|
|
ea15ce4e04 | ||
|
|
865a7a5a31 | ||
|
|
de4ca50a40 | ||
|
|
8cabaafc58 | ||
|
|
e9d66b8094 | ||
|
|
26d3d6b1e4 | ||
|
|
36d6debeab |
@@ -5,8 +5,8 @@ services:
|
||||
volumes:
|
||||
- ${PWD}/fs/etc/clickhouse-server/config.d/config.xml:/etc/clickhouse-server/config.d/config.xml
|
||||
- ${PWD}/fs/etc/clickhouse-server/users.d/users.xml:/etc/clickhouse-server/users.d/users.xml
|
||||
- ${PWD}/fs/tmp/var/lib/clickhouse/:/var/lib/clickhouse/
|
||||
- ${PWD}/fs/tmp/var/lib/clickhouse/user_scripts/:/var/lib/clickhouse/user_scripts/
|
||||
- clickhouse_data:/var/lib/clickhouse/
|
||||
ports:
|
||||
- '127.0.0.1:8123:8123'
|
||||
- '127.0.0.1:9000:9000'
|
||||
@@ -69,3 +69,5 @@ services:
|
||||
schema-migrator-sync:
|
||||
condition: service_completed_successfully
|
||||
restart: on-failure
|
||||
volumes:
|
||||
clickhouse_data:
|
||||
9
.github/pull_request_template.md
vendored
9
.github/pull_request_template.md
vendored
@@ -6,6 +6,15 @@
|
||||
> Why does this change exist?
|
||||
> What problem does it solve, and why is this the right approach?
|
||||
|
||||
|
||||
|
||||
#### Screenshots / Screen Recordings (if applicable)
|
||||
> Include screenshots or screen recordings that clearly show the behavior before the change and the result after the change. This helps reviewers quickly understand the impact and verify the update.
|
||||
|
||||
|
||||
#### Issues closed by this PR
|
||||
> Reference issues using `Closes #issue-number` to enable automatic closure on merge.
|
||||
|
||||
---
|
||||
|
||||
### ✅ Change Type
|
||||
|
||||
7
.github/workflows/commitci.yaml
vendored
7
.github/workflows/commitci.yaml
vendored
@@ -25,3 +25,10 @@ jobs:
|
||||
else
|
||||
echo "No references to 'ee' packages found in 'pkg' directory"
|
||||
fi
|
||||
|
||||
if grep -R --include="*.go" '.*/ee/.*' cmd/community/; then
|
||||
echo "Error: Found references to 'ee' packages in 'cmd/community' directory"
|
||||
exit 1
|
||||
else
|
||||
echo "No references to 'ee' packages found in 'cmd/community' directory"
|
||||
fi
|
||||
|
||||
5
.github/workflows/integrationci.yaml
vendored
5
.github/workflows/integrationci.yaml
vendored
@@ -84,8 +84,11 @@ jobs:
|
||||
sudo rm /etc/apt/sources.list.d/google-chrome.list
|
||||
export CHROMEDRIVER_VERSION=`curl -s https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_${CHROME_MAJOR_VERSION%%.*}`
|
||||
curl -L -O "https://storage.googleapis.com/chrome-for-testing-public/${CHROMEDRIVER_VERSION}/linux64/chromedriver-linux64.zip"
|
||||
unzip chromedriver-linux64.zip && chmod +x chromedriver && sudo mv chromedriver /usr/local/bin
|
||||
unzip chromedriver-linux64.zip
|
||||
chmod +x chromedriver-linux64/chromedriver
|
||||
sudo mv chromedriver-linux64/chromedriver /usr/local/bin/chromedriver
|
||||
chromedriver -version
|
||||
google-chrome-stable --version
|
||||
- name: run
|
||||
run: |
|
||||
cd tests/integration && \
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,6 +1,9 @@
|
||||
|
||||
node_modules
|
||||
|
||||
.vscode
|
||||
!.vscode/settings.json
|
||||
|
||||
deploy/docker/environment_tiny/common_test
|
||||
frontend/node_modules
|
||||
frontend/.pnp
|
||||
@@ -104,7 +107,6 @@ dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
|
||||
@@ -5,13 +5,14 @@ import (
|
||||
"log/slog"
|
||||
|
||||
"github.com/SigNoz/signoz/cmd"
|
||||
"github.com/SigNoz/signoz/ee/authz/openfgaauthz"
|
||||
"github.com/SigNoz/signoz/ee/authz/openfgaschema"
|
||||
"github.com/SigNoz/signoz/ee/sqlstore/postgressqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/analytics"
|
||||
"github.com/SigNoz/signoz/pkg/authn"
|
||||
"github.com/SigNoz/signoz/pkg/authz"
|
||||
"github.com/SigNoz/signoz/pkg/authz/openfgaauthz"
|
||||
"github.com/SigNoz/signoz/pkg/authz/openfgaschema"
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/gateway"
|
||||
"github.com/SigNoz/signoz/pkg/gateway/noopgateway"
|
||||
"github.com/SigNoz/signoz/pkg/licensing"
|
||||
"github.com/SigNoz/signoz/pkg/licensing/nooplicensing"
|
||||
"github.com/SigNoz/signoz/pkg/modules/dashboard"
|
||||
@@ -24,7 +25,6 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/signoz"
|
||||
"github.com/SigNoz/signoz/pkg/sqlschema"
|
||||
"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/version"
|
||||
"github.com/SigNoz/signoz/pkg/zeus"
|
||||
@@ -57,13 +57,6 @@ func runServer(ctx context.Context, config signoz.Config, logger *slog.Logger) e
|
||||
// print the version
|
||||
version.Info.PrettyPrint(config.Version)
|
||||
|
||||
// add enterprise sqlstore factories to the community sqlstore factories
|
||||
sqlstoreFactories := signoz.NewSQLStoreProviderFactories()
|
||||
if err := sqlstoreFactories.Add(postgressqlstore.NewFactory(sqlstorehook.NewLoggingFactory())); err != nil {
|
||||
logger.ErrorContext(ctx, "failed to add postgressqlstore factory", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
signoz, err := signoz.New(
|
||||
ctx,
|
||||
config,
|
||||
@@ -90,6 +83,9 @@ func runServer(ctx context.Context, config signoz.Config, logger *slog.Logger) e
|
||||
func(store sqlstore.SQLStore, settings factory.ProviderSettings, analytics analytics.Analytics, orgGetter organization.Getter, _ role.Module, queryParser queryparser.QueryParser, _ querier.Querier, _ licensing.Licensing) dashboard.Module {
|
||||
return impldashboard.NewModule(impldashboard.NewStore(store), settings, analytics, orgGetter, queryParser)
|
||||
},
|
||||
func(_ licensing.Licensing) factory.ProviderFactory[gateway.Gateway, gateway.Config] {
|
||||
return noopgateway.NewProviderFactory()
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
logger.ErrorContext(ctx, "failed to create signoz", "error", err)
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/SigNoz/signoz/ee/authn/callbackauthn/samlcallbackauthn"
|
||||
"github.com/SigNoz/signoz/ee/authz/openfgaauthz"
|
||||
"github.com/SigNoz/signoz/ee/authz/openfgaschema"
|
||||
"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/dashboard/impldashboard"
|
||||
@@ -22,6 +23,7 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/authn"
|
||||
"github.com/SigNoz/signoz/pkg/authz"
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/gateway"
|
||||
"github.com/SigNoz/signoz/pkg/licensing"
|
||||
"github.com/SigNoz/signoz/pkg/modules/dashboard"
|
||||
pkgimpldashboard "github.com/SigNoz/signoz/pkg/modules/dashboard/impldashboard"
|
||||
@@ -120,6 +122,9 @@ func runServer(ctx context.Context, config signoz.Config, logger *slog.Logger) e
|
||||
func(store sqlstore.SQLStore, settings factory.ProviderSettings, analytics analytics.Analytics, orgGetter organization.Getter, role role.Module, queryParser queryparser.QueryParser, querier querier.Querier, licensing licensing.Licensing) dashboard.Module {
|
||||
return impldashboard.NewModule(pkgimpldashboard.NewStore(store), settings, analytics, orgGetter, role, queryParser, querier, licensing)
|
||||
},
|
||||
func(licensing licensing.Licensing) factory.ProviderFactory[gateway.Gateway, gateway.Config] {
|
||||
return httpgateway.NewProviderFactory(licensing)
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
logger.ErrorContext(ctx, "failed to create signoz", "error", err)
|
||||
|
||||
@@ -176,7 +176,7 @@ services:
|
||||
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
|
||||
signoz:
|
||||
!!merge <<: *db-depend
|
||||
image: signoz/signoz:v0.107.0
|
||||
image: signoz/signoz:v0.108.0
|
||||
command:
|
||||
- --config=/root/config/prometheus.yml
|
||||
ports:
|
||||
|
||||
@@ -117,7 +117,7 @@ services:
|
||||
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
|
||||
signoz:
|
||||
!!merge <<: *db-depend
|
||||
image: signoz/signoz:v0.107.0
|
||||
image: signoz/signoz:v0.108.0
|
||||
command:
|
||||
- --config=/root/config/prometheus.yml
|
||||
ports:
|
||||
|
||||
@@ -179,7 +179,7 @@ services:
|
||||
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
|
||||
signoz:
|
||||
!!merge <<: *db-depend
|
||||
image: signoz/signoz:${VERSION:-v0.107.0}
|
||||
image: signoz/signoz:${VERSION:-v0.108.0}
|
||||
container_name: signoz
|
||||
command:
|
||||
- --config=/root/config/prometheus.yml
|
||||
|
||||
@@ -111,7 +111,7 @@ services:
|
||||
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
|
||||
signoz:
|
||||
!!merge <<: *db-depend
|
||||
image: signoz/signoz:${VERSION:-v0.107.0}
|
||||
image: signoz/signoz:${VERSION:-v0.108.0}
|
||||
container_name: signoz
|
||||
command:
|
||||
- --config=/root/config/prometheus.yml
|
||||
|
||||
@@ -607,186 +607,6 @@ paths:
|
||||
summary: Update auth domain
|
||||
tags:
|
||||
- authdomains
|
||||
/api/v1/fields/keys:
|
||||
get:
|
||||
deprecated: false
|
||||
description: This endpoint returns field keys
|
||||
operationId: GetFieldsKeys
|
||||
parameters:
|
||||
- in: query
|
||||
name: signal
|
||||
schema:
|
||||
type: string
|
||||
- in: query
|
||||
name: source
|
||||
schema:
|
||||
type: string
|
||||
- in: query
|
||||
name: limit
|
||||
schema:
|
||||
type: integer
|
||||
- in: query
|
||||
name: startUnixMilli
|
||||
schema:
|
||||
format: int64
|
||||
type: integer
|
||||
- in: query
|
||||
name: endUnixMilli
|
||||
schema:
|
||||
format: int64
|
||||
type: integer
|
||||
- in: query
|
||||
name: fieldContext
|
||||
schema:
|
||||
type: string
|
||||
- in: query
|
||||
name: fieldDataType
|
||||
schema:
|
||||
type: string
|
||||
- content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TelemetrytypesMetricContext'
|
||||
in: query
|
||||
name: metricContext
|
||||
- in: query
|
||||
name: name
|
||||
schema:
|
||||
type: string
|
||||
- in: query
|
||||
name: searchText
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
data:
|
||||
$ref: '#/components/schemas/TelemetrytypesGettableFieldKeys'
|
||||
status:
|
||||
type: string
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Unauthorized
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Internal Server Error
|
||||
security:
|
||||
- api_key:
|
||||
- VIEWER
|
||||
- tokenizer:
|
||||
- VIEWER
|
||||
summary: Get field keys
|
||||
tags:
|
||||
- fields
|
||||
/api/v1/fields/values:
|
||||
get:
|
||||
deprecated: false
|
||||
description: This endpoint returns field values
|
||||
operationId: GetFieldsValues
|
||||
parameters:
|
||||
- in: query
|
||||
name: signal
|
||||
schema:
|
||||
type: string
|
||||
- in: query
|
||||
name: source
|
||||
schema:
|
||||
type: string
|
||||
- in: query
|
||||
name: limit
|
||||
schema:
|
||||
type: integer
|
||||
- in: query
|
||||
name: startUnixMilli
|
||||
schema:
|
||||
format: int64
|
||||
type: integer
|
||||
- in: query
|
||||
name: endUnixMilli
|
||||
schema:
|
||||
format: int64
|
||||
type: integer
|
||||
- in: query
|
||||
name: fieldContext
|
||||
schema:
|
||||
type: string
|
||||
- in: query
|
||||
name: fieldDataType
|
||||
schema:
|
||||
type: string
|
||||
- content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TelemetrytypesMetricContext'
|
||||
in: query
|
||||
name: metricContext
|
||||
- in: query
|
||||
name: name
|
||||
schema:
|
||||
type: string
|
||||
- in: query
|
||||
name: searchText
|
||||
schema:
|
||||
type: string
|
||||
- in: query
|
||||
name: existingQuery
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
data:
|
||||
$ref: '#/components/schemas/TelemetrytypesGettableFieldValues'
|
||||
status:
|
||||
type: string
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Unauthorized
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Internal Server Error
|
||||
security:
|
||||
- api_key:
|
||||
- VIEWER
|
||||
- tokenizer:
|
||||
- VIEWER
|
||||
summary: Get field values
|
||||
tags:
|
||||
- fields
|
||||
/api/v1/getResetPasswordToken/{id}:
|
||||
get:
|
||||
deprecated: false
|
||||
@@ -2247,6 +2067,361 @@ paths:
|
||||
summary: Get features
|
||||
tags:
|
||||
- features
|
||||
/api/v2/gateway/ingestion_keys:
|
||||
get:
|
||||
deprecated: false
|
||||
description: This endpoint returns the ingestion keys for a workspace
|
||||
operationId: GetIngestionKeys
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
data:
|
||||
$ref: '#/components/schemas/GatewaytypesGettableIngestionKeys'
|
||||
status:
|
||||
type: string
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Unauthorized
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Internal Server Error
|
||||
security:
|
||||
- api_key:
|
||||
- ADMIN
|
||||
- tokenizer:
|
||||
- ADMIN
|
||||
summary: Get ingestion keys for workspace
|
||||
tags:
|
||||
- gateway
|
||||
post:
|
||||
deprecated: false
|
||||
description: This endpoint creates an ingestion key for the workspace
|
||||
operationId: CreateIngestionKey
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GatewaytypesPostableIngestionKey'
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
data:
|
||||
$ref: '#/components/schemas/GatewaytypesGettableCreatedIngestionKey'
|
||||
status:
|
||||
type: string
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Unauthorized
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Internal Server Error
|
||||
security:
|
||||
- api_key:
|
||||
- ADMIN
|
||||
- tokenizer:
|
||||
- ADMIN
|
||||
summary: Create ingestion key for workspace
|
||||
tags:
|
||||
- gateway
|
||||
/api/v2/gateway/ingestion_keys/{keyId}:
|
||||
delete:
|
||||
deprecated: false
|
||||
description: This endpoint deletes an ingestion key for the workspace
|
||||
operationId: DeleteIngestionKey
|
||||
parameters:
|
||||
- in: path
|
||||
name: keyId
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"204":
|
||||
description: No Content
|
||||
"401":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Unauthorized
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Internal Server Error
|
||||
security:
|
||||
- api_key:
|
||||
- ADMIN
|
||||
- tokenizer:
|
||||
- ADMIN
|
||||
summary: Delete ingestion key for workspace
|
||||
tags:
|
||||
- gateway
|
||||
patch:
|
||||
deprecated: false
|
||||
description: This endpoint updates an ingestion key for the workspace
|
||||
operationId: UpdateIngestionKey
|
||||
parameters:
|
||||
- in: path
|
||||
name: keyId
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GatewaytypesPostableIngestionKey'
|
||||
responses:
|
||||
"204":
|
||||
description: No Content
|
||||
"401":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Unauthorized
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Internal Server Error
|
||||
security:
|
||||
- api_key:
|
||||
- ADMIN
|
||||
- tokenizer:
|
||||
- ADMIN
|
||||
summary: Update ingestion key for workspace
|
||||
tags:
|
||||
- gateway
|
||||
/api/v2/gateway/ingestion_keys/{keyId}/limits:
|
||||
post:
|
||||
deprecated: false
|
||||
description: This endpoint creates an ingestion key limit
|
||||
operationId: CreateIngestionKeyLimit
|
||||
parameters:
|
||||
- in: path
|
||||
name: keyId
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GatewaytypesPostableIngestionKeyLimit'
|
||||
responses:
|
||||
"201":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
data:
|
||||
$ref: '#/components/schemas/GatewaytypesGettableCreatedIngestionKeyLimit'
|
||||
status:
|
||||
type: string
|
||||
type: object
|
||||
description: Created
|
||||
"401":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Unauthorized
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Internal Server Error
|
||||
security:
|
||||
- api_key:
|
||||
- ADMIN
|
||||
- tokenizer:
|
||||
- ADMIN
|
||||
summary: Create limit for the ingestion key
|
||||
tags:
|
||||
- gateway
|
||||
/api/v2/gateway/ingestion_keys/limits/{limitId}:
|
||||
delete:
|
||||
deprecated: false
|
||||
description: This endpoint deletes an ingestion key limit
|
||||
operationId: DeleteIngestionKeyLimit
|
||||
parameters:
|
||||
- in: path
|
||||
name: limitId
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"204":
|
||||
description: No Content
|
||||
"401":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Unauthorized
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Internal Server Error
|
||||
security:
|
||||
- api_key:
|
||||
- ADMIN
|
||||
- tokenizer:
|
||||
- ADMIN
|
||||
summary: Delete limit for the ingestion key
|
||||
tags:
|
||||
- gateway
|
||||
patch:
|
||||
deprecated: false
|
||||
description: This endpoint updates an ingestion key limit
|
||||
operationId: UpdateIngestionKeyLimit
|
||||
parameters:
|
||||
- in: path
|
||||
name: limitId
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GatewaytypesUpdatableIngestionKeyLimit'
|
||||
responses:
|
||||
"204":
|
||||
description: No Content
|
||||
"401":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Unauthorized
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Internal Server Error
|
||||
security:
|
||||
- api_key:
|
||||
- ADMIN
|
||||
- tokenizer:
|
||||
- ADMIN
|
||||
summary: Update limit for the ingestion key
|
||||
tags:
|
||||
- gateway
|
||||
/api/v2/gateway/ingestion_keys/search:
|
||||
get:
|
||||
deprecated: false
|
||||
description: This endpoint returns the ingestion keys for a workspace
|
||||
operationId: SearchIngestionKeys
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
data:
|
||||
$ref: '#/components/schemas/GatewaytypesGettableIngestionKeys'
|
||||
status:
|
||||
type: string
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Unauthorized
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Internal Server Error
|
||||
security:
|
||||
- api_key:
|
||||
- ADMIN
|
||||
- tokenizer:
|
||||
- ADMIN
|
||||
summary: Search ingestion keys for workspace
|
||||
tags:
|
||||
- gateway
|
||||
/api/v2/metric/alerts:
|
||||
get:
|
||||
deprecated: false
|
||||
@@ -3231,6 +3406,160 @@ components:
|
||||
nullable: true
|
||||
type: object
|
||||
type: object
|
||||
GatewaytypesGettableCreatedIngestionKey:
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
value:
|
||||
type: string
|
||||
type: object
|
||||
GatewaytypesGettableCreatedIngestionKeyLimit:
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
type: object
|
||||
GatewaytypesGettableIngestionKeys:
|
||||
properties:
|
||||
_pagination:
|
||||
$ref: '#/components/schemas/GatewaytypesPagination'
|
||||
keys:
|
||||
items:
|
||||
$ref: '#/components/schemas/GatewaytypesIngestionKey'
|
||||
nullable: true
|
||||
type: array
|
||||
type: object
|
||||
GatewaytypesIngestionKey:
|
||||
properties:
|
||||
created_at:
|
||||
format: date-time
|
||||
type: string
|
||||
expires_at:
|
||||
format: date-time
|
||||
type: string
|
||||
id:
|
||||
type: string
|
||||
limits:
|
||||
items:
|
||||
$ref: '#/components/schemas/GatewaytypesLimit'
|
||||
nullable: true
|
||||
type: array
|
||||
name:
|
||||
type: string
|
||||
tags:
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
updated_at:
|
||||
format: date-time
|
||||
type: string
|
||||
value:
|
||||
type: string
|
||||
workspace_id:
|
||||
type: string
|
||||
type: object
|
||||
GatewaytypesLimit:
|
||||
properties:
|
||||
config:
|
||||
$ref: '#/components/schemas/GatewaytypesLimitConfig'
|
||||
created_at:
|
||||
format: date-time
|
||||
type: string
|
||||
id:
|
||||
type: string
|
||||
key_id:
|
||||
type: string
|
||||
metric:
|
||||
$ref: '#/components/schemas/GatewaytypesLimitMetric'
|
||||
signal:
|
||||
type: string
|
||||
tags:
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
updated_at:
|
||||
format: date-time
|
||||
type: string
|
||||
type: object
|
||||
GatewaytypesLimitConfig:
|
||||
properties:
|
||||
day:
|
||||
$ref: '#/components/schemas/GatewaytypesLimitValue'
|
||||
second:
|
||||
$ref: '#/components/schemas/GatewaytypesLimitValue'
|
||||
type: object
|
||||
GatewaytypesLimitMetric:
|
||||
properties:
|
||||
day:
|
||||
$ref: '#/components/schemas/GatewaytypesLimitMetricValue'
|
||||
second:
|
||||
$ref: '#/components/schemas/GatewaytypesLimitMetricValue'
|
||||
type: object
|
||||
GatewaytypesLimitMetricValue:
|
||||
properties:
|
||||
count:
|
||||
format: int64
|
||||
type: integer
|
||||
size:
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
GatewaytypesLimitValue:
|
||||
properties:
|
||||
count:
|
||||
format: int64
|
||||
type: integer
|
||||
size:
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
GatewaytypesPagination:
|
||||
properties:
|
||||
page:
|
||||
type: integer
|
||||
pages:
|
||||
type: integer
|
||||
per_page:
|
||||
type: integer
|
||||
total:
|
||||
type: integer
|
||||
type: object
|
||||
GatewaytypesPostableIngestionKey:
|
||||
properties:
|
||||
expires_at:
|
||||
format: date-time
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
tags:
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
type: object
|
||||
GatewaytypesPostableIngestionKeyLimit:
|
||||
properties:
|
||||
config:
|
||||
$ref: '#/components/schemas/GatewaytypesLimitConfig'
|
||||
signal:
|
||||
type: string
|
||||
tags:
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
type: object
|
||||
GatewaytypesUpdatableIngestionKeyLimit:
|
||||
properties:
|
||||
config:
|
||||
$ref: '#/components/schemas/GatewaytypesLimitConfig'
|
||||
tags:
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
type: object
|
||||
MetricsexplorertypesMetricAlert:
|
||||
properties:
|
||||
alertId:
|
||||
@@ -3561,65 +3890,6 @@ components:
|
||||
status:
|
||||
type: string
|
||||
type: object
|
||||
TelemetrytypesGettableFieldKeys:
|
||||
properties:
|
||||
complete:
|
||||
type: boolean
|
||||
keys:
|
||||
additionalProperties:
|
||||
items:
|
||||
$ref: '#/components/schemas/TelemetrytypesTelemetryFieldKey'
|
||||
type: array
|
||||
nullable: true
|
||||
type: object
|
||||
type: object
|
||||
TelemetrytypesGettableFieldValues:
|
||||
properties:
|
||||
complete:
|
||||
type: boolean
|
||||
values:
|
||||
$ref: '#/components/schemas/TelemetrytypesTelemetryFieldValues'
|
||||
type: object
|
||||
TelemetrytypesMetricContext:
|
||||
properties:
|
||||
metricName:
|
||||
type: string
|
||||
type: object
|
||||
TelemetrytypesTelemetryFieldKey:
|
||||
properties:
|
||||
description:
|
||||
type: string
|
||||
fieldContext:
|
||||
type: string
|
||||
fieldDataType:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
signal:
|
||||
type: string
|
||||
unit:
|
||||
type: string
|
||||
type: object
|
||||
TelemetrytypesTelemetryFieldValues:
|
||||
properties:
|
||||
boolValues:
|
||||
items:
|
||||
type: boolean
|
||||
type: array
|
||||
numberValues:
|
||||
items:
|
||||
format: double
|
||||
type: number
|
||||
type: array
|
||||
relatedValues:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
stringValues:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
TypesChangePasswordRequest:
|
||||
properties:
|
||||
newPassword:
|
||||
|
||||
282
ee/gateway/httpgateway/provider.go
Normal file
282
ee/gateway/httpgateway/provider.go
Normal file
@@ -0,0 +1,282 @@
|
||||
package httpgateway
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/gateway"
|
||||
"github.com/SigNoz/signoz/pkg/http/client"
|
||||
"github.com/SigNoz/signoz/pkg/licensing"
|
||||
"github.com/SigNoz/signoz/pkg/types/gatewaytypes"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
settings factory.ScopedProviderSettings
|
||||
config gateway.Config
|
||||
httpClient *client.Client
|
||||
licensing licensing.Licensing
|
||||
}
|
||||
|
||||
func NewProviderFactory(licensing licensing.Licensing) factory.ProviderFactory[gateway.Gateway, gateway.Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("http"), func(ctx context.Context, ps factory.ProviderSettings, c gateway.Config) (gateway.Gateway, error) {
|
||||
return New(ctx, ps, c, licensing)
|
||||
})
|
||||
}
|
||||
|
||||
func New(ctx context.Context, providerSettings factory.ProviderSettings, config gateway.Config, licensing licensing.Licensing) (gateway.Gateway, error) {
|
||||
settings := factory.NewScopedProviderSettings(providerSettings, "github.com/SigNoz/signoz/ee/gateway/httpgateway")
|
||||
|
||||
httpClient, err := client.New(
|
||||
settings.Logger(),
|
||||
providerSettings.TracerProvider,
|
||||
providerSettings.MeterProvider,
|
||||
client.WithRequestResponseLog(true),
|
||||
client.WithRetryCount(3),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Provider{
|
||||
settings: settings,
|
||||
config: config,
|
||||
httpClient: httpClient,
|
||||
licensing: licensing,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (provider *Provider) GetIngestionKeys(ctx context.Context, orgID valuer.UUID, page, perPage int) (*gatewaytypes.GettableIngestionKeys, error) {
|
||||
qParams := url.Values{}
|
||||
qParams.Add("page", strconv.Itoa(page))
|
||||
qParams.Add("per_page", strconv.Itoa(perPage))
|
||||
|
||||
responseBody, err := provider.do(ctx, orgID, http.MethodGet, "/v1/workspaces/me/keys", qParams, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ingestionKeys []gatewaytypes.IngestionKey
|
||||
if err := json.Unmarshal([]byte(gjson.GetBytes(responseBody, "data").String()), &ingestionKeys); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var pagination gatewaytypes.Pagination
|
||||
if err := json.Unmarshal([]byte(gjson.GetBytes(responseBody, "_pagination").String()), &pagination); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &gatewaytypes.GettableIngestionKeys{
|
||||
Keys: ingestionKeys,
|
||||
Pagination: pagination,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (provider *Provider) SearchIngestionKeysByName(ctx context.Context, orgID valuer.UUID, name string, page, perPage int) (*gatewaytypes.GettableIngestionKeys, error) {
|
||||
qParams := url.Values{}
|
||||
qParams.Add("name", name)
|
||||
qParams.Add("page", strconv.Itoa(page))
|
||||
qParams.Add("per_page", strconv.Itoa(perPage))
|
||||
|
||||
responseBody, err := provider.do(ctx, orgID, http.MethodGet, "/v1/workspaces/me/keys/search", qParams, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ingestionKeys []gatewaytypes.IngestionKey
|
||||
if err := json.Unmarshal([]byte(gjson.GetBytes(responseBody, "data").String()), &ingestionKeys); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var pagination gatewaytypes.Pagination
|
||||
if err := json.Unmarshal([]byte(gjson.GetBytes(responseBody, "_pagination").String()), &pagination); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &gatewaytypes.GettableIngestionKeys{
|
||||
Keys: ingestionKeys,
|
||||
Pagination: pagination,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (provider *Provider) CreateIngestionKey(ctx context.Context, orgID valuer.UUID, name string, tags []string, expiresAt time.Time) (*gatewaytypes.GettableCreatedIngestionKey, error) {
|
||||
requestBody := gatewaytypes.PostableIngestionKey{
|
||||
Name: name,
|
||||
Tags: tags,
|
||||
ExpiresAt: expiresAt,
|
||||
}
|
||||
requestBodyBytes, err := json.Marshal(requestBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
responseBody, err := provider.do(ctx, orgID, http.MethodPost, "/v1/workspaces/me/keys", nil, requestBodyBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var createdKeyResponse gatewaytypes.GettableCreatedIngestionKey
|
||||
if err := json.Unmarshal([]byte(gjson.GetBytes(responseBody, "data").String()), &createdKeyResponse); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &createdKeyResponse, nil
|
||||
}
|
||||
|
||||
func (provider *Provider) UpdateIngestionKey(ctx context.Context, orgID valuer.UUID, keyID string, name string, tags []string, expiresAt time.Time) error {
|
||||
requestBody := gatewaytypes.PostableIngestionKey{
|
||||
Name: name,
|
||||
Tags: tags,
|
||||
ExpiresAt: expiresAt,
|
||||
}
|
||||
requestBodyBytes, err := json.Marshal(requestBody)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = provider.do(ctx, orgID, http.MethodPatch, "/v1/workspaces/me/keys/"+keyID, nil, requestBodyBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (provider *Provider) DeleteIngestionKey(ctx context.Context, orgID valuer.UUID, keyID string) error {
|
||||
_, err := provider.do(ctx, orgID, http.MethodDelete, "/v1/workspaces/me/keys/"+keyID, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (provider *Provider) CreateIngestionKeyLimit(ctx context.Context, orgID valuer.UUID, keyID string, signal string, limitConfig gatewaytypes.LimitConfig, tags []string) (*gatewaytypes.GettableCreatedIngestionKeyLimit, error) {
|
||||
requestBody := gatewaytypes.PostableIngestionKeyLimit{
|
||||
Signal: signal,
|
||||
Config: limitConfig,
|
||||
Tags: tags,
|
||||
}
|
||||
requestBodyBytes, err := json.Marshal(requestBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
responseBody, err := provider.do(ctx, orgID, http.MethodPost, "/v1/workspaces/me/keys/"+keyID+"/limits", nil, requestBodyBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var createdIngestionKeyLimitResponse gatewaytypes.GettableCreatedIngestionKeyLimit
|
||||
if err := json.Unmarshal([]byte(gjson.GetBytes(responseBody, "data").String()), &createdIngestionKeyLimitResponse); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &createdIngestionKeyLimitResponse, nil
|
||||
}
|
||||
|
||||
func (provider *Provider) UpdateIngestionKeyLimit(ctx context.Context, orgID valuer.UUID, limitID string, limitConfig gatewaytypes.LimitConfig, tags []string) error {
|
||||
requestBody := gatewaytypes.UpdatableIngestionKeyLimit{
|
||||
Config: limitConfig,
|
||||
Tags: tags,
|
||||
}
|
||||
requestBodyBytes, err := json.Marshal(requestBody)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = provider.do(ctx, orgID, http.MethodPatch, "/v1/workspaces/me/limits/"+limitID, nil, requestBodyBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (provider *Provider) DeleteIngestionKeyLimit(ctx context.Context, orgID valuer.UUID, limitID string) error {
|
||||
_, err := provider.do(ctx, orgID, http.MethodDelete, "/v1/workspaces/me/limits/"+limitID, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (provider *Provider) do(ctx context.Context, orgID valuer.UUID, method string, path string, queryParams url.Values, body []byte) ([]byte, error) {
|
||||
license, err := provider.licensing.GetActive(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, errors.New(errors.TypeLicenseUnavailable, errors.CodeLicenseUnavailable, "no valid license found").WithAdditional("this feature requires a valid license").WithAdditional(err.Error())
|
||||
}
|
||||
|
||||
// build url
|
||||
requestURL := provider.config.URL.JoinPath(path)
|
||||
|
||||
// add query params to the url
|
||||
if queryParams != nil {
|
||||
requestURL.RawQuery = queryParams.Encode()
|
||||
}
|
||||
|
||||
// build request
|
||||
request, err := http.NewRequestWithContext(ctx, method, requestURL.String(), bytes.NewBuffer(body))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// add headers needed to call gateway
|
||||
request.Header.Set("Content-Type", "application/json")
|
||||
request.Header.Set("X-Signoz-Cloud-Api-Key", license.Key)
|
||||
request.Header.Set("X-Consumer-Username", "lid:00000000-0000-0000-0000-000000000000")
|
||||
request.Header.Set("X-Consumer-Groups", "ns:default")
|
||||
|
||||
// execute request
|
||||
response, err := provider.httpClient.Do(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// read response
|
||||
defer response.Body.Close()
|
||||
responseBody, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// only 2XX
|
||||
if response.StatusCode/100 == 2 {
|
||||
return responseBody, nil
|
||||
}
|
||||
|
||||
errorMessage := gjson.GetBytes(responseBody, "error").String()
|
||||
if errorMessage == "" {
|
||||
errorMessage = "an unknown error occurred"
|
||||
}
|
||||
|
||||
// return error for non 2XX
|
||||
return nil, provider.errFromStatusCode(response.StatusCode, errorMessage)
|
||||
}
|
||||
|
||||
func (provider *Provider) errFromStatusCode(code int, errorMessage string) error {
|
||||
switch code {
|
||||
case http.StatusBadRequest:
|
||||
return errors.New(errors.TypeInvalidInput, errors.CodeInvalidInput, errorMessage)
|
||||
case http.StatusUnauthorized:
|
||||
return errors.New(errors.TypeUnauthenticated, errors.CodeUnauthenticated, errorMessage)
|
||||
case http.StatusForbidden:
|
||||
return errors.New(errors.TypeForbidden, errors.CodeForbidden, errorMessage)
|
||||
case http.StatusNotFound:
|
||||
return errors.New(errors.TypeNotFound, errors.CodeNotFound, errorMessage)
|
||||
case http.StatusConflict:
|
||||
return errors.New(errors.TypeAlreadyExists, errors.CodeAlreadyExists, errorMessage)
|
||||
}
|
||||
|
||||
return errors.New(errors.TypeInternal, errors.CodeInternal, errorMessage)
|
||||
}
|
||||
@@ -9,6 +9,8 @@ import (
|
||||
"github.com/SigNoz/signoz/ee/query-service/integrations/gateway"
|
||||
"github.com/SigNoz/signoz/ee/query-service/usage"
|
||||
"github.com/SigNoz/signoz/pkg/alertmanager"
|
||||
"github.com/SigNoz/signoz/pkg/apis/fields"
|
||||
"github.com/SigNoz/signoz/pkg/global"
|
||||
"github.com/SigNoz/signoz/pkg/http/middleware"
|
||||
querierAPI "github.com/SigNoz/signoz/pkg/querier"
|
||||
baseapp "github.com/SigNoz/signoz/pkg/query-service/app"
|
||||
@@ -35,6 +37,7 @@ type APIHandlerOptions struct {
|
||||
GatewayUrl string
|
||||
// Querier Influx Interval
|
||||
FluxInterval time.Duration
|
||||
GlobalConfig global.Config
|
||||
}
|
||||
|
||||
type APIHandler struct {
|
||||
@@ -53,6 +56,7 @@ func NewAPIHandler(opts APIHandlerOptions, signoz *signoz.SigNoz) (*APIHandler,
|
||||
FluxInterval: opts.FluxInterval,
|
||||
AlertmanagerAPI: alertmanager.NewAPI(signoz.Alertmanager),
|
||||
LicensingAPI: httplicensing.NewLicensingAPI(signoz.Licensing),
|
||||
FieldsAPI: fields.NewAPI(signoz.Instrumentation.ToProviderSettings(), signoz.TelemetryStore),
|
||||
Signoz: signoz,
|
||||
QuerierAPI: querierAPI.NewAPI(signoz.Instrumentation.ToProviderSettings(), signoz.Querier, signoz.Analytics),
|
||||
QueryParserAPI: queryparser.NewAPI(signoz.Instrumentation.ToProviderSettings(), signoz.QueryParser),
|
||||
|
||||
@@ -76,7 +76,7 @@ func (ah *APIHandler) CloudIntegrationsGenerateConnectionParams(w http.ResponseW
|
||||
return
|
||||
}
|
||||
|
||||
ingestionUrl, signozApiUrl, apiErr := ah.getIngestionUrlAndSigNozAPIUrl(r.Context(), license.Key)
|
||||
signozApiUrl, apiErr := ah.getIngestionUrlAndSigNozAPIUrl(r.Context(), license.Key)
|
||||
if apiErr != nil {
|
||||
RespondError(w, basemodel.WrapApiError(
|
||||
apiErr, "couldn't deduce ingestion url and signoz api url",
|
||||
@@ -84,7 +84,7 @@ func (ah *APIHandler) CloudIntegrationsGenerateConnectionParams(w http.ResponseW
|
||||
return
|
||||
}
|
||||
|
||||
result.IngestionUrl = ingestionUrl
|
||||
result.IngestionUrl = ah.opts.GlobalConfig.IngestionURL.String()
|
||||
result.SigNozAPIUrl = signozApiUrl
|
||||
|
||||
gatewayUrl := ah.opts.GatewayUrl
|
||||
@@ -186,7 +186,7 @@ func (ah *APIHandler) getOrCreateCloudIntegrationUser(
|
||||
}
|
||||
|
||||
func (ah *APIHandler) getIngestionUrlAndSigNozAPIUrl(ctx context.Context, licenseKey string) (
|
||||
string, string, *basemodel.ApiError,
|
||||
string, *basemodel.ApiError,
|
||||
) {
|
||||
// TODO: remove this struct from here
|
||||
type deploymentResponse struct {
|
||||
@@ -200,7 +200,7 @@ func (ah *APIHandler) getIngestionUrlAndSigNozAPIUrl(ctx context.Context, licens
|
||||
|
||||
respBytes, err := ah.Signoz.Zeus.GetDeployment(ctx, licenseKey)
|
||||
if err != nil {
|
||||
return "", "", basemodel.InternalError(fmt.Errorf(
|
||||
return "", basemodel.InternalError(fmt.Errorf(
|
||||
"couldn't query for deployment info: error: %w", err,
|
||||
))
|
||||
}
|
||||
@@ -209,7 +209,7 @@ func (ah *APIHandler) getIngestionUrlAndSigNozAPIUrl(ctx context.Context, licens
|
||||
|
||||
err = json.Unmarshal(respBytes, resp)
|
||||
if err != nil {
|
||||
return "", "", basemodel.InternalError(fmt.Errorf(
|
||||
return "", basemodel.InternalError(fmt.Errorf(
|
||||
"couldn't unmarshal deployment info response: error: %w", err,
|
||||
))
|
||||
}
|
||||
@@ -219,16 +219,14 @@ func (ah *APIHandler) getIngestionUrlAndSigNozAPIUrl(ctx context.Context, licens
|
||||
|
||||
if len(regionDns) < 1 || len(deploymentName) < 1 {
|
||||
// Fail early if actual response structure and expectation here ever diverge
|
||||
return "", "", basemodel.InternalError(fmt.Errorf(
|
||||
return "", basemodel.InternalError(fmt.Errorf(
|
||||
"deployment info response not in expected shape. couldn't determine region dns and deployment name",
|
||||
))
|
||||
}
|
||||
|
||||
ingestionUrl := fmt.Sprintf("https://ingest.%s", regionDns)
|
||||
|
||||
signozApiUrl := fmt.Sprintf("https://%s.%s", deploymentName, regionDns)
|
||||
|
||||
return ingestionUrl, signozApiUrl, nil
|
||||
return signozApiUrl, nil
|
||||
}
|
||||
|
||||
type ingestionKey struct {
|
||||
|
||||
@@ -172,6 +172,7 @@ func NewServer(config signoz.Config, signoz *signoz.SigNoz) (*Server, error) {
|
||||
FluxInterval: config.Querier.FluxInterval,
|
||||
Gateway: gatewayProxy,
|
||||
GatewayUrl: config.Gateway.URL.String(),
|
||||
GlobalConfig: config.Global,
|
||||
}
|
||||
|
||||
apiHandler, err := api.NewAPIHandler(apiOpts, signoz)
|
||||
@@ -236,6 +237,7 @@ func (s *Server) createPublicServer(apiHandler *api.APIHandler, web web.Web) (*h
|
||||
apiHandler.RegisterLogsRoutes(r, am)
|
||||
apiHandler.RegisterIntegrationRoutes(r, am)
|
||||
apiHandler.RegisterCloudIntegrationsRoutes(r, am)
|
||||
apiHandler.RegisterFieldsRoutes(r, am)
|
||||
apiHandler.RegisterQueryRangeV3Routes(r, am)
|
||||
apiHandler.RegisterInfraMetricsRoutes(r, am)
|
||||
apiHandler.RegisterQueryRangeV4Routes(r, am)
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
cd frontend && yarn run commitlint --edit $1
|
||||
# Convert $1 to absolute path before cd
|
||||
commit_msg_file="$(realpath "$1")"
|
||||
|
||||
cd frontend && yarn run commitlint "$commit_msg_file"
|
||||
|
||||
branch="$(git rev-parse --abbrev-ref HEAD)"
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
FixedDurationSuggestionOptions,
|
||||
Options,
|
||||
RelativeDurationSuggestionOptions,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
} from 'container/TopNav/DateTimeSelectionV2/constants';
|
||||
import dayjs from 'dayjs';
|
||||
import { isValidShortHandDateTimeFormat } from 'lib/getMinMax';
|
||||
import { defaultTo, isFunction, noop } from 'lodash-es';
|
||||
|
||||
@@ -8,11 +8,11 @@ import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
|
||||
import { QueryParams } from 'constants/query';
|
||||
import ROUTES from 'constants/routes';
|
||||
import { DateTimeRangeType } from 'container/TopNav/CustomDateTimeModal';
|
||||
import { RelativeDurationSuggestionOptions } from 'container/TopNav/DateTimeSelectionV2/constants';
|
||||
import {
|
||||
LexicalContext,
|
||||
Option,
|
||||
RelativeDurationSuggestionOptions,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import dayjs from 'dayjs';
|
||||
import { Clock, PenLine, TriangleAlertIcon } from 'lucide-react';
|
||||
import { useTimezone } from 'providers/Timezone';
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
CustomTimeType,
|
||||
LexicalContext,
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import dayjs, { Dayjs } from 'dayjs';
|
||||
import { useTimezone } from 'providers/Timezone';
|
||||
import { Dispatch, SetStateAction, useMemo } from 'react';
|
||||
|
||||
@@ -13,7 +13,7 @@ import DateTimeSelectionV2 from 'container/TopNav/DateTimeSelectionV2';
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import TraceExplorerControls from 'container/TracesExplorer/Controls';
|
||||
import { PER_PAGE_OPTIONS } from 'container/TracesExplorer/ListView/configs';
|
||||
import { TracesLoading } from 'container/TracesExplorer/TraceLoading/TraceLoading';
|
||||
|
||||
@@ -24,7 +24,7 @@ import { INFRA_MONITORING_K8S_PARAMS_KEYS } from 'container/InfraMonitoringK8s/c
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import GetMinMax from 'lib/getMinMax';
|
||||
|
||||
@@ -5,7 +5,7 @@ import DateTimeSelectionV2 from 'container/TopNav/DateTimeSelectionV2';
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useMemo } from 'react';
|
||||
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
@@ -12,7 +12,7 @@ import DateTimeSelectionV2 from 'container/TopNav/DateTimeSelectionV2';
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import { useResizeObserver } from 'hooks/useDimensions';
|
||||
|
||||
@@ -7,7 +7,7 @@ import DateTimeSelectionV2 from 'container/TopNav/DateTimeSelectionV2';
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import GetMinMax from 'lib/getMinMax';
|
||||
import { ArrowDown, ArrowUp, X } from 'lucide-react';
|
||||
|
||||
@@ -13,7 +13,7 @@ import QueryBuilderSearchV2 from 'container/QueryBuilder/filters/QueryBuilderSea
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { GetMetricQueryRange } from 'lib/dashboard/getQueryResults';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useQueries } from 'react-query';
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { useQueries } from 'react-query';
|
||||
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import {
|
||||
|
||||
@@ -37,10 +37,7 @@ function ThresholdItem({
|
||||
);
|
||||
if (units.length === 0) {
|
||||
component = (
|
||||
<Tooltip
|
||||
trigger="hover"
|
||||
title="Please select a Y-axis unit for the query first"
|
||||
>
|
||||
<Tooltip trigger="hover" title="No compatible units available">
|
||||
<Select
|
||||
placeholder="Unit"
|
||||
value={threshold.unit ? threshold.unit : null}
|
||||
|
||||
@@ -47,9 +47,17 @@ export function getCategoryByOptionId(id: string): string | undefined {
|
||||
}
|
||||
|
||||
export function getCategorySelectOptionByName(
|
||||
name: string,
|
||||
name: string | undefined,
|
||||
): DefaultOptionType[] {
|
||||
if (!name) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const categories = getYAxisCategories(YAxisSource.ALERTS);
|
||||
if (!categories.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return (
|
||||
categories
|
||||
.find((category) => category.name === name)
|
||||
|
||||
@@ -15,11 +15,10 @@ import GridPanelSwitch from 'container/GridPanelSwitch';
|
||||
import { populateMultipleResults } from 'container/NewWidget/LeftContainer/WidgetGraph/util';
|
||||
import { getFormatNameByOptionId } from 'container/NewWidget/RightContainer/alertFomatCategories';
|
||||
import { timePreferenceType } from 'container/NewWidget/RightContainer/timeItems';
|
||||
import { Time } from 'container/TopNav/DateTimeSelection/config';
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time as TimeV2,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
@@ -60,7 +59,7 @@ export interface ChartPreviewProps {
|
||||
query: Query | null;
|
||||
graphType?: PANEL_TYPES;
|
||||
selectedTime?: timePreferenceType;
|
||||
selectedInterval?: Time | TimeV2 | CustomTimeType;
|
||||
selectedInterval?: Time | CustomTimeType;
|
||||
headline?: JSX.Element;
|
||||
alertDef?: AlertDef;
|
||||
userQueryKey?: string;
|
||||
|
||||
@@ -4,3 +4,7 @@
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.rule-unit-selector {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
@@ -15,8 +15,7 @@ import { DefaultOptionType } from 'antd/es/select';
|
||||
import {
|
||||
getCategoryByOptionId,
|
||||
getCategorySelectOptionByName,
|
||||
} from 'container/NewWidget/RightContainer/alertFomatCategories';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
} from 'container/CreateAlertV2/AlertCondition/utils';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
AlertDef,
|
||||
@@ -43,10 +42,10 @@ function RuleOptions({
|
||||
setAlertDef,
|
||||
queryCategory,
|
||||
queryOptions,
|
||||
yAxisUnit,
|
||||
}: RuleOptionsProps): JSX.Element {
|
||||
// init namespace for translations
|
||||
const { t } = useTranslation('alerts');
|
||||
const { currentQuery } = useQueryBuilder();
|
||||
|
||||
const { ruleType } = alertDef;
|
||||
|
||||
@@ -365,11 +364,9 @@ function RuleOptions({
|
||||
</InlineSelect>
|
||||
);
|
||||
|
||||
const selectedCategory = getCategoryByOptionId(currentQuery?.unit || '');
|
||||
const selectedCategory = getCategoryByOptionId(yAxisUnit);
|
||||
|
||||
const categorySelectOptions = getCategorySelectOptionByName(
|
||||
selectedCategory?.name,
|
||||
);
|
||||
const categorySelectOptions = getCategorySelectOptionByName(selectedCategory);
|
||||
|
||||
const step3Label = alertDef.alertType === 'METRIC_BASED_ALERT' ? '3' : '2';
|
||||
|
||||
@@ -402,6 +399,7 @@ function RuleOptions({
|
||||
|
||||
<Form.Item noStyle>
|
||||
<Select
|
||||
className="rule-unit-selector"
|
||||
getPopupContainer={popupContainer}
|
||||
allowClear
|
||||
showSearch
|
||||
@@ -515,5 +513,6 @@ interface RuleOptionsProps {
|
||||
setAlertDef: (a: AlertDef) => void;
|
||||
queryCategory: EQueryType;
|
||||
queryOptions: DefaultOptionType[];
|
||||
yAxisUnit: string;
|
||||
}
|
||||
export default RuleOptions;
|
||||
|
||||
@@ -914,6 +914,7 @@ function FormAlertRules({
|
||||
alertDef={alertDef}
|
||||
setAlertDef={setAlertDef}
|
||||
queryOptions={queryOptions}
|
||||
yAxisUnit={yAxisUnit || ''}
|
||||
/>
|
||||
|
||||
{renderBasicInfo()}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { SelectProps } from 'antd';
|
||||
import { Time } from 'container/TopNav/DateTimeSelection/config';
|
||||
import { Time } from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import getStartEndRangeTime from 'lib/getStartEndRangeTime';
|
||||
import getStep from 'lib/getStep';
|
||||
import {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { DEFAULT_ENTITY_VERSION, ENTITY_VERSION_V5 } from 'constants/app';
|
||||
import { QueryParams } from 'constants/query';
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { populateMultipleResults } from 'container/NewWidget/LeftContainer/WidgetGraph/util';
|
||||
import { CustomTimeType } from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
import { CustomTimeType } from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
||||
import { useIntersectionObserver } from 'hooks/useIntersectionObserver';
|
||||
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
|
||||
|
||||
@@ -26,7 +26,7 @@ import { QUERY_KEYS } from 'container/InfraMonitoringK8s/EntityDetailsUtils/util
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import GetMinMax from 'lib/getMinMax';
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import GetMinMax from 'lib/getMinMax';
|
||||
|
||||
@@ -26,7 +26,7 @@ import { QUERY_KEYS } from 'container/InfraMonitoringK8s/EntityDetailsUtils/util
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import GetMinMax from 'lib/getMinMax';
|
||||
|
||||
@@ -16,7 +16,7 @@ import DateTimeSelectionV2 from 'container/TopNav/DateTimeSelectionV2';
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { GetMetricQueryRange } from 'lib/dashboard/getQueryResults';
|
||||
import { isArray } from 'lodash-es';
|
||||
|
||||
@@ -4,7 +4,7 @@ import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import { initialQueriesMap } from 'constants/queryBuilder';
|
||||
import ROUTES from 'constants/routes';
|
||||
import { K8sCategory } from 'container/InfraMonitoringK8s/constants';
|
||||
import { Time } from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
import { Time } from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import * as useQueryBuilderHooks from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import * as appContextHooks from 'providers/App/App';
|
||||
import { LicenseEvent } from 'types/api/licensesV3/getActive';
|
||||
|
||||
@@ -7,7 +7,7 @@ import DateTimeSelectionV2 from 'container/TopNav/DateTimeSelectionV2';
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useMemo } from 'react';
|
||||
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
@@ -14,7 +14,7 @@ import DateTimeSelectionV2 from 'container/TopNav/DateTimeSelectionV2';
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import { useResizeObserver } from 'hooks/useDimensions';
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
/* eslint-disable sonarjs/no-duplicate-string */
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { K8sCategory } from 'container/InfraMonitoringK8s/constants';
|
||||
import { Time } from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
import { Time } from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import * as appContextHooks from 'providers/App/App';
|
||||
import { LicenseEvent } from 'types/api/licensesV3/getActive';
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import DateTimeSelectionV2 from 'container/TopNav/DateTimeSelectionV2';
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import TraceExplorerControls from 'container/TracesExplorer/Controls';
|
||||
import { PER_PAGE_OPTIONS } from 'container/TracesExplorer/ListView/configs';
|
||||
import { TracesLoading } from 'container/TracesExplorer/TraceLoading/TraceLoading';
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { initialQueriesMap } from 'constants/queryBuilder';
|
||||
import { K8sCategory } from 'container/InfraMonitoringK8s/constants';
|
||||
import { Time } from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
import { Time } from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import * as useQueryBuilderHooks from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import * as appContextHooks from 'providers/App/App';
|
||||
import { LicenseEvent } from 'types/api/licensesV3/getActive';
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import GetMinMax from 'lib/getMinMax';
|
||||
|
||||
@@ -23,7 +23,7 @@ import { QUERY_KEYS } from 'container/InfraMonitoringK8s/EntityDetailsUtils/util
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import GetMinMax from 'lib/getMinMax';
|
||||
|
||||
@@ -26,7 +26,7 @@ import NodeEvents from 'container/InfraMonitoringK8s/EntityDetailsUtils/EntityEv
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import GetMinMax from 'lib/getMinMax';
|
||||
|
||||
@@ -27,7 +27,7 @@ import { QUERY_KEYS } from 'container/InfraMonitoringK8s/EntityDetailsUtils/util
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import GetMinMax from 'lib/getMinMax';
|
||||
|
||||
@@ -26,7 +26,7 @@ import { QUERY_KEYS } from 'container/InfraMonitoringK8s/EntityDetailsUtils/util
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import GetMinMax from 'lib/getMinMax';
|
||||
|
||||
@@ -9,7 +9,7 @@ import { K8sCategory } from 'container/InfraMonitoringK8s/constants';
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import GetMinMax from 'lib/getMinMax';
|
||||
import { X } from 'lucide-react';
|
||||
|
||||
@@ -4,7 +4,7 @@ import NewExplorerCTA from 'container/NewExplorerCTA';
|
||||
import { FileText } from 'lucide-react';
|
||||
import { useLocation } from 'react-use';
|
||||
|
||||
import DateTimeSelector from '../TopNav/DateTimeSelection';
|
||||
import DateTimeSelector from '../TopNav/DateTimeSelectionV2';
|
||||
import { Container } from './styles';
|
||||
import { LocalTopNavProps } from './types';
|
||||
|
||||
@@ -37,7 +37,7 @@ function LocalTopNav({
|
||||
{actions}
|
||||
{renderPermissions?.isDateTimeEnabled && (
|
||||
<div>
|
||||
<DateTimeSelector />
|
||||
<DateTimeSelector showAutoRefresh={false} />
|
||||
</div>
|
||||
)}
|
||||
</Space>
|
||||
|
||||
@@ -4,9 +4,9 @@ import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
|
||||
import Controls from 'container/Controls';
|
||||
import Download from 'container/Download/Download';
|
||||
import { getGlobalTime } from 'container/LogsSearchFilter/utils';
|
||||
import { getMinMax } from 'container/TopNav/AutoRefresh/config';
|
||||
import dayjs from 'dayjs';
|
||||
import { Pagination } from 'hooks/queryPagination';
|
||||
import { getMinMaxForSelectedTime } from 'lib/getMinMax';
|
||||
import { FlatLogData } from 'lib/logs/flatLogData';
|
||||
import { OrderPreferenceItems } from 'pages/Logs/config';
|
||||
import { memo, useMemo } from 'react';
|
||||
@@ -50,7 +50,7 @@ function LogControls(): JSX.Element | null {
|
||||
};
|
||||
|
||||
const handleGoToLatest = (): void => {
|
||||
const { maxTime, minTime } = getMinMax(
|
||||
const { maxTime, minTime } = getMinMaxForSelectedTime(
|
||||
globalTime.selectedTime,
|
||||
globalTime.minTime,
|
||||
globalTime.maxTime,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { QueryParams } from 'constants/query';
|
||||
import { getMinMax } from 'container/TopNav/AutoRefresh/config';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { getMinMaxForSelectedTime } from 'lib/getMinMax';
|
||||
import history from 'lib/history';
|
||||
import { parseQuery } from 'lib/logql';
|
||||
import isEqual from 'lodash-es/isEqual';
|
||||
@@ -44,7 +44,7 @@ export function useSearchParser(): {
|
||||
search: `?${QueryParams.q}=${updatedQueryString}&${QueryParams.order}=${order}`,
|
||||
});
|
||||
|
||||
const globalTime = getMinMax(selectedTime, minTime, maxTime);
|
||||
const globalTime = getMinMaxForSelectedTime(selectedTime, minTime, maxTime);
|
||||
|
||||
dispatch({
|
||||
type: SET_SEARCH_QUERY_STRING,
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { Time } from 'container/TopNav/DateTimeSelection/config';
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time as TimeV2,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { GetMinMaxPayload } from 'lib/getMinMax';
|
||||
|
||||
export const getGlobalTime = (
|
||||
selectedTime: Time | TimeV2 | CustomTimeType,
|
||||
selectedTime: Time | CustomTimeType,
|
||||
globalTime: GetMinMaxPayload,
|
||||
): GetMinMaxPayload | undefined => {
|
||||
if (selectedTime === 'custom') {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { handleGraphClick } from 'container/GridCardLayout/GridCard/utils';
|
||||
import { useGraphClickToShowButton } from 'container/GridCardLayout/useGraphClickToShowButton';
|
||||
import useNavigateToExplorerPages from 'container/GridCardLayout/useNavigateToExplorerPages';
|
||||
import PanelWrapper from 'container/PanelWrapper/PanelWrapper';
|
||||
import { CustomTimeType } from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
import { CustomTimeType } from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import { useSafeNavigate } from 'hooks/useSafeNavigate';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import './styles.scss';
|
||||
|
||||
import { RelativeDurationOptions } from 'container/TopNav/DateTimeSelection/config';
|
||||
import { RelativeDurationOptions } from 'container/TopNav/DateTimeSelectionV2/constants';
|
||||
import { useState } from 'react';
|
||||
import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import './styles.scss';
|
||||
|
||||
import { RelativeDurationOptions } from 'container/TopNav/DateTimeSelection/config';
|
||||
import { RelativeDurationOptions } from 'container/TopNav/DateTimeSelectionV2/constants';
|
||||
import { useState } from 'react';
|
||||
import { PipelineData } from 'types/api/pipeline/def';
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
initialQueriesMap,
|
||||
PANEL_TYPES,
|
||||
} from 'constants/queryBuilder';
|
||||
import { Time } from 'container/TopNav/DateTimeSelection/config';
|
||||
import { Time } from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
||||
import cloneDeep from 'lodash-es/cloneDeep';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import './styles.scss';
|
||||
|
||||
import { Select } from 'antd';
|
||||
import {
|
||||
RelativeDurationOptions,
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelection/config';
|
||||
import { RelativeDurationOptions } from 'container/TopNav/DateTimeSelectionV2/constants';
|
||||
import { Time } from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
import LogsCountInInterval from './components/LogsCountInInterval';
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
initialQueriesMap,
|
||||
PANEL_TYPES,
|
||||
} from 'constants/queryBuilder';
|
||||
import { Time } from 'container/TopNav/DateTimeSelection/config';
|
||||
import { Time } from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
||||
import cloneDeep from 'lodash-es/cloneDeep';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
@@ -9,7 +9,7 @@ import DateTimeSelectionV2 from 'container/TopNav/DateTimeSelectionV2';
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import dayjs from 'dayjs';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import GetMinMax from 'lib/getMinMax';
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { ServiceDataProps } from 'api/metrics/getTopLevelOperations';
|
||||
import { Time } from 'container/TopNav/DateTimeSelection/config';
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time as TimeV2,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
|
||||
import { UseQueryResult } from 'react-query';
|
||||
import { SuccessResponse } from 'types/api';
|
||||
@@ -26,7 +25,7 @@ export interface ServiceMetricsTableProps {
|
||||
|
||||
export interface GetQueryRangeRequestDataProps {
|
||||
topLevelOperations: [keyof ServiceDataProps, string[]][];
|
||||
globalSelectedInterval: Time | TimeV2 | CustomTimeType;
|
||||
globalSelectedInterval: Time | CustomTimeType;
|
||||
dotMetricsEnabled: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import { LogsLoading } from 'container/LogsLoading/LogsLoading';
|
||||
import EmptyMetricsSearch from 'container/MetricsExplorer/Explorer/EmptyMetricsSearch';
|
||||
import { MetricsLoading } from 'container/MetricsExplorer/MetricsLoading/MetricsLoading';
|
||||
import NoLogs from 'container/NoLogs/NoLogs';
|
||||
import { CustomTimeType } from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
import { CustomTimeType } from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { TracesLoading } from 'container/TracesExplorer/TraceLoading/TraceLoading';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
import GetMinMax, { GetMinMaxPayload } from 'lib/getMinMax';
|
||||
|
||||
import { Time } from '../DateTimeSelection/config';
|
||||
import { CustomTimeType, Time as TimeV2 } from '../DateTimeSelectionV2/config';
|
||||
|
||||
export const options: IOptions[] = [
|
||||
{
|
||||
label: 'off',
|
||||
key: 'off',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: '5s',
|
||||
key: '5s',
|
||||
value: 5000,
|
||||
},
|
||||
{
|
||||
label: '10s',
|
||||
key: '10s',
|
||||
value: 10000,
|
||||
},
|
||||
{
|
||||
label: '30s',
|
||||
key: '30s',
|
||||
value: 30000,
|
||||
},
|
||||
{
|
||||
label: '1m',
|
||||
key: '1m',
|
||||
value: 60000,
|
||||
},
|
||||
{
|
||||
label: '5m',
|
||||
key: '5m',
|
||||
value: 300000,
|
||||
},
|
||||
{
|
||||
label: '10m',
|
||||
key: '10m',
|
||||
value: 600000,
|
||||
},
|
||||
{
|
||||
label: '30m',
|
||||
key: '30m',
|
||||
value: 1800000,
|
||||
},
|
||||
{
|
||||
label: '1h',
|
||||
key: '1h',
|
||||
value: 3600000,
|
||||
},
|
||||
{
|
||||
label: '2h',
|
||||
key: '2h',
|
||||
value: 7200000,
|
||||
},
|
||||
{
|
||||
label: '1d',
|
||||
key: '1d',
|
||||
value: 86400000,
|
||||
},
|
||||
];
|
||||
|
||||
export interface IOptions {
|
||||
label: string;
|
||||
key: string;
|
||||
value: number;
|
||||
}
|
||||
|
||||
export const getMinMax = (
|
||||
selectedTime: Time | TimeV2 | CustomTimeType,
|
||||
minTime: number,
|
||||
maxTime: number,
|
||||
): GetMinMaxPayload =>
|
||||
selectedTime !== 'custom'
|
||||
? GetMinMax(selectedTime)
|
||||
: GetMinMax(selectedTime, [minTime, maxTime]);
|
||||
@@ -1,202 +0,0 @@
|
||||
import { CaretDownFilled } from '@ant-design/icons';
|
||||
import {
|
||||
Checkbox,
|
||||
Divider,
|
||||
Popover,
|
||||
Radio,
|
||||
RadioChangeEvent,
|
||||
Space,
|
||||
Typography,
|
||||
} from 'antd';
|
||||
import { CheckboxChangeEvent } from 'antd/lib/checkbox';
|
||||
import get from 'api/browser/localstorage/get';
|
||||
import set from 'api/browser/localstorage/set';
|
||||
import { DASHBOARD_TIME_IN_DURATION } from 'constants/app';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import _omit from 'lodash-es/omit';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { useInterval } from 'react-use';
|
||||
import { Dispatch } from 'redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import AppActions from 'types/actions';
|
||||
import {
|
||||
UPDATE_AUTO_REFRESH_INTERVAL,
|
||||
UPDATE_TIME_INTERVAL,
|
||||
} from 'types/actions/globalTime';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import { popupContainer } from 'utils/selectPopupContainer';
|
||||
|
||||
import { getMinMax, options } from './config';
|
||||
import { ButtonContainer, Container } from './styles';
|
||||
|
||||
function AutoRefresh({
|
||||
disabled = false,
|
||||
showAutoRefreshBtnPrimary = true,
|
||||
}: AutoRefreshProps): JSX.Element {
|
||||
const globalTime = useSelector<AppState, GlobalReducer>(
|
||||
(state) => state.globalTime,
|
||||
);
|
||||
const { pathname } = useLocation();
|
||||
|
||||
const isDisabled = useMemo(
|
||||
() =>
|
||||
disabled ||
|
||||
globalTime.isAutoRefreshDisabled ||
|
||||
globalTime.selectedTime === 'custom',
|
||||
[globalTime.isAutoRefreshDisabled, disabled, globalTime.selectedTime],
|
||||
);
|
||||
|
||||
const localStorageData = JSON.parse(get(DASHBOARD_TIME_IN_DURATION) || '{}');
|
||||
|
||||
const localStorageValue = useMemo(() => localStorageData[pathname], [
|
||||
pathname,
|
||||
localStorageData,
|
||||
]);
|
||||
|
||||
const [isAutoRefreshEnabled, setIsAutoRefreshfreshEnabled] = useState<boolean>(
|
||||
Boolean(localStorageValue),
|
||||
);
|
||||
|
||||
const dispatch = useDispatch<Dispatch<AppActions>>();
|
||||
|
||||
useEffect(() => {
|
||||
const isAutoRefreshEnabled = Boolean(localStorageValue);
|
||||
dispatch({
|
||||
type: UPDATE_AUTO_REFRESH_INTERVAL,
|
||||
payload: localStorageValue,
|
||||
});
|
||||
setIsAutoRefreshfreshEnabled(isAutoRefreshEnabled);
|
||||
}, [localStorageValue, dispatch]);
|
||||
|
||||
const params = useUrlQuery();
|
||||
|
||||
const [selectedOption, setSelectedOption] = useState<string>(
|
||||
localStorageValue || options[0].key,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedOption(localStorageValue || options[0].key);
|
||||
}, [localStorageValue, params]);
|
||||
|
||||
const getOption = useMemo(
|
||||
() => options.find((option) => option.key === selectedOption),
|
||||
[selectedOption],
|
||||
);
|
||||
|
||||
useInterval(() => {
|
||||
const selectedValue = getOption?.value;
|
||||
|
||||
if (isDisabled || !isAutoRefreshEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedOption !== 'off' && selectedValue) {
|
||||
const { maxTime, minTime } = getMinMax(
|
||||
globalTime.selectedTime,
|
||||
globalTime.minTime,
|
||||
globalTime.maxTime,
|
||||
);
|
||||
|
||||
dispatch({
|
||||
type: UPDATE_TIME_INTERVAL,
|
||||
payload: {
|
||||
maxTime,
|
||||
minTime,
|
||||
selectedTime: globalTime.selectedTime,
|
||||
},
|
||||
});
|
||||
}
|
||||
}, getOption?.value || 0);
|
||||
|
||||
const onChangeHandler = useCallback(
|
||||
(event: RadioChangeEvent) => {
|
||||
const selectedValue = event.target.value;
|
||||
setSelectedOption(selectedValue);
|
||||
params.set(DASHBOARD_TIME_IN_DURATION, selectedValue);
|
||||
set(
|
||||
DASHBOARD_TIME_IN_DURATION,
|
||||
JSON.stringify({ ...localStorageData, [pathname]: selectedValue }),
|
||||
);
|
||||
setIsAutoRefreshfreshEnabled(true);
|
||||
},
|
||||
[params, pathname, localStorageData],
|
||||
);
|
||||
|
||||
const onChangeAutoRefreshHandler = useCallback(
|
||||
(event: CheckboxChangeEvent) => {
|
||||
const { checked } = event.target;
|
||||
if (!checked) {
|
||||
// remove the path from localstorage
|
||||
set(
|
||||
DASHBOARD_TIME_IN_DURATION,
|
||||
JSON.stringify(_omit(localStorageData, pathname)),
|
||||
);
|
||||
}
|
||||
setIsAutoRefreshfreshEnabled(checked);
|
||||
},
|
||||
[localStorageData, pathname],
|
||||
);
|
||||
|
||||
if (globalTime.selectedTime === 'custom') {
|
||||
// eslint-disable-next-line react/jsx-no-useless-fragment
|
||||
return <></>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Popover
|
||||
getPopupContainer={popupContainer}
|
||||
placement="bottomLeft"
|
||||
trigger={['click']}
|
||||
content={
|
||||
<Container>
|
||||
<Checkbox
|
||||
onChange={onChangeAutoRefreshHandler}
|
||||
checked={isAutoRefreshEnabled}
|
||||
disabled={isDisabled}
|
||||
>
|
||||
Auto Refresh
|
||||
</Checkbox>
|
||||
|
||||
<Divider />
|
||||
|
||||
<Typography.Paragraph disabled={isDisabled}>
|
||||
Refresh Interval
|
||||
</Typography.Paragraph>
|
||||
|
||||
<Radio.Group onChange={onChangeHandler} value={selectedOption}>
|
||||
<Space direction="vertical">
|
||||
{options
|
||||
.filter((e) => e.label !== 'off')
|
||||
.map((option) => (
|
||||
<Radio disabled={isDisabled} key={option.key} value={option.key}>
|
||||
{option.label}
|
||||
</Radio>
|
||||
))}
|
||||
</Space>
|
||||
</Radio.Group>
|
||||
</Container>
|
||||
}
|
||||
>
|
||||
<ButtonContainer
|
||||
title="Set auto refresh"
|
||||
type={showAutoRefreshBtnPrimary ? 'primary' : 'default'}
|
||||
>
|
||||
<CaretDownFilled />
|
||||
</ButtonContainer>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
||||
interface AutoRefreshProps {
|
||||
disabled?: boolean;
|
||||
showAutoRefreshBtnPrimary?: boolean;
|
||||
}
|
||||
|
||||
AutoRefresh.defaultProps = {
|
||||
disabled: false,
|
||||
showAutoRefreshBtnPrimary: true,
|
||||
};
|
||||
|
||||
export default AutoRefresh;
|
||||
@@ -1,13 +0,0 @@
|
||||
import { Button } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const Container = styled.div`
|
||||
min-width: 8rem;
|
||||
`;
|
||||
|
||||
export const ButtonContainer = styled(Button)`
|
||||
&&& {
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
`;
|
||||
@@ -1,9 +1,10 @@
|
||||
import GetMinMax, { GetMinMaxPayload } from 'lib/getMinMax';
|
||||
export interface IOptions {
|
||||
label: string;
|
||||
key: string;
|
||||
value: number;
|
||||
}
|
||||
|
||||
import { Time } from '../DateTimeSelection/config';
|
||||
import { CustomTimeType, Time as TimeV2 } from '../DateTimeSelectionV2/config';
|
||||
|
||||
export const options: IOptions[] = [
|
||||
export const refreshIntervalOptions: IOptions[] = [
|
||||
{
|
||||
label: 'off',
|
||||
key: 'off',
|
||||
@@ -60,18 +61,3 @@ export const options: IOptions[] = [
|
||||
value: 86400000,
|
||||
},
|
||||
];
|
||||
|
||||
export interface IOptions {
|
||||
label: string;
|
||||
key: string;
|
||||
value: number;
|
||||
}
|
||||
|
||||
export const getMinMax = (
|
||||
selectedTime: Time | TimeV2 | CustomTimeType,
|
||||
minTime: number,
|
||||
maxTime: number,
|
||||
): GetMinMaxPayload =>
|
||||
selectedTime !== 'custom'
|
||||
? GetMinMax(selectedTime)
|
||||
: GetMinMax(selectedTime, [minTime, maxTime]);
|
||||
@@ -7,6 +7,7 @@ import get from 'api/browser/localstorage/get';
|
||||
import set from 'api/browser/localstorage/set';
|
||||
import { DASHBOARD_TIME_IN_DURATION } from 'constants/app';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { getMinMaxForSelectedTime } from 'lib/getMinMax';
|
||||
import _omit from 'lodash-es/omit';
|
||||
import { Check } from 'lucide-react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
@@ -23,7 +24,7 @@ import {
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import { popupContainer } from 'utils/selectPopupContainer';
|
||||
|
||||
import { getMinMax, options } from './config';
|
||||
import { refreshIntervalOptions } from './constants';
|
||||
import { ButtonContainer } from './styles';
|
||||
|
||||
const DEFAULT_REFRESH_INTERVAL = '30s';
|
||||
@@ -70,20 +71,23 @@ function AutoRefresh({
|
||||
const params = useUrlQuery();
|
||||
|
||||
const defaultOption = useMemo(
|
||||
() => options.find((option) => option.key === DEFAULT_REFRESH_INTERVAL),
|
||||
() =>
|
||||
refreshIntervalOptions.find(
|
||||
(option) => option.key === DEFAULT_REFRESH_INTERVAL,
|
||||
),
|
||||
[],
|
||||
);
|
||||
|
||||
const [selectedOption, setSelectedOption] = useState<string>(
|
||||
localStorageValue || options[0].key,
|
||||
localStorageValue || refreshIntervalOptions[0].key,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedOption(localStorageValue || options[0].key);
|
||||
setSelectedOption(localStorageValue || refreshIntervalOptions[0].key);
|
||||
}, [localStorageValue, params, defaultOption]);
|
||||
|
||||
const getOption = useMemo(
|
||||
() => options.find((option) => option.key === selectedOption),
|
||||
() => refreshIntervalOptions.find((option) => option.key === selectedOption),
|
||||
[selectedOption],
|
||||
);
|
||||
|
||||
@@ -95,7 +99,7 @@ function AutoRefresh({
|
||||
}
|
||||
|
||||
if (selectedOption !== 'off' && selectedValue) {
|
||||
const { maxTime, minTime } = getMinMax(
|
||||
const { maxTime, minTime } = getMinMaxForSelectedTime(
|
||||
globalTime.selectedTime,
|
||||
globalTime.minTime,
|
||||
globalTime.maxTime,
|
||||
@@ -175,7 +179,7 @@ function AutoRefresh({
|
||||
>
|
||||
Refresh Interval
|
||||
</Typography.Paragraph>
|
||||
{options
|
||||
{refreshIntervalOptions
|
||||
.filter((e) => e.label !== 'off')
|
||||
.map((option) => (
|
||||
<Button
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
.date-time-selection-container {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { RefreshTextContainer, Typography } from './styles';
|
||||
|
||||
function RefreshText({
|
||||
onLastRefreshHandler,
|
||||
refreshButtonHidden,
|
||||
}: RefreshTextProps): JSX.Element {
|
||||
const [refreshText, setRefreshText] = useState<string>('');
|
||||
|
||||
// this is to update the refresh text
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
const text = onLastRefreshHandler();
|
||||
if (refreshText !== text) {
|
||||
setRefreshText(text);
|
||||
}
|
||||
}, 2000);
|
||||
return (): void => {
|
||||
clearInterval(interval);
|
||||
};
|
||||
}, [onLastRefreshHandler, refreshText]);
|
||||
|
||||
return (
|
||||
<RefreshTextContainer refreshButtonHidden={refreshButtonHidden}>
|
||||
<Typography>{refreshText}</Typography>
|
||||
</RefreshTextContainer>
|
||||
);
|
||||
}
|
||||
|
||||
interface RefreshTextProps {
|
||||
onLastRefreshHandler: () => string;
|
||||
refreshButtonHidden: boolean;
|
||||
}
|
||||
|
||||
export default RefreshText;
|
||||
@@ -1,143 +0,0 @@
|
||||
import ROUTES from 'constants/routes';
|
||||
|
||||
type FiveMin = '5m';
|
||||
type TenMin = '10m';
|
||||
type FifteenMin = '15m';
|
||||
type ThirtyMin = '30m';
|
||||
type OneMin = '1m';
|
||||
type SixHour = '6h';
|
||||
type OneHour = '1h';
|
||||
type FourHour = '4h';
|
||||
type ThreeHour = '3h';
|
||||
type TwelveHour = '12h';
|
||||
type OneDay = '1d';
|
||||
type ThreeDay = '3d';
|
||||
type OneWeek = '1w';
|
||||
type Custom = 'custom';
|
||||
|
||||
export type Time =
|
||||
| FiveMin
|
||||
| TenMin
|
||||
| FifteenMin
|
||||
| ThirtyMin
|
||||
| OneMin
|
||||
| FourHour
|
||||
| SixHour
|
||||
| OneHour
|
||||
| ThreeHour
|
||||
| Custom
|
||||
| OneWeek
|
||||
| OneDay
|
||||
| TwelveHour
|
||||
| ThreeDay;
|
||||
|
||||
export const Options: Option[] = [
|
||||
{ value: '5m', label: 'Last 5 min' },
|
||||
{ value: '15m', label: 'Last 15 min' },
|
||||
{ value: '30m', label: 'Last 30 min' },
|
||||
{ value: '1h', label: 'Last 1 hour' },
|
||||
{ value: '6h', label: 'Last 6 hour' },
|
||||
{ value: '1d', label: 'Last 1 day' },
|
||||
{ value: '3d', label: 'Last 3 days' },
|
||||
{ value: '1w', label: 'Last 1 week' },
|
||||
{ value: 'custom', label: 'Custom' },
|
||||
];
|
||||
|
||||
type TimeFrame = {
|
||||
'5min': string;
|
||||
'15min': string;
|
||||
'30min': string;
|
||||
'1hr': string;
|
||||
'6hr': string;
|
||||
'1day': string;
|
||||
'3days': string;
|
||||
'1week': string;
|
||||
[key: string]: string; // Index signature to allow any string as index
|
||||
};
|
||||
|
||||
export const RelativeTimeMap: TimeFrame = {
|
||||
'5min': '5m',
|
||||
'15min': '15m',
|
||||
'30min': '30m',
|
||||
'1hr': '1h',
|
||||
'6hr': '6h',
|
||||
'1day': '1d',
|
||||
'3days': '3d',
|
||||
'1week': '1w',
|
||||
};
|
||||
|
||||
export interface Option {
|
||||
value: Time;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export const RelativeDurationOptions: Option[] = [
|
||||
{ value: '5m', label: 'Last 5 min' },
|
||||
{ value: '15m', label: 'Last 15 min' },
|
||||
{ value: '30m', label: 'Last 30 min' },
|
||||
{ value: '1h', label: 'Last 1 hour' },
|
||||
{ value: '6h', label: 'Last 6 hour' },
|
||||
{ value: '1d', label: 'Last 1 day' },
|
||||
{ value: '3d', label: 'Last 3 days' },
|
||||
{ value: '1w', label: 'Last 1 week' },
|
||||
];
|
||||
|
||||
export const getDefaultOption = (route: string): Time => {
|
||||
if (route === ROUTES.SERVICE_MAP) {
|
||||
return RelativeDurationOptions[2].value;
|
||||
}
|
||||
if (route === ROUTES.APPLICATION) {
|
||||
return Options[2].value;
|
||||
}
|
||||
return Options[2].value;
|
||||
};
|
||||
|
||||
export const getOptions = (routes: string): Option[] => {
|
||||
if (routes === ROUTES.SERVICE_MAP) {
|
||||
return RelativeDurationOptions;
|
||||
}
|
||||
return Options;
|
||||
};
|
||||
|
||||
export const routesToHideBreadCrumbs = [ROUTES.SUPPORT, ROUTES.ALL_DASHBOARD];
|
||||
|
||||
export const routesToSkip = [
|
||||
ROUTES.HOME,
|
||||
ROUTES.SETTINGS,
|
||||
ROUTES.LIST_ALL_ALERT,
|
||||
ROUTES.TRACE_DETAIL,
|
||||
ROUTES.ALL_CHANNELS,
|
||||
ROUTES.USAGE_EXPLORER,
|
||||
ROUTES.GET_STARTED,
|
||||
ROUTES.GET_STARTED_WITH_CLOUD,
|
||||
ROUTES.GET_STARTED_APPLICATION_MONITORING,
|
||||
ROUTES.GET_STARTED_INFRASTRUCTURE_MONITORING,
|
||||
ROUTES.GET_STARTED_LOGS_MANAGEMENT,
|
||||
ROUTES.GET_STARTED_AWS_MONITORING,
|
||||
ROUTES.GET_STARTED_AZURE_MONITORING,
|
||||
ROUTES.VERSION,
|
||||
ROUTES.ALL_DASHBOARD,
|
||||
ROUTES.ORG_SETTINGS,
|
||||
ROUTES.INGESTION_SETTINGS,
|
||||
ROUTES.ERROR_DETAIL,
|
||||
ROUTES.LOGS_PIPELINES,
|
||||
ROUTES.BILLING,
|
||||
ROUTES.SUPPORT,
|
||||
ROUTES.WORKSPACE_LOCKED,
|
||||
ROUTES.WORKSPACE_SUSPENDED,
|
||||
ROUTES.LOGS,
|
||||
ROUTES.MY_SETTINGS,
|
||||
ROUTES.LIST_LICENSES,
|
||||
];
|
||||
|
||||
export const routesToDisable = [ROUTES.LOGS_EXPLORER, ROUTES.LIVE_LOGS];
|
||||
|
||||
export interface LocalStorageTimeRange {
|
||||
localstorageStartTime: string | null;
|
||||
localstorageEndTime: string | null;
|
||||
}
|
||||
|
||||
export interface TimeRange {
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
}
|
||||
@@ -1,425 +0,0 @@
|
||||
import './DateTimeSelection.styles.scss';
|
||||
|
||||
import { SyncOutlined } from '@ant-design/icons';
|
||||
import { Button } from 'antd';
|
||||
import getLocalStorageKey from 'api/browser/localstorage/get';
|
||||
import setLocalStorageKey from 'api/browser/localstorage/set';
|
||||
import CustomTimePicker from 'components/CustomTimePicker/CustomTimePicker';
|
||||
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
|
||||
import { LOCALSTORAGE } from 'constants/localStorage';
|
||||
import { QueryParams } from 'constants/query';
|
||||
import ROUTES from 'constants/routes';
|
||||
import dayjs, { Dayjs } from 'dayjs';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { updateStepInterval } from 'hooks/queryBuilder/useStepInterval';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import GetMinMax from 'lib/getMinMax';
|
||||
import getTimeString from 'lib/getTimeString';
|
||||
import history from 'lib/history';
|
||||
import { isObject } from 'lodash-es';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { connect, useSelector } from 'react-redux';
|
||||
import { RouteComponentProps, withRouter } from 'react-router-dom';
|
||||
import { bindActionCreators, Dispatch } from 'redux';
|
||||
import { ThunkDispatch } from 'redux-thunk';
|
||||
import { GlobalTimeLoading, UpdateTimeInterval } from 'store/actions';
|
||||
import { AppState } from 'store/reducers';
|
||||
import AppActions from 'types/actions';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
|
||||
import AutoRefresh from '../AutoRefresh';
|
||||
import CustomDateTimeModal, { DateTimeRangeType } from '../CustomDateTimeModal';
|
||||
import { CustomTimeType, Time as TimeV2 } from '../DateTimeSelectionV2/config';
|
||||
import {
|
||||
getDefaultOption,
|
||||
getOptions,
|
||||
LocalStorageTimeRange,
|
||||
Time,
|
||||
TimeRange,
|
||||
} from './config';
|
||||
import RefreshText from './Refresh';
|
||||
import { Form, FormContainer, FormItem } from './styles';
|
||||
|
||||
function DateTimeSelection({
|
||||
location,
|
||||
updateTimeInterval,
|
||||
globalTimeLoading,
|
||||
}: Props): JSX.Element {
|
||||
const [formSelector] = Form.useForm();
|
||||
|
||||
const [hasSelectedTimeError, setHasSelectedTimeError] = useState(false);
|
||||
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||
|
||||
const urlQuery = useUrlQuery();
|
||||
const searchStartTime = urlQuery.get('startTime');
|
||||
const searchEndTime = urlQuery.get('endTime');
|
||||
|
||||
const {
|
||||
localstorageStartTime,
|
||||
localstorageEndTime,
|
||||
} = ((): LocalStorageTimeRange => {
|
||||
const routes = getLocalStorageKey(LOCALSTORAGE.METRICS_TIME_IN_DURATION);
|
||||
|
||||
if (routes !== null) {
|
||||
const routesObject = JSON.parse(routes || '{}');
|
||||
const selectedTime = routesObject[location.pathname];
|
||||
|
||||
if (selectedTime) {
|
||||
let parsedSelectedTime: TimeRange;
|
||||
try {
|
||||
parsedSelectedTime = JSON.parse(selectedTime);
|
||||
} catch {
|
||||
parsedSelectedTime = selectedTime;
|
||||
}
|
||||
|
||||
if (isObject(parsedSelectedTime)) {
|
||||
return {
|
||||
localstorageStartTime: parsedSelectedTime.startTime,
|
||||
localstorageEndTime: parsedSelectedTime.endTime,
|
||||
};
|
||||
}
|
||||
return { localstorageStartTime: null, localstorageEndTime: null };
|
||||
}
|
||||
}
|
||||
return { localstorageStartTime: null, localstorageEndTime: null };
|
||||
})();
|
||||
|
||||
const getTime = useCallback((): [number, number] | undefined => {
|
||||
if (searchEndTime && searchStartTime) {
|
||||
const startDate = dayjs(
|
||||
new Date(parseInt(getTimeString(searchStartTime), 10)),
|
||||
);
|
||||
const endDate = dayjs(new Date(parseInt(getTimeString(searchEndTime), 10)));
|
||||
|
||||
return [startDate.toDate().getTime() || 0, endDate.toDate().getTime() || 0];
|
||||
}
|
||||
if (localstorageStartTime && localstorageEndTime) {
|
||||
const startDate = dayjs(localstorageStartTime);
|
||||
const endDate = dayjs(localstorageEndTime);
|
||||
|
||||
return [startDate.toDate().getTime() || 0, endDate.toDate().getTime() || 0];
|
||||
}
|
||||
return undefined;
|
||||
}, [
|
||||
localstorageEndTime,
|
||||
localstorageStartTime,
|
||||
searchEndTime,
|
||||
searchStartTime,
|
||||
]);
|
||||
|
||||
const [options, setOptions] = useState(getOptions(location.pathname));
|
||||
const [refreshButtonHidden, setRefreshButtonHidden] = useState<boolean>(false);
|
||||
const [customDateTimeVisible, setCustomDTPickerVisible] = useState<boolean>(
|
||||
false,
|
||||
);
|
||||
|
||||
const { stagedQuery, initQueryBuilderData } = useQueryBuilder();
|
||||
|
||||
const { maxTime, minTime, selectedTime } = useSelector<
|
||||
AppState,
|
||||
GlobalReducer
|
||||
>((state) => state.globalTime);
|
||||
|
||||
const getInputLabel = (
|
||||
startTime?: Dayjs,
|
||||
endTime?: Dayjs,
|
||||
timeInterval: Time | TimeV2 | CustomTimeType = '15m',
|
||||
): string | Time => {
|
||||
if (startTime && endTime && timeInterval === 'custom') {
|
||||
const format = DATE_TIME_FORMATS.SLASH_DATETIME;
|
||||
|
||||
const startString = startTime.format(format);
|
||||
const endString = endTime.format(format);
|
||||
|
||||
return `${startString} - ${endString}`;
|
||||
}
|
||||
|
||||
return timeInterval;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedTime === 'custom') {
|
||||
setRefreshButtonHidden(true);
|
||||
} else {
|
||||
setRefreshButtonHidden(false);
|
||||
}
|
||||
}, [selectedTime]);
|
||||
|
||||
const getDefaultTime = (pathName: string): Time => {
|
||||
const defaultSelectedOption = getDefaultOption(pathName);
|
||||
|
||||
const routes = getLocalStorageKey(LOCALSTORAGE.METRICS_TIME_IN_DURATION);
|
||||
|
||||
if (routes !== null) {
|
||||
const routesObject = JSON.parse(routes || '{}');
|
||||
const selectedTime = routesObject[pathName];
|
||||
|
||||
if (selectedTime) {
|
||||
let parsedSelectedTime: TimeRange;
|
||||
try {
|
||||
parsedSelectedTime = JSON.parse(selectedTime);
|
||||
} catch {
|
||||
parsedSelectedTime = selectedTime;
|
||||
}
|
||||
if (isObject(parsedSelectedTime)) {
|
||||
return 'custom';
|
||||
}
|
||||
return selectedTime;
|
||||
}
|
||||
}
|
||||
|
||||
return defaultSelectedOption;
|
||||
};
|
||||
|
||||
const updateLocalStorageForRoutes = (value: Time | TimeV2 | string): void => {
|
||||
const preRoutes = getLocalStorageKey(LOCALSTORAGE.METRICS_TIME_IN_DURATION);
|
||||
if (preRoutes !== null) {
|
||||
const preRoutesObject = JSON.parse(preRoutes);
|
||||
|
||||
const preRoute = {
|
||||
...preRoutesObject,
|
||||
};
|
||||
preRoute[location.pathname] = value;
|
||||
|
||||
setLocalStorageKey(
|
||||
LOCALSTORAGE.METRICS_TIME_IN_DURATION,
|
||||
JSON.stringify(preRoute),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const onLastRefreshHandler = useCallback(() => {
|
||||
const currentTime = dayjs();
|
||||
|
||||
const lastRefresh = dayjs(
|
||||
selectedTime === 'custom' ? minTime / 1000000 : maxTime / 1000000,
|
||||
);
|
||||
|
||||
const secondsDiff = currentTime.diff(lastRefresh, 'seconds');
|
||||
|
||||
const minutedDiff = currentTime.diff(lastRefresh, 'minutes');
|
||||
const hoursDiff = currentTime.diff(lastRefresh, 'hours');
|
||||
const daysDiff = currentTime.diff(lastRefresh, 'days');
|
||||
const monthsDiff = currentTime.diff(lastRefresh, 'months');
|
||||
|
||||
if (monthsDiff > 0) {
|
||||
return `Last refresh -${monthsDiff} months ago`;
|
||||
}
|
||||
|
||||
if (daysDiff > 0) {
|
||||
return `Last refresh - ${daysDiff} days ago`;
|
||||
}
|
||||
|
||||
if (hoursDiff > 0) {
|
||||
return `Last refresh - ${hoursDiff} hrs ago`;
|
||||
}
|
||||
|
||||
if (minutedDiff > 0) {
|
||||
return `Last refresh - ${minutedDiff} mins ago`;
|
||||
}
|
||||
|
||||
return `Last refresh - ${secondsDiff} sec ago`;
|
||||
}, [maxTime, minTime, selectedTime]);
|
||||
|
||||
const isLogsExplorerPage = useMemo(
|
||||
() => location.pathname === ROUTES.LOGS_EXPLORER,
|
||||
[location.pathname],
|
||||
);
|
||||
|
||||
const onSelectHandler = (value: Time | TimeV2 | CustomTimeType): void => {
|
||||
if (value !== 'custom') {
|
||||
updateTimeInterval(value);
|
||||
updateLocalStorageForRoutes(value);
|
||||
if (refreshButtonHidden) {
|
||||
setRefreshButtonHidden(false);
|
||||
}
|
||||
} else {
|
||||
setRefreshButtonHidden(true);
|
||||
setCustomDTPickerVisible(true);
|
||||
}
|
||||
|
||||
if (!isLogsExplorerPage) {
|
||||
urlQuery.set(QueryParams.startTime, minTime.toString());
|
||||
urlQuery.set(QueryParams.endTime, maxTime.toString());
|
||||
const generatedUrl = `${location.pathname}?${urlQuery.toString()}`;
|
||||
history.push(generatedUrl);
|
||||
}
|
||||
|
||||
if (!stagedQuery) {
|
||||
return;
|
||||
}
|
||||
initQueryBuilderData(updateStepInterval(stagedQuery));
|
||||
};
|
||||
|
||||
const onRefreshHandler = (): void => {
|
||||
onSelectHandler(selectedTime);
|
||||
onLastRefreshHandler();
|
||||
};
|
||||
|
||||
const onCustomDateHandler = (dateTimeRange: DateTimeRangeType): void => {
|
||||
if (dateTimeRange !== null) {
|
||||
const [startTimeMoment, endTimeMoment] = dateTimeRange;
|
||||
if (startTimeMoment && endTimeMoment) {
|
||||
updateTimeInterval('custom', [
|
||||
startTimeMoment?.toDate().getTime() || 0,
|
||||
endTimeMoment?.toDate().getTime() || 0,
|
||||
]);
|
||||
updateLocalStorageForRoutes(
|
||||
JSON.stringify({ startTime: startTimeMoment, endTime: endTimeMoment }),
|
||||
);
|
||||
if (!isLogsExplorerPage) {
|
||||
urlQuery.set(
|
||||
QueryParams.startTime,
|
||||
startTimeMoment?.toDate().getTime().toString(),
|
||||
);
|
||||
urlQuery.set(
|
||||
QueryParams.endTime,
|
||||
endTimeMoment?.toDate().getTime().toString(),
|
||||
);
|
||||
const generatedUrl = `${location.pathname}?${urlQuery.toString()}`;
|
||||
history.push(generatedUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// this is triggred when we change the routes and based on that we are changing the default options
|
||||
useEffect(() => {
|
||||
const metricsTimeDuration = getLocalStorageKey(
|
||||
LOCALSTORAGE.METRICS_TIME_IN_DURATION,
|
||||
);
|
||||
|
||||
if (metricsTimeDuration === null) {
|
||||
setLocalStorageKey(
|
||||
LOCALSTORAGE.METRICS_TIME_IN_DURATION,
|
||||
JSON.stringify({}),
|
||||
);
|
||||
}
|
||||
|
||||
const currentRoute = location.pathname;
|
||||
const time = getDefaultTime(currentRoute);
|
||||
|
||||
const currentOptions = getOptions(currentRoute);
|
||||
setOptions(currentOptions);
|
||||
|
||||
const getCustomOrIntervalTime = (time: Time): Time => {
|
||||
if (searchEndTime !== null && searchStartTime !== null) {
|
||||
return 'custom';
|
||||
}
|
||||
if (
|
||||
(localstorageEndTime === null || localstorageStartTime === null) &&
|
||||
time === 'custom'
|
||||
) {
|
||||
return getDefaultOption(currentRoute);
|
||||
}
|
||||
|
||||
return time;
|
||||
};
|
||||
|
||||
const updatedTime = getCustomOrIntervalTime(time);
|
||||
|
||||
const [preStartTime = 0, preEndTime = 0] = getTime() || [];
|
||||
|
||||
setRefreshButtonHidden(updatedTime === 'custom');
|
||||
|
||||
updateTimeInterval(updatedTime, [preStartTime, preEndTime]);
|
||||
|
||||
if (updatedTime !== 'custom') {
|
||||
const { minTime, maxTime } = GetMinMax(updatedTime);
|
||||
urlQuery.set(QueryParams.startTime, minTime.toString());
|
||||
urlQuery.set(QueryParams.endTime, maxTime.toString());
|
||||
} else {
|
||||
urlQuery.set(QueryParams.startTime, preStartTime.toString());
|
||||
urlQuery.set(QueryParams.endTime, preEndTime.toString());
|
||||
}
|
||||
const generatedUrl = `${location.pathname}?${urlQuery.toString()}`;
|
||||
history.replace(generatedUrl);
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [location.pathname, updateTimeInterval, globalTimeLoading]);
|
||||
|
||||
return (
|
||||
<div className="date-time-selection-container">
|
||||
<Form
|
||||
form={formSelector}
|
||||
layout="inline"
|
||||
initialValues={{ interval: selectedTime }}
|
||||
>
|
||||
<FormContainer>
|
||||
<CustomTimePicker
|
||||
open={isOpen}
|
||||
setOpen={setIsOpen}
|
||||
onSelect={(value: unknown): void => {
|
||||
onSelectHandler(value as Time);
|
||||
}}
|
||||
onError={(hasError: boolean): void => {
|
||||
setHasSelectedTimeError(hasError);
|
||||
}}
|
||||
selectedTime={selectedTime}
|
||||
onValidCustomDateChange={(dateTime): void =>
|
||||
onCustomDateHandler(dateTime.time as DateTimeRangeType)
|
||||
}
|
||||
selectedValue={getInputLabel(
|
||||
dayjs(minTime / 1000000),
|
||||
dayjs(maxTime / 1000000),
|
||||
selectedTime,
|
||||
)}
|
||||
data-testid="dropDown"
|
||||
items={options}
|
||||
minTime={minTime}
|
||||
maxTime={maxTime}
|
||||
/>
|
||||
|
||||
<FormItem hidden={refreshButtonHidden}>
|
||||
<Button
|
||||
icon={<SyncOutlined />}
|
||||
type="primary"
|
||||
onClick={onRefreshHandler}
|
||||
/>
|
||||
</FormItem>
|
||||
|
||||
<FormItem>
|
||||
<AutoRefresh disabled={refreshButtonHidden} />
|
||||
</FormItem>
|
||||
</FormContainer>
|
||||
</Form>
|
||||
|
||||
{!hasSelectedTimeError && selectedTime !== 'custom' && (
|
||||
<RefreshText
|
||||
{...{
|
||||
onLastRefreshHandler,
|
||||
}}
|
||||
refreshButtonHidden={refreshButtonHidden}
|
||||
/>
|
||||
)}
|
||||
|
||||
<CustomDateTimeModal
|
||||
visible={customDateTimeVisible}
|
||||
onCreate={onCustomDateHandler}
|
||||
onCancel={(): void => {
|
||||
setCustomDTPickerVisible(false);
|
||||
}}
|
||||
setCustomDTPickerVisible={setCustomDTPickerVisible}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface DispatchProps {
|
||||
updateTimeInterval: (
|
||||
interval: Time | TimeV2 | CustomTimeType,
|
||||
dateTimeRange?: [number, number],
|
||||
) => (dispatch: Dispatch<AppActions>) => void;
|
||||
globalTimeLoading: () => void;
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (
|
||||
dispatch: ThunkDispatch<unknown, unknown, AppActions>,
|
||||
): DispatchProps => ({
|
||||
updateTimeInterval: bindActionCreators(UpdateTimeInterval, dispatch),
|
||||
globalTimeLoading: bindActionCreators(GlobalTimeLoading, dispatch),
|
||||
});
|
||||
|
||||
type Props = DispatchProps & RouteComponentProps;
|
||||
|
||||
export default connect(null, mapDispatchToProps)(withRouter(DateTimeSelection));
|
||||
@@ -1,34 +0,0 @@
|
||||
import { Form as FormComponent, Typography as TypographyComponent } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const Form = styled(FormComponent)`
|
||||
&&& {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
`;
|
||||
|
||||
export const Typography = styled(TypographyComponent)`
|
||||
&&& {
|
||||
text-align: right;
|
||||
}
|
||||
`;
|
||||
|
||||
export const FormItem = styled(Form.Item)`
|
||||
&&& {
|
||||
margin: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
refreshButtonHidden: boolean;
|
||||
}
|
||||
|
||||
export const RefreshTextContainer = styled.div<Props>`
|
||||
visibility: ${({ refreshButtonHidden }): string =>
|
||||
refreshButtonHidden ? 'hidden' : 'visible'};
|
||||
`;
|
||||
|
||||
export const FormContainer = styled.div`
|
||||
display: flex;
|
||||
gap: 0.1rem;
|
||||
`;
|
||||
@@ -1,54 +1,6 @@
|
||||
/* eslint-disable sonarjs/no-duplicate-string */
|
||||
import ROUTES from 'constants/routes';
|
||||
|
||||
type FiveMin = '5m';
|
||||
type TenMin = '10m';
|
||||
type FifteenMin = '15m';
|
||||
type ThirtyMin = '30m';
|
||||
type FortyFiveMin = '45m';
|
||||
type OneMin = '1m';
|
||||
type ThreeHour = '3h';
|
||||
type SixHour = '6h';
|
||||
type OneHour = '1h';
|
||||
type FourHour = '4h';
|
||||
type TwelveHour = '12h';
|
||||
type OneDay = '1d';
|
||||
type ThreeDay = '3d';
|
||||
type FourDay = '4d';
|
||||
type TenDay = '10d';
|
||||
type OneWeek = '1w';
|
||||
type TwoWeek = '2w';
|
||||
type SixWeek = '6w';
|
||||
type OneMonth = '1month';
|
||||
type TwoMonths = '2months';
|
||||
type Custom = 'custom';
|
||||
|
||||
export type Time =
|
||||
| FiveMin
|
||||
| TenMin
|
||||
| FifteenMin
|
||||
| ThirtyMin
|
||||
| OneMin
|
||||
| ThreeHour
|
||||
| FourHour
|
||||
| SixHour
|
||||
| OneHour
|
||||
| Custom
|
||||
| OneWeek
|
||||
| SixWeek
|
||||
| OneDay
|
||||
| FourDay
|
||||
| ThreeDay
|
||||
| FortyFiveMin
|
||||
| TwelveHour
|
||||
| TenDay
|
||||
| TwoWeek
|
||||
| OneMonth
|
||||
| TwoMonths;
|
||||
|
||||
export type TimeUnit = 'm' | 'h' | 'd' | 'w';
|
||||
|
||||
export type CustomTimeType = `${string}${TimeUnit}`;
|
||||
import { CustomTimeType, Option, Time, TimeFrame } from './types';
|
||||
|
||||
export const Options: Option[] = [
|
||||
{ value: '5m', label: 'Last 5 minutes' },
|
||||
@@ -63,10 +15,16 @@ export const Options: Option[] = [
|
||||
{ value: 'custom', label: 'Custom Date Range' },
|
||||
];
|
||||
|
||||
export interface Option {
|
||||
value: Time;
|
||||
label: string;
|
||||
}
|
||||
export const RelativeTimeMap: TimeFrame = {
|
||||
'5min': '5m',
|
||||
'15min': '15m',
|
||||
'30min': '30m',
|
||||
'1hr': '1h',
|
||||
'6hr': '6h',
|
||||
'1day': '1d',
|
||||
'3days': '3d',
|
||||
'1week': '1w',
|
||||
};
|
||||
|
||||
export const OLD_RELATIVE_TIME_VALUES = [
|
||||
'1min',
|
||||
@@ -244,18 +202,3 @@ export const routesToSkip = [
|
||||
];
|
||||
|
||||
export const routesToDisable = [ROUTES.LOGS_EXPLORER, ROUTES.LIVE_LOGS];
|
||||
|
||||
export interface LocalStorageTimeRange {
|
||||
localstorageStartTime: string | null;
|
||||
localstorageEndTime: string | null;
|
||||
}
|
||||
|
||||
export interface TimeRange {
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
}
|
||||
|
||||
export enum LexicalContext {
|
||||
CUSTOM_DATE_PICKER = 'customDatePicker',
|
||||
CUSTOM_DATE_TIME_INPUT = 'customDateTimeInput',
|
||||
}
|
||||
@@ -35,19 +35,21 @@ import { v4 as uuid } from 'uuid';
|
||||
|
||||
import AutoRefresh from '../AutoRefreshV2';
|
||||
import { DateTimeRangeType } from '../CustomDateTimeModal';
|
||||
import { RelativeTimeMap } from '../DateTimeSelection/config';
|
||||
import {
|
||||
convertOldTimeToNewValidCustomTimeFormat,
|
||||
CustomTimeType,
|
||||
getDefaultOption,
|
||||
getOptions,
|
||||
LocalStorageTimeRange,
|
||||
OLD_RELATIVE_TIME_VALUES,
|
||||
Time,
|
||||
TimeRange,
|
||||
} from './config';
|
||||
RelativeTimeMap,
|
||||
} from './constants';
|
||||
import RefreshText from './Refresh';
|
||||
import { Form, FormContainer, FormItem } from './styles';
|
||||
import {
|
||||
CustomTimeType,
|
||||
LocalStorageTimeRange,
|
||||
Time,
|
||||
TimeRange,
|
||||
} from './types';
|
||||
|
||||
function DateTimeSelection({
|
||||
showAutoRefresh,
|
||||
|
||||
80
frontend/src/container/TopNav/DateTimeSelectionV2/types.ts
Normal file
80
frontend/src/container/TopNav/DateTimeSelectionV2/types.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
type FiveMin = '5m';
|
||||
type TenMin = '10m';
|
||||
type FifteenMin = '15m';
|
||||
type ThirtyMin = '30m';
|
||||
type FortyFiveMin = '45m';
|
||||
type OneMin = '1m';
|
||||
type ThreeHour = '3h';
|
||||
type SixHour = '6h';
|
||||
type OneHour = '1h';
|
||||
type FourHour = '4h';
|
||||
type TwelveHour = '12h';
|
||||
type OneDay = '1d';
|
||||
type ThreeDay = '3d';
|
||||
type FourDay = '4d';
|
||||
type TenDay = '10d';
|
||||
type OneWeek = '1w';
|
||||
type TwoWeek = '2w';
|
||||
type SixWeek = '6w';
|
||||
type OneMonth = '1month';
|
||||
type TwoMonths = '2months';
|
||||
type Custom = 'custom';
|
||||
|
||||
export type Time =
|
||||
| FiveMin
|
||||
| TenMin
|
||||
| FifteenMin
|
||||
| ThirtyMin
|
||||
| OneMin
|
||||
| ThreeHour
|
||||
| FourHour
|
||||
| SixHour
|
||||
| OneHour
|
||||
| Custom
|
||||
| OneWeek
|
||||
| SixWeek
|
||||
| OneDay
|
||||
| FourDay
|
||||
| ThreeDay
|
||||
| FortyFiveMin
|
||||
| TwelveHour
|
||||
| TenDay
|
||||
| TwoWeek
|
||||
| OneMonth
|
||||
| TwoMonths;
|
||||
|
||||
export type TimeUnit = 'm' | 'h' | 'd' | 'w';
|
||||
|
||||
export type CustomTimeType = `${string}${TimeUnit}`;
|
||||
|
||||
export interface Option {
|
||||
value: Time;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export type TimeFrame = {
|
||||
'5min': string;
|
||||
'15min': string;
|
||||
'30min': string;
|
||||
'1hr': string;
|
||||
'6hr': string;
|
||||
'1day': string;
|
||||
'3days': string;
|
||||
'1week': string;
|
||||
[key: string]: string; // Index signature to allow any string as index
|
||||
};
|
||||
|
||||
export interface LocalStorageTimeRange {
|
||||
localstorageStartTime: string | null;
|
||||
localstorageEndTime: string | null;
|
||||
}
|
||||
|
||||
export interface TimeRange {
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
}
|
||||
|
||||
export enum LexicalContext {
|
||||
CUSTOM_DATE_PICKER = 'customDatePicker',
|
||||
CUSTOM_DATE_TIME_INPUT = 'customDateTimeInput',
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import { matchPath, useHistory } from 'react-router-dom';
|
||||
|
||||
import NewExplorerCTA from '../NewExplorerCTA';
|
||||
import DateTimeSelector from './DateTimeSelectionV2';
|
||||
import { routesToDisable, routesToSkip } from './DateTimeSelectionV2/config';
|
||||
import { routesToDisable, routesToSkip } from './DateTimeSelectionV2/constants';
|
||||
|
||||
function TopNav(): JSX.Element | null {
|
||||
const { location } = useHistory();
|
||||
|
||||
@@ -12,7 +12,7 @@ import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
||||
import EmptyLogsSearch from 'container/EmptyLogsSearch/EmptyLogsSearch';
|
||||
import NoLogs from 'container/NoLogs/NoLogs';
|
||||
import { useOptionsMenu } from 'container/OptionsMenu';
|
||||
import { CustomTimeType } from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
import { CustomTimeType } from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import TraceExplorerControls from 'container/TracesExplorer/Controls';
|
||||
import { getListViewQuery } from 'container/TracesExplorer/explorerUtils';
|
||||
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
||||
|
||||
183
frontend/src/hooks/dashboard/utils.test.ts
Normal file
183
frontend/src/hooks/dashboard/utils.test.ts
Normal file
@@ -0,0 +1,183 @@
|
||||
/* eslint-disable sonarjs/no-duplicate-string */
|
||||
import {
|
||||
initialClickHouseData,
|
||||
initialQueryBuilderFormValuesMap,
|
||||
initialQueryPromQLData,
|
||||
PANEL_TYPES,
|
||||
} from 'constants/queryBuilder';
|
||||
import { IDashboardVariable, Widgets } from 'types/api/dashboard/getAll';
|
||||
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
import { createDynamicVariableToWidgetsMap } from './utils';
|
||||
|
||||
const createMockDynamicVariable = (
|
||||
overrides: Partial<IDashboardVariable> = {},
|
||||
): IDashboardVariable => ({
|
||||
id: 'var-1',
|
||||
name: 'testVar',
|
||||
description: '',
|
||||
type: 'DYNAMIC',
|
||||
sort: 'DISABLED',
|
||||
multiSelect: false,
|
||||
showALLOption: false,
|
||||
dynamicVariablesAttribute: 'service.name',
|
||||
...overrides,
|
||||
});
|
||||
|
||||
const createBaseWidget = (id: string, query: Query): Widgets => ({
|
||||
id,
|
||||
title: 'Test Widget',
|
||||
description: '',
|
||||
panelTypes: PANEL_TYPES.TIME_SERIES,
|
||||
opacity: '1',
|
||||
nullZeroValues: '',
|
||||
timePreferance: 'GLOBAL_TIME',
|
||||
softMin: null,
|
||||
softMax: null,
|
||||
selectedLogFields: null,
|
||||
selectedTracesFields: null,
|
||||
query,
|
||||
});
|
||||
|
||||
const createMockPromQLWidget = (
|
||||
id: string,
|
||||
queries: {
|
||||
query: string;
|
||||
name?: string;
|
||||
legend?: string;
|
||||
disabled?: boolean;
|
||||
}[],
|
||||
): Widgets => {
|
||||
const promqlQueries = queries.map((q) => ({
|
||||
...initialQueryPromQLData,
|
||||
query: q.query,
|
||||
name: q.name || 'A',
|
||||
legend: q.legend || '',
|
||||
disabled: q.disabled ?? false,
|
||||
}));
|
||||
|
||||
const query: Query = {
|
||||
queryType: EQueryType.PROM,
|
||||
promql: promqlQueries,
|
||||
builder: {
|
||||
queryData: [],
|
||||
queryFormulas: [],
|
||||
queryTraceOperator: [],
|
||||
},
|
||||
clickhouse_sql: [],
|
||||
id: 'query-1',
|
||||
};
|
||||
|
||||
return createBaseWidget(id, query);
|
||||
};
|
||||
|
||||
const createMockClickHouseWidget = (
|
||||
id: string,
|
||||
queries: {
|
||||
query: string;
|
||||
name?: string;
|
||||
legend?: string;
|
||||
disabled?: boolean;
|
||||
}[],
|
||||
): Widgets => {
|
||||
const clickhouseQueries = queries.map((q) => ({
|
||||
...initialClickHouseData,
|
||||
query: q.query,
|
||||
name: q.name || 'A',
|
||||
legend: q.legend || '',
|
||||
disabled: q.disabled ?? false,
|
||||
}));
|
||||
|
||||
const query: Query = {
|
||||
queryType: EQueryType.CLICKHOUSE,
|
||||
promql: [],
|
||||
builder: {
|
||||
queryData: [],
|
||||
queryFormulas: [],
|
||||
queryTraceOperator: [],
|
||||
},
|
||||
clickhouse_sql: clickhouseQueries,
|
||||
id: 'query-1',
|
||||
};
|
||||
|
||||
return createBaseWidget(id, query);
|
||||
};
|
||||
|
||||
const createMockQueryBuilderWidget = (
|
||||
id: string,
|
||||
filters: { key: string; value: string | string[]; op?: string }[],
|
||||
): Widgets => {
|
||||
const queryData = {
|
||||
...initialQueryBuilderFormValuesMap[DataSource.LOGS],
|
||||
queryName: 'A',
|
||||
filters: {
|
||||
items: filters.map((f, index) => ({
|
||||
id: `filter-${index}`,
|
||||
key: { key: f.key, dataType: DataTypes.String, type: '', id: f.key },
|
||||
op: f.op || '=',
|
||||
value: f.value,
|
||||
})),
|
||||
op: 'AND',
|
||||
},
|
||||
};
|
||||
|
||||
const query: Query = {
|
||||
queryType: EQueryType.QUERY_BUILDER,
|
||||
promql: [],
|
||||
builder: {
|
||||
queryData: [queryData],
|
||||
queryFormulas: [],
|
||||
queryTraceOperator: [],
|
||||
},
|
||||
clickhouse_sql: [],
|
||||
id: 'query-1',
|
||||
};
|
||||
|
||||
return createBaseWidget(id, query);
|
||||
};
|
||||
|
||||
describe('createDynamicVariableToWidgetsMap', () => {
|
||||
it('should handle widgets with different query types', () => {
|
||||
const dynamicVariables = [
|
||||
createMockDynamicVariable({
|
||||
id: 'var-1',
|
||||
name: 'service.name123',
|
||||
dynamicVariablesAttribute: 'service.name',
|
||||
}),
|
||||
];
|
||||
|
||||
const widgets = [
|
||||
createMockPromQLWidget('widget-promql-pass', [
|
||||
{ query: 'up{service="$service.name123"}' },
|
||||
]),
|
||||
createMockPromQLWidget('widget-promql-fail', [
|
||||
{ query: 'up{service="$service.name"}' },
|
||||
]),
|
||||
createMockClickHouseWidget('widget-clickhouse-pass', [
|
||||
{ query: "SELECT * FROM logs WHERE service_name = '$service.name123'" },
|
||||
]),
|
||||
createMockClickHouseWidget('widget-clickhouse-fail', [
|
||||
{ query: "SELECT * FROM logs WHERE service_name = '$service.name'" },
|
||||
]),
|
||||
createMockQueryBuilderWidget('widget-builder-pass', [
|
||||
{ key: 'service.name', value: '$service.name123' },
|
||||
]),
|
||||
createMockQueryBuilderWidget('widget-builder-fail', [
|
||||
{ key: 'service.name', value: '$service.name' },
|
||||
]),
|
||||
];
|
||||
|
||||
const result = createDynamicVariableToWidgetsMap(dynamicVariables, widgets);
|
||||
|
||||
expect(result['var-1']).toContain('widget-promql-pass');
|
||||
expect(result['var-1']).toContain('widget-clickhouse-pass');
|
||||
expect(result['var-1']).toContain('widget-builder-pass');
|
||||
|
||||
expect(result['var-1']).not.toContain('widget-promql-fail');
|
||||
expect(result['var-1']).not.toContain('widget-clickhouse-fail');
|
||||
expect(result['var-1']).not.toContain('widget-builder-fail');
|
||||
});
|
||||
});
|
||||
@@ -104,10 +104,9 @@ export const createDynamicVariableToWidgetsMap = (
|
||||
// Check each widget for usage of dynamic variables
|
||||
if (Array.isArray(widgets)) {
|
||||
widgets.forEach((widget) => {
|
||||
if (
|
||||
widget.query?.builder?.queryData &&
|
||||
widget.query?.queryType === EQueryType.QUERY_BUILDER
|
||||
) {
|
||||
if (widget.query?.queryType === EQueryType.QUERY_BUILDER) {
|
||||
if (!Array.isArray(widget.query.builder.queryData)) return;
|
||||
|
||||
widget.query.builder.queryData.forEach((queryData: IBuilderQuery) => {
|
||||
// Check filter items for dynamic variables
|
||||
queryData.filters?.items?.forEach((filter: TagFilterItem) => {
|
||||
@@ -139,6 +138,34 @@ export const createDynamicVariableToWidgetsMap = (
|
||||
});
|
||||
}
|
||||
});
|
||||
} else if (widget.query?.queryType === EQueryType.PROM) {
|
||||
if (!Array.isArray(widget.query.promql)) return;
|
||||
|
||||
widget.query.promql.forEach((promqlQuery) => {
|
||||
dynamicVariables.forEach((variable) => {
|
||||
if (
|
||||
variable.dynamicVariablesAttribute &&
|
||||
promqlQuery.query?.includes(`$${variable.name}`) &&
|
||||
!dynamicVariableToWidgetsMap[variable.id].includes(widget.id)
|
||||
) {
|
||||
dynamicVariableToWidgetsMap[variable.id].push(widget.id);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (widget.query?.queryType === EQueryType.CLICKHOUSE) {
|
||||
if (!Array.isArray(widget.query.clickhouse_sql)) return;
|
||||
|
||||
widget.query.clickhouse_sql.forEach((clickhouseQuery) => {
|
||||
dynamicVariables.forEach((variable) => {
|
||||
if (
|
||||
variable.dynamicVariablesAttribute &&
|
||||
clickhouseQuery.query?.includes(`$${variable.name}`) &&
|
||||
!dynamicVariableToWidgetsMap[variable.id].includes(widget.id)
|
||||
) {
|
||||
dynamicVariableToWidgetsMap[variable.id].push(widget.id);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import getService from 'api/metrics/getService';
|
||||
import { AxiosError } from 'axios';
|
||||
import { Time } from 'container/TopNav/DateTimeSelection/config';
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time as TimeV2,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import {
|
||||
QueryKey,
|
||||
useQuery,
|
||||
@@ -30,7 +29,7 @@ export const useQueryService = ({
|
||||
interface UseQueryServiceProps {
|
||||
minTime: number;
|
||||
maxTime: number;
|
||||
selectedTime: Time | TimeV2 | CustomTimeType;
|
||||
selectedTime: Time | CustomTimeType;
|
||||
selectedTags: Tags[];
|
||||
options?: UseQueryOptions<PayloadProps, AxiosError, PayloadProps, QueryKey>;
|
||||
}
|
||||
|
||||
132
frontend/src/lib/__tests__/getConvertedValue.test.ts
Normal file
132
frontend/src/lib/__tests__/getConvertedValue.test.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
import { UniversalYAxisUnit } from 'components/YAxisUnitSelector/types';
|
||||
import { convertValue, getFormattedUnit } from 'lib/getConvertedValue';
|
||||
|
||||
describe('getFormattedUnit', () => {
|
||||
it('should return the grafana unit for universal unit if it exists', () => {
|
||||
const formattedUnit = getFormattedUnit(UniversalYAxisUnit.KILOBYTES);
|
||||
expect(formattedUnit).toBe('deckbytes');
|
||||
});
|
||||
|
||||
it('should return the unit directly if it is not a universal unit', () => {
|
||||
const formattedUnit = getFormattedUnit('{reason}');
|
||||
expect(formattedUnit).toBe('{reason}');
|
||||
});
|
||||
|
||||
it('should return the universal unit directly if it does not have a grafana equivalent', () => {
|
||||
const formattedUnit = getFormattedUnit(UniversalYAxisUnit.EXABYTES);
|
||||
expect(formattedUnit).toBe(UniversalYAxisUnit.EXABYTES);
|
||||
});
|
||||
});
|
||||
|
||||
describe('convertValue', () => {
|
||||
describe('data', () => {
|
||||
it('should convert bytes (IEC) to kilobytes', () => {
|
||||
expect(
|
||||
convertValue(
|
||||
1000,
|
||||
UniversalYAxisUnit.BYTES_IEC,
|
||||
UniversalYAxisUnit.KILOBYTES,
|
||||
),
|
||||
).toBe(1);
|
||||
});
|
||||
|
||||
it('should convert bytes (SI) to kilobytes', () => {
|
||||
expect(
|
||||
convertValue(1000, UniversalYAxisUnit.BYTES, UniversalYAxisUnit.KILOBYTES),
|
||||
).toBe(1);
|
||||
});
|
||||
|
||||
it('should convert kilobytes to bytes', () => {
|
||||
expect(
|
||||
convertValue(1, UniversalYAxisUnit.KILOBYTES, UniversalYAxisUnit.BYTES),
|
||||
).toBe(1000);
|
||||
});
|
||||
|
||||
it('should convert megabytes to kilobytes', () => {
|
||||
expect(convertValue(1, 'mbytes', 'kbytes')).toBe(1024);
|
||||
});
|
||||
|
||||
it('should convert gigabytes to megabytes', () => {
|
||||
expect(convertValue(1, 'gbytes', 'mbytes')).toBe(1024);
|
||||
});
|
||||
|
||||
it('should convert kilobytes to megabytes', () => {
|
||||
expect(convertValue(1024, 'kbytes', 'mbytes')).toBe(1);
|
||||
});
|
||||
|
||||
it('should convert bits to gigabytes', () => {
|
||||
// 12 GB = 103079215104 bits
|
||||
expect(convertValue(103079215104, 'bits', 'gbytes')).toBe(12);
|
||||
});
|
||||
});
|
||||
|
||||
describe('time', () => {
|
||||
it('should convert milliseconds to seconds', () => {
|
||||
expect(convertValue(1000, 'ms', 's')).toBe(1);
|
||||
});
|
||||
|
||||
it('should convert seconds to milliseconds', () => {
|
||||
expect(convertValue(1, 's', 'ms')).toBe(1000);
|
||||
});
|
||||
|
||||
it('should convert nanoseconds to milliseconds', () => {
|
||||
expect(convertValue(1000000, 'ns', 'ms')).toBe(1);
|
||||
});
|
||||
|
||||
it('should convert seconds to minutes', () => {
|
||||
expect(convertValue(60, 's', 'm')).toBe(1);
|
||||
});
|
||||
|
||||
it('should convert minutes to hours', () => {
|
||||
expect(convertValue(60, 'm', 'h')).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('data rate', () => {
|
||||
it('should convert bytes/sec to kibibytes/sec', () => {
|
||||
expect(convertValue(1024, 'binBps', 'KiBs')).toBe(1);
|
||||
});
|
||||
|
||||
it('should convert kibibytes/sec to bytes/sec', () => {
|
||||
expect(convertValue(1, 'KiBs', 'binBps')).toBe(1024);
|
||||
});
|
||||
});
|
||||
|
||||
describe('throughput', () => {
|
||||
it('should convert counts per second to counts per minute', () => {
|
||||
expect(convertValue(1, 'cps', 'cpm')).toBe(1 / 60);
|
||||
});
|
||||
|
||||
it('should convert operations per second to operations per minute', () => {
|
||||
expect(convertValue(1, 'ops', 'opm')).toBe(1 / 60);
|
||||
});
|
||||
|
||||
it('should convert counts per minute to counts per second', () => {
|
||||
expect(convertValue(1, 'cpm', 'cps')).toBe(60);
|
||||
});
|
||||
|
||||
it('should convert operations per minute to operations per second', () => {
|
||||
expect(convertValue(1, 'opm', 'ops')).toBe(60);
|
||||
});
|
||||
});
|
||||
|
||||
describe('percent', () => {
|
||||
it('should convert percentunit to percent', () => {
|
||||
expect(convertValue(0.5, 'percentunit', 'percent')).toBe(50);
|
||||
});
|
||||
|
||||
it('should convert percent to percentunit', () => {
|
||||
expect(convertValue(50, 'percent', 'percentunit')).toBe(0.5);
|
||||
});
|
||||
});
|
||||
|
||||
describe('invalid values', () => {
|
||||
it('should return null when currentUnit is invalid', () => {
|
||||
expect(convertValue(100, 'invalidUnit', 'bytes')).toBeNull();
|
||||
});
|
||||
|
||||
it('should return null when targetUnit is invalid', () => {
|
||||
expect(convertValue(100, 'bytes', 'invalidUnit')).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -11,11 +11,10 @@ import {
|
||||
import { ENTITY_VERSION_V5 } from 'constants/app';
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { timePreferenceType } from 'container/NewWidget/RightContainer/timeItems';
|
||||
import { Time } from 'container/TopNav/DateTimeSelection/config';
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time as TimeV2,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { Pagination } from 'hooks/queryPagination';
|
||||
import { convertNewDataToOld } from 'lib/newQueryBuilder/convertNewDataToOld';
|
||||
import { isEmpty } from 'lodash-es';
|
||||
@@ -392,7 +391,7 @@ export interface GetQueryResultsProps {
|
||||
query: Query;
|
||||
graphType: PANEL_TYPES;
|
||||
selectedTime: timePreferenceType;
|
||||
globalSelectedInterval?: Time | TimeV2 | CustomTimeType;
|
||||
globalSelectedInterval?: Time | CustomTimeType;
|
||||
variables?: Record<string, unknown>;
|
||||
params?: Record<string, unknown>;
|
||||
fillGaps?: boolean;
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
import {
|
||||
UniversalUnitToGrafanaUnit,
|
||||
Y_AXIS_UNIT_NAMES,
|
||||
} from 'components/YAxisUnitSelector/constants';
|
||||
import { UniversalYAxisUnit } from 'components/YAxisUnitSelector/types';
|
||||
import { isUniversalUnit } from 'components/YAxisUnitSelector/utils';
|
||||
|
||||
// 1 byte = 8 bits
|
||||
// Or 1 bit = 1/8 bytes
|
||||
const BIT_FACTOR = 1 / 8;
|
||||
|
||||
const DECIMAL_FACTOR = 1000;
|
||||
const BINARY_FACTOR = 1024;
|
||||
|
||||
const unitsMapping = [
|
||||
{
|
||||
label: 'Data',
|
||||
@@ -15,62 +29,132 @@ const unitsMapping = [
|
||||
{
|
||||
label: 'bits(IEC)',
|
||||
value: 'bits',
|
||||
factor: 8, // 1 byte = 8 bits
|
||||
factor: BIT_FACTOR,
|
||||
},
|
||||
{
|
||||
label: 'bits(SI)',
|
||||
value: 'decbits',
|
||||
factor: 8, // 1 byte = 8 bits
|
||||
factor: BIT_FACTOR,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.KILOBITS],
|
||||
value: UniversalYAxisUnit.KILOBITS,
|
||||
factor: BIT_FACTOR * DECIMAL_FACTOR,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.MEGABITS],
|
||||
value: UniversalYAxisUnit.MEGABITS,
|
||||
factor: BIT_FACTOR * DECIMAL_FACTOR ** 2,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.GIGABITS],
|
||||
value: UniversalYAxisUnit.GIGABITS,
|
||||
factor: BIT_FACTOR * DECIMAL_FACTOR ** 3,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.TERABITS],
|
||||
value: UniversalYAxisUnit.TERABITS,
|
||||
factor: BIT_FACTOR * DECIMAL_FACTOR ** 4,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.PETABITS],
|
||||
value: UniversalYAxisUnit.PETABITS,
|
||||
factor: BIT_FACTOR * DECIMAL_FACTOR ** 5,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.EXABITS],
|
||||
value: UniversalYAxisUnit.EXABITS,
|
||||
factor: BIT_FACTOR * DECIMAL_FACTOR ** 6,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.ZETTABITS],
|
||||
value: UniversalYAxisUnit.ZETTABITS,
|
||||
factor: BIT_FACTOR * DECIMAL_FACTOR ** 7,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.YOTTABITS],
|
||||
value: UniversalYAxisUnit.YOTTABITS,
|
||||
factor: BIT_FACTOR * DECIMAL_FACTOR ** 8,
|
||||
},
|
||||
{
|
||||
label: 'kibibytes',
|
||||
value: 'kbytes',
|
||||
factor: 1024,
|
||||
factor: BINARY_FACTOR,
|
||||
},
|
||||
{
|
||||
label: 'kilobytes',
|
||||
value: 'deckbytes',
|
||||
factor: 1000,
|
||||
factor: DECIMAL_FACTOR,
|
||||
},
|
||||
{
|
||||
label: 'mebibytes',
|
||||
value: 'mbytes',
|
||||
factor: 1024 * 1024,
|
||||
factor: BINARY_FACTOR ** 2,
|
||||
},
|
||||
{
|
||||
label: 'megabytes',
|
||||
value: 'decmbytes',
|
||||
factor: 1000 * 1000,
|
||||
factor: DECIMAL_FACTOR ** 2,
|
||||
},
|
||||
{
|
||||
label: 'gibibytes',
|
||||
value: 'gbytes',
|
||||
factor: 1024 * 1024 * 1024,
|
||||
factor: BINARY_FACTOR ** 3,
|
||||
},
|
||||
{
|
||||
label: 'gigabytes',
|
||||
value: 'decgbytes',
|
||||
factor: 1000 * 1000 * 1000,
|
||||
factor: DECIMAL_FACTOR ** 3,
|
||||
},
|
||||
{
|
||||
label: 'tebibytes',
|
||||
value: 'tbytes',
|
||||
factor: 1024 * 1024 * 1024 * 1024,
|
||||
factor: BINARY_FACTOR ** 4,
|
||||
},
|
||||
{
|
||||
label: 'terabytes',
|
||||
value: 'dectbytes',
|
||||
factor: 1000 * 1000 * 1000 * 1000,
|
||||
factor: DECIMAL_FACTOR ** 4,
|
||||
},
|
||||
{
|
||||
label: 'pebibytes',
|
||||
value: 'pbytes',
|
||||
factor: 1024 * 1024 * 1024 * 1024 * 1024,
|
||||
factor: BINARY_FACTOR ** 5,
|
||||
},
|
||||
{
|
||||
label: 'petabytes',
|
||||
value: 'decpbytes',
|
||||
factor: 1000 * 1000 * 1000 * 1000 * 1000,
|
||||
factor: DECIMAL_FACTOR ** 5,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.EXABYTES],
|
||||
value: UniversalYAxisUnit.EXABYTES,
|
||||
factor: DECIMAL_FACTOR ** 6,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.EXBIBYTES],
|
||||
value: UniversalYAxisUnit.EXBIBYTES,
|
||||
factor: BINARY_FACTOR ** 6,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.ZETTABYTES],
|
||||
value: UniversalYAxisUnit.ZETTABYTES,
|
||||
factor: DECIMAL_FACTOR ** 7,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.ZEBIBYTES],
|
||||
value: UniversalYAxisUnit.ZEBIBYTES,
|
||||
factor: BINARY_FACTOR ** 7,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.YOTTABYTES],
|
||||
value: UniversalYAxisUnit.YOTTABYTES,
|
||||
factor: DECIMAL_FACTOR ** 8,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.YOBIBYTES],
|
||||
value: UniversalYAxisUnit.YOBIBYTES,
|
||||
factor: BINARY_FACTOR ** 8,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -90,44 +174,103 @@ const unitsMapping = [
|
||||
{
|
||||
label: 'bits/sec(IEC)',
|
||||
value: 'binbps',
|
||||
factor: 8, // 1 byte = 8 bits
|
||||
factor: BIT_FACTOR, // 1 byte = 8 bits
|
||||
},
|
||||
{
|
||||
label: 'bits/sec(SI)',
|
||||
value: 'bps',
|
||||
factor: 8, // 1 byte = 8 bits
|
||||
factor: BIT_FACTOR, // 1 byte = 8 bits
|
||||
},
|
||||
{
|
||||
label: 'kibibytes/sec',
|
||||
value: 'KiBs',
|
||||
factor: 1024,
|
||||
factor: BINARY_FACTOR,
|
||||
},
|
||||
{
|
||||
label: 'kibibits/sec',
|
||||
value: 'Kibits',
|
||||
factor: 8 * 1024, // 1 KiB = 8 Kibits
|
||||
factor: BIT_FACTOR * BINARY_FACTOR, // 1 KiB = 8 Kibits
|
||||
},
|
||||
{
|
||||
label: 'kilobytes/sec',
|
||||
value: 'KBs',
|
||||
factor: 1000,
|
||||
factor: DECIMAL_FACTOR,
|
||||
},
|
||||
{
|
||||
label: 'kilobits/sec',
|
||||
value: 'Kbits',
|
||||
factor: 8 * 1000, // 1 KB = 8 Kbits
|
||||
factor: BIT_FACTOR * DECIMAL_FACTOR, // 1 KB = 8 Kbits
|
||||
},
|
||||
{
|
||||
label: 'mebibytes/sec',
|
||||
value: 'MiBs',
|
||||
factor: 1024 * 1024,
|
||||
factor: BINARY_FACTOR ** 2,
|
||||
},
|
||||
{
|
||||
label: 'mebibits/sec',
|
||||
value: 'Mibits',
|
||||
factor: 8 * 1024 * 1024, // 1 MiB = 8 Mibits
|
||||
factor: BIT_FACTOR * BINARY_FACTOR ** 2, // 1 MiB = 8 Mibits
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.EXABYTES_SECOND],
|
||||
value: UniversalYAxisUnit.EXABYTES_SECOND,
|
||||
factor: DECIMAL_FACTOR ** 6,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.ZETTABYTES_SECOND],
|
||||
value: UniversalYAxisUnit.ZETTABYTES_SECOND,
|
||||
factor: DECIMAL_FACTOR ** 7,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.YOTTABYTES_SECOND],
|
||||
value: UniversalYAxisUnit.YOTTABYTES_SECOND,
|
||||
factor: DECIMAL_FACTOR ** 8,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.EXBIBYTES_SECOND],
|
||||
value: UniversalYAxisUnit.EXBIBYTES_SECOND,
|
||||
factor: BINARY_FACTOR ** 6,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.ZEBIBYTES_SECOND],
|
||||
value: UniversalYAxisUnit.ZEBIBYTES_SECOND,
|
||||
factor: BINARY_FACTOR ** 7,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.YOBIBYTES_SECOND],
|
||||
value: UniversalYAxisUnit.YOBIBYTES_SECOND,
|
||||
factor: BINARY_FACTOR ** 8,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.EXABITS_SECOND],
|
||||
value: UniversalYAxisUnit.EXABITS_SECOND,
|
||||
factor: BIT_FACTOR * DECIMAL_FACTOR ** 6,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.ZETTABITS_SECOND],
|
||||
value: UniversalYAxisUnit.ZETTABITS_SECOND,
|
||||
factor: BIT_FACTOR * DECIMAL_FACTOR ** 7,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.YOTTABITS_SECOND],
|
||||
value: UniversalYAxisUnit.YOTTABITS_SECOND,
|
||||
factor: BIT_FACTOR * DECIMAL_FACTOR ** 8,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.EXBIBITS_SECOND],
|
||||
value: UniversalYAxisUnit.EXBIBITS_SECOND,
|
||||
factor: BIT_FACTOR * BINARY_FACTOR ** 6,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.ZEBIBITS_SECOND],
|
||||
value: UniversalYAxisUnit.ZEBIBITS_SECOND,
|
||||
factor: BIT_FACTOR * BINARY_FACTOR ** 7,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.YOBIBITS_SECOND],
|
||||
value: UniversalYAxisUnit.YOBIBITS_SECOND,
|
||||
factor: BIT_FACTOR * BINARY_FACTOR ** 8,
|
||||
},
|
||||
// ... (other options)
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -268,6 +411,14 @@ function findUnitObject(
|
||||
return unitObj || null;
|
||||
}
|
||||
|
||||
export function getFormattedUnit(unit: string): string {
|
||||
const isUniversalYAxisUnit = isUniversalUnit(unit);
|
||||
if (isUniversalYAxisUnit) {
|
||||
return UniversalUnitToGrafanaUnit[unit as UniversalYAxisUnit] || unit;
|
||||
}
|
||||
return unit;
|
||||
}
|
||||
|
||||
export function convertValue(
|
||||
value: number,
|
||||
currentUnit?: string,
|
||||
@@ -281,8 +432,12 @@ export function convertValue(
|
||||
) {
|
||||
return value;
|
||||
}
|
||||
const currentUnitObj = findUnitObject(currentUnit);
|
||||
const targetUnitObj = findUnitObject(targetUnit);
|
||||
|
||||
const formattedCurrentUnit = getFormattedUnit(currentUnit);
|
||||
const formattedTargetUnit = getFormattedUnit(targetUnit);
|
||||
|
||||
const currentUnitObj = findUnitObject(formattedCurrentUnit);
|
||||
const targetUnitObj = findUnitObject(formattedTargetUnit);
|
||||
|
||||
if (currentUnitObj && targetUnitObj) {
|
||||
const baseValue = value * currentUnitObj.factor;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Time } from 'container/TopNav/DateTimeSelection/config';
|
||||
import { Time as TimeV2 } from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { isString } from 'lodash-es';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
|
||||
@@ -43,7 +45,7 @@ export const getMinTimeForRelativeTimes = (
|
||||
};
|
||||
|
||||
const GetMinMax = (
|
||||
interval: Time | TimeV2 | string,
|
||||
interval: Time | string,
|
||||
dateTimeRange?: [number, number],
|
||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||
): GetMinMaxPayload => {
|
||||
@@ -128,6 +130,15 @@ const GetMinMax = (
|
||||
};
|
||||
};
|
||||
|
||||
export const getMinMaxForSelectedTime = (
|
||||
selectedTime: Time | CustomTimeType,
|
||||
minTime: number,
|
||||
maxTime: number,
|
||||
): GetMinMaxPayload =>
|
||||
selectedTime !== 'custom'
|
||||
? GetMinMax(selectedTime)
|
||||
: GetMinMax(selectedTime, [minTime, maxTime]);
|
||||
|
||||
export interface GetMinMaxPayload {
|
||||
minTime: GlobalReducer['minTime'];
|
||||
maxTime: GlobalReducer['maxTime'];
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { timePreferenceType } from 'container/NewWidget/RightContainer/timeItems';
|
||||
import { Time } from 'container/TopNav/DateTimeSelection/config';
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time as TimeV2,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import store from 'store';
|
||||
|
||||
import getMaxMinTime from './getMaxMinTime';
|
||||
@@ -41,7 +40,7 @@ const getStartEndRangeTime = ({
|
||||
interface GetStartEndRangeTimesProps {
|
||||
type?: timePreferenceType;
|
||||
graphType?: PANEL_TYPES | null;
|
||||
interval?: Time | TimeV2 | CustomTimeType;
|
||||
interval?: Time | CustomTimeType;
|
||||
}
|
||||
|
||||
interface GetStartEndRangeTimesPayload {
|
||||
|
||||
@@ -17,7 +17,7 @@ import AlertHistory from 'container/AlertHistory';
|
||||
import { TIMELINE_TABLE_PAGE_SIZE } from 'container/AlertHistory/constants';
|
||||
import { AlertDetailsTab, TimelineFilter } from 'container/AlertHistory/types';
|
||||
import { urlKey } from 'container/AllError/utils';
|
||||
import { RelativeTimeMap } from 'container/TopNav/DateTimeSelection/config';
|
||||
import { RelativeTimeMap } from 'container/TopNav/DateTimeSelectionV2/constants';
|
||||
import useAxiosError from 'hooks/useAxiosError';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import { useSafeNavigate } from 'hooks/useSafeNavigate';
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { ValidateFunnelResponse } from 'api/traceFunnels';
|
||||
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
||||
import { Time } from 'container/TopNav/DateTimeSelection/config';
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time as TimeV2,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { normalizeSteps } from 'hooks/TracesFunnels/useFunnelConfiguration';
|
||||
import { useValidateFunnelSteps } from 'hooks/TracesFunnels/useFunnels';
|
||||
import getStartEndRangeTime from 'lib/getStartEndRangeTime';
|
||||
@@ -34,7 +33,7 @@ import { v4 } from 'uuid';
|
||||
interface FunnelContextType {
|
||||
startTime: number;
|
||||
endTime: number;
|
||||
selectedTime: CustomTimeType | Time | TimeV2;
|
||||
selectedTime: CustomTimeType | Time;
|
||||
validTracesCount: number;
|
||||
funnelId: string;
|
||||
steps: FunnelStepData[];
|
||||
|
||||
@@ -5,7 +5,6 @@ import locked from 'api/v1/dashboards/id/lock';
|
||||
import { ALL_SELECTED_VALUE } from 'components/NewSelect/utils';
|
||||
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
||||
import ROUTES from 'constants/routes';
|
||||
import { getMinMax } from 'container/TopNav/AutoRefresh/config';
|
||||
import dayjs, { Dayjs } from 'dayjs';
|
||||
import { useDashboardVariablesFromLocalStorage } from 'hooks/dashboard/useDashboardFromLocalStorage';
|
||||
import useVariablesFromUrl from 'hooks/dashboard/useVariablesFromUrl';
|
||||
@@ -13,6 +12,7 @@ import { useSafeNavigate } from 'hooks/useSafeNavigate';
|
||||
import useTabVisibility from 'hooks/useTabFocus';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { getUpdatedLayout } from 'lib/dashboard/getUpdatedLayout';
|
||||
import { getMinMaxForSelectedTime } from 'lib/getMinMax';
|
||||
import { defaultTo, isEmpty } from 'lodash-es';
|
||||
import isEqual from 'lodash-es/isEqual';
|
||||
import isUndefined from 'lodash-es/isUndefined';
|
||||
@@ -371,7 +371,7 @@ export function DashboardProvider({
|
||||
onOk() {
|
||||
setSelectedDashboard(updatedDashboardData);
|
||||
|
||||
const { maxTime, minTime } = getMinMax(
|
||||
const { maxTime, minTime } = getMinMaxForSelectedTime(
|
||||
globalTime.selectedTime,
|
||||
globalTime.minTime,
|
||||
globalTime.maxTime,
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import { Time } from 'container/TopNav/DateTimeSelection/config';
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time as TimeV2,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import GetMinMax from 'lib/getMinMax';
|
||||
import { Dispatch } from 'redux';
|
||||
import AppActions from 'types/actions';
|
||||
import { UPDATE_TIME_INTERVAL } from 'types/actions/globalTime';
|
||||
|
||||
export const UpdateTimeInterval = (
|
||||
interval: Time | TimeV2 | CustomTimeType,
|
||||
interval: Time | CustomTimeType,
|
||||
dateTimeRange: [number, number] = [0, 0],
|
||||
): ((dispatch: Dispatch<AppActions>) => void) => (
|
||||
dispatch: Dispatch<AppActions>,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getDefaultOption } from 'container/TopNav/DateTimeSelection/config';
|
||||
import { getDefaultOption } from 'container/TopNav/DateTimeSelectionV2/constants';
|
||||
import {
|
||||
GLOBAL_TIME_LOADING_START,
|
||||
GlobalTimeAction,
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { Time } from 'container/TopNav/DateTimeSelection/config';
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time as TimeV2,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
|
||||
import { ResetIdStartAndEnd, SetSearchQueryString } from './logs';
|
||||
|
||||
@@ -17,7 +16,7 @@ export type GlobalTime = {
|
||||
};
|
||||
|
||||
interface UpdateTime extends GlobalTime {
|
||||
selectedTime: Time | TimeV2 | CustomTimeType;
|
||||
selectedTime: Time | CustomTimeType;
|
||||
}
|
||||
|
||||
interface UpdateTimeInterval {
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import { Time } from 'container/TopNav/DateTimeSelection/config';
|
||||
import {
|
||||
CustomTimeType,
|
||||
Time as TimeV2,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/config';
|
||||
Time,
|
||||
} from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import { GlobalTime } from 'types/actions/globalTime';
|
||||
|
||||
export interface GlobalReducer {
|
||||
maxTime: GlobalTime['maxTime'];
|
||||
minTime: GlobalTime['minTime'];
|
||||
loading: boolean;
|
||||
selectedTime: Time | TimeV2 | CustomTimeType;
|
||||
selectedTime: Time | CustomTimeType;
|
||||
isAutoRefreshDisabled: boolean;
|
||||
selectedAutoRefreshInterval: string;
|
||||
}
|
||||
|
||||
@@ -7634,11 +7634,6 @@ compute-scroll-into-view@^3.0.2:
|
||||
resolved "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.0.3.tgz"
|
||||
integrity sha512-nadqwNxghAGTamwIqQSG433W6OADZx2vCo3UXHNrzTRHK/htu+7+L0zhjEoaeaQVNAi3YgqWDv8+tzf0hRfR+A==
|
||||
|
||||
confusing-browser-globals@^1.0.10:
|
||||
version "1.0.11"
|
||||
resolved "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz"
|
||||
integrity sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==
|
||||
|
||||
connect-history-api-fallback@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz"
|
||||
@@ -9018,42 +9013,11 @@ escodegen@^2.0.0:
|
||||
optionalDependencies:
|
||||
source-map "~0.6.1"
|
||||
|
||||
eslint-config-airbnb-base@^15.0.0:
|
||||
version "15.0.0"
|
||||
resolved "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz"
|
||||
integrity sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==
|
||||
dependencies:
|
||||
confusing-browser-globals "^1.0.10"
|
||||
object.assign "^4.1.2"
|
||||
object.entries "^1.1.5"
|
||||
semver "^6.3.0"
|
||||
|
||||
eslint-config-airbnb-typescript@^16.1.4:
|
||||
version "16.2.0"
|
||||
resolved "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-16.2.0.tgz"
|
||||
integrity sha512-OUaMPZpTOZGKd5tXOjJ9PRU4iYNW/Z5DoHIynjsVK/FpkWdiY5+nxQW6TiJAlLwVI1l53xUOrnlZWtVBVQzuWA==
|
||||
dependencies:
|
||||
eslint-config-airbnb-base "^15.0.0"
|
||||
|
||||
eslint-config-airbnb@^19.0.4:
|
||||
version "19.0.4"
|
||||
resolved "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz"
|
||||
integrity sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==
|
||||
dependencies:
|
||||
eslint-config-airbnb-base "^15.0.0"
|
||||
object.assign "^4.1.2"
|
||||
object.entries "^1.1.5"
|
||||
|
||||
eslint-config-prettier@^8.3.0:
|
||||
version "8.8.0"
|
||||
resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz"
|
||||
integrity sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==
|
||||
|
||||
eslint-config-standard@^16.0.3:
|
||||
version "16.0.3"
|
||||
resolved "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-16.0.3.tgz"
|
||||
integrity sha512-x4fmJL5hGqNJKGHSjnLdgA6U6h1YW/G2dW9fA+cyVur4SK6lyue8+UgNKWlZtUDTXvgKDD/Oa3GQjmB5kjtVvg==
|
||||
|
||||
eslint-import-resolver-node@^0.3.7:
|
||||
version "0.3.7"
|
||||
resolved "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz"
|
||||
@@ -9070,14 +9034,6 @@ eslint-module-utils@^2.8.0:
|
||||
dependencies:
|
||||
debug "^3.2.7"
|
||||
|
||||
eslint-plugin-es@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz"
|
||||
integrity sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==
|
||||
dependencies:
|
||||
eslint-utils "^2.0.0"
|
||||
regexpp "^3.0.0"
|
||||
|
||||
eslint-plugin-import@^2.28.1:
|
||||
version "2.28.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz#63b8b5b3c409bfc75ebaf8fb206b07ab435482c4"
|
||||
@@ -9130,18 +9086,6 @@ eslint-plugin-jsx-a11y@^6.5.1:
|
||||
object.fromentries "^2.0.6"
|
||||
semver "^6.3.0"
|
||||
|
||||
eslint-plugin-node@^11.1.0:
|
||||
version "11.1.0"
|
||||
resolved "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz"
|
||||
integrity sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==
|
||||
dependencies:
|
||||
eslint-plugin-es "^3.0.0"
|
||||
eslint-utils "^2.0.0"
|
||||
ignore "^5.1.1"
|
||||
minimatch "^3.0.4"
|
||||
resolve "^1.10.1"
|
||||
semver "^6.1.0"
|
||||
|
||||
eslint-plugin-prettier@^4.0.0:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz"
|
||||
@@ -9149,11 +9093,6 @@ eslint-plugin-prettier@^4.0.0:
|
||||
dependencies:
|
||||
prettier-linter-helpers "^1.0.0"
|
||||
|
||||
eslint-plugin-promise@^5.1.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.2.0.tgz"
|
||||
integrity sha512-SftLb1pUG01QYq2A/hGAWfDRXqYD82zE7j7TopDOyNdU+7SvvoXREls/+PRTY17vUXzXnZA/zfnyKgRH6x4JJw==
|
||||
|
||||
eslint-plugin-react-hooks@^4.3.0:
|
||||
version "4.6.0"
|
||||
resolved "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz"
|
||||
@@ -9198,7 +9137,7 @@ eslint-scope@5.1.1, eslint-scope@^5.1.1:
|
||||
esrecurse "^4.3.0"
|
||||
estraverse "^4.1.1"
|
||||
|
||||
eslint-utils@^2.0.0, eslint-utils@^2.1.0:
|
||||
eslint-utils@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz"
|
||||
integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==
|
||||
@@ -10733,7 +10672,7 @@ ignore@^4.0.6:
|
||||
resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz"
|
||||
integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
|
||||
|
||||
ignore@^5.1.1, ignore@^5.1.8, ignore@^5.2.0:
|
||||
ignore@^5.1.8, ignore@^5.2.0:
|
||||
version "5.2.4"
|
||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324"
|
||||
integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==
|
||||
@@ -13693,7 +13632,7 @@ object-keys@^1.1.1:
|
||||
resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz"
|
||||
integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
|
||||
|
||||
object.assign@^4.1.2, object.assign@^4.1.3, object.assign@^4.1.4:
|
||||
object.assign@^4.1.3, object.assign@^4.1.4:
|
||||
version "4.1.4"
|
||||
resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz"
|
||||
integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==
|
||||
@@ -13703,7 +13642,7 @@ object.assign@^4.1.2, object.assign@^4.1.3, object.assign@^4.1.4:
|
||||
has-symbols "^1.0.3"
|
||||
object-keys "^1.1.1"
|
||||
|
||||
object.entries@^1.1.5, object.entries@^1.1.6:
|
||||
object.entries@^1.1.6:
|
||||
version "1.1.6"
|
||||
resolved "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz"
|
||||
integrity sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==
|
||||
@@ -15814,7 +15753,7 @@ regexp.prototype.flags@^1.4.3, regexp.prototype.flags@^1.5.0:
|
||||
define-properties "^1.2.0"
|
||||
functions-have-names "^1.2.3"
|
||||
|
||||
regexpp@^3.0.0, regexpp@^3.1.0:
|
||||
regexpp@^3.1.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz"
|
||||
integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
|
||||
@@ -16095,7 +16034,7 @@ resolve.exports@^1.1.0:
|
||||
resolved "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz"
|
||||
integrity sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==
|
||||
|
||||
resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.1:
|
||||
resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.1:
|
||||
version "1.22.2"
|
||||
resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz"
|
||||
integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==
|
||||
@@ -16343,7 +16282,7 @@ selfsigned@^2.4.1:
|
||||
"@types/node-forge" "^1.3.0"
|
||||
node-forge "^1"
|
||||
|
||||
"semver@2 || 3 || 4 || 5", semver@7.3.7, semver@7.5.4, semver@7.x, semver@^5.6.0, semver@^6.0.0, semver@^6.1.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0, semver@^6.3.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.6.3:
|
||||
"semver@2 || 3 || 4 || 5", semver@7.3.7, semver@7.5.4, semver@7.x, semver@^5.6.0, semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0, semver@^6.3.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.6.3:
|
||||
version "7.5.4"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
|
||||
integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
|
||||
|
||||
127
pkg/apis/fields/api.go
Normal file
127
pkg/apis/fields/api.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package fields
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/http/render"
|
||||
"github.com/SigNoz/signoz/pkg/telemetrylogs"
|
||||
"github.com/SigNoz/signoz/pkg/telemetrymetadata"
|
||||
"github.com/SigNoz/signoz/pkg/telemetrymeter"
|
||||
"github.com/SigNoz/signoz/pkg/telemetrymetrics"
|
||||
"github.com/SigNoz/signoz/pkg/telemetrystore"
|
||||
"github.com/SigNoz/signoz/pkg/telemetrytraces"
|
||||
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
|
||||
)
|
||||
|
||||
type API struct {
|
||||
telemetryStore telemetrystore.TelemetryStore
|
||||
telemetryMetadataStore telemetrytypes.MetadataStore
|
||||
}
|
||||
|
||||
// TODO: move this to module and remove metastore init
|
||||
func NewAPI(
|
||||
settings factory.ProviderSettings,
|
||||
telemetryStore telemetrystore.TelemetryStore,
|
||||
) *API {
|
||||
telemetryMetadataStore := telemetrymetadata.NewTelemetryMetaStore(
|
||||
settings,
|
||||
telemetryStore,
|
||||
telemetrytraces.DBName,
|
||||
telemetrytraces.TagAttributesV2TableName,
|
||||
telemetrytraces.SpanAttributesKeysTblName,
|
||||
telemetrytraces.SpanIndexV3TableName,
|
||||
telemetrymetrics.DBName,
|
||||
telemetrymetrics.AttributesMetadataTableName,
|
||||
telemetrymeter.DBName,
|
||||
telemetrymeter.SamplesAgg1dTableName,
|
||||
telemetrylogs.DBName,
|
||||
telemetrylogs.LogsV2TableName,
|
||||
telemetrylogs.TagAttributesV2TableName,
|
||||
telemetrylogs.LogAttributeKeysTblName,
|
||||
telemetrylogs.LogResourceKeysTblName,
|
||||
telemetrymetadata.DBName,
|
||||
telemetrymetadata.AttributesMetadataLocalTableName,
|
||||
)
|
||||
|
||||
return &API{
|
||||
telemetryStore: telemetryStore,
|
||||
telemetryMetadataStore: telemetryMetadataStore,
|
||||
}
|
||||
}
|
||||
|
||||
func (api *API) GetFieldsKeys(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
type fieldKeysResponse struct {
|
||||
Keys map[string][]*telemetrytypes.TelemetryFieldKey `json:"keys"`
|
||||
Complete bool `json:"complete"`
|
||||
}
|
||||
|
||||
bodyBytes, _ := io.ReadAll(r.Body)
|
||||
r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||
ctx := r.Context()
|
||||
|
||||
fieldKeySelector, err := parseFieldKeyRequest(r)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
keys, complete, err := api.telemetryMetadataStore.GetKeys(ctx, fieldKeySelector)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
response := fieldKeysResponse{
|
||||
Keys: keys,
|
||||
Complete: complete,
|
||||
}
|
||||
|
||||
render.Success(w, http.StatusOK, response)
|
||||
}
|
||||
|
||||
func (api *API) GetFieldsValues(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
type fieldValuesResponse struct {
|
||||
Values *telemetrytypes.TelemetryFieldValues `json:"values"`
|
||||
Complete bool `json:"complete"`
|
||||
}
|
||||
|
||||
bodyBytes, _ := io.ReadAll(r.Body)
|
||||
r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||
ctx := r.Context()
|
||||
|
||||
fieldValueSelector, err := parseFieldValueRequest(r)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
allValues, allComplete, err := api.telemetryMetadataStore.GetAllValues(ctx, fieldValueSelector)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
relatedValues, relatedComplete, err := api.telemetryMetadataStore.GetRelatedValues(ctx, fieldValueSelector)
|
||||
if err != nil {
|
||||
// we don't want to return error if we fail to get related values for some reason
|
||||
relatedValues = []string{}
|
||||
}
|
||||
|
||||
values := &telemetrytypes.TelemetryFieldValues{
|
||||
StringValues: allValues.StringValues,
|
||||
NumberValues: allValues.NumberValues,
|
||||
RelatedValues: relatedValues,
|
||||
}
|
||||
|
||||
response := fieldValuesResponse{
|
||||
Values: values,
|
||||
Complete: allComplete && relatedComplete,
|
||||
}
|
||||
|
||||
render.Success(w, http.StatusOK, response)
|
||||
}
|
||||
162
pkg/apis/fields/parse.go
Normal file
162
pkg/apis/fields/parse.go
Normal file
@@ -0,0 +1,162 @@
|
||||
package fields
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
)
|
||||
|
||||
func parseFieldKeyRequest(r *http.Request) (*telemetrytypes.FieldKeySelector, error) {
|
||||
var req telemetrytypes.FieldKeySelector
|
||||
var signal telemetrytypes.Signal
|
||||
var source telemetrytypes.Source
|
||||
var err error
|
||||
|
||||
signalStr := r.URL.Query().Get("signal")
|
||||
if signalStr != "" {
|
||||
signal = telemetrytypes.Signal{String: valuer.NewString(signalStr)}
|
||||
} else {
|
||||
signal = telemetrytypes.SignalUnspecified
|
||||
}
|
||||
|
||||
sourceStr := r.URL.Query().Get("source")
|
||||
if sourceStr != "" {
|
||||
source = telemetrytypes.Source{String: valuer.NewString(sourceStr)}
|
||||
} else {
|
||||
source = telemetrytypes.SourceUnspecified
|
||||
}
|
||||
|
||||
if r.URL.Query().Get("limit") != "" {
|
||||
limit, err := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, errors.TypeInvalidInput, errors.CodeInvalidInput, "failed to parse limit")
|
||||
}
|
||||
req.Limit = limit
|
||||
} else {
|
||||
req.Limit = 1000
|
||||
}
|
||||
|
||||
var startUnixMilli, endUnixMilli int64
|
||||
|
||||
if r.URL.Query().Get("startUnixMilli") != "" {
|
||||
startUnixMilli, err = strconv.ParseInt(r.URL.Query().Get("startUnixMilli"), 10, 64)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, errors.TypeInvalidInput, errors.CodeInvalidInput, "failed to parse startUnixMilli")
|
||||
}
|
||||
// Round down to the nearest 6 hours (21600000 milliseconds)
|
||||
startUnixMilli -= startUnixMilli % 21600000
|
||||
}
|
||||
if r.URL.Query().Get("endUnixMilli") != "" {
|
||||
endUnixMilli, err = strconv.ParseInt(r.URL.Query().Get("endUnixMilli"), 10, 64)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, errors.TypeInvalidInput, errors.CodeInvalidInput, "failed to parse endUnixMilli")
|
||||
}
|
||||
}
|
||||
|
||||
// Parse fieldContext directly instead of using JSON unmarshalling.
|
||||
var fieldContext telemetrytypes.FieldContext
|
||||
fieldContextStr := r.URL.Query().Get("fieldContext")
|
||||
if fieldContextStr != "" {
|
||||
fieldContext = telemetrytypes.FieldContext{String: valuer.NewString(fieldContextStr)}
|
||||
}
|
||||
|
||||
// Parse fieldDataType directly instead of using JSON unmarshalling.
|
||||
var fieldDataType telemetrytypes.FieldDataType
|
||||
fieldDataTypeStr := r.URL.Query().Get("fieldDataType")
|
||||
if fieldDataTypeStr != "" {
|
||||
fieldDataType = telemetrytypes.FieldDataType{String: valuer.NewString(fieldDataTypeStr)}
|
||||
}
|
||||
|
||||
metricName := r.URL.Query().Get("metricName")
|
||||
var metricContext *telemetrytypes.MetricContext
|
||||
if metricName != "" {
|
||||
metricContext = &telemetrytypes.MetricContext{
|
||||
MetricName: metricName,
|
||||
}
|
||||
}
|
||||
|
||||
name := r.URL.Query().Get("searchText")
|
||||
|
||||
if name != "" && fieldContext == telemetrytypes.FieldContextUnspecified {
|
||||
parsedFieldKey := telemetrytypes.GetFieldKeyFromKeyText(name)
|
||||
if parsedFieldKey.FieldContext != telemetrytypes.FieldContextUnspecified {
|
||||
// Only apply inferred context if it is valid for the current signal
|
||||
if isContextValidForSignal(parsedFieldKey.FieldContext, signal) {
|
||||
name = parsedFieldKey.Name
|
||||
fieldContext = parsedFieldKey.FieldContext
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
req = telemetrytypes.FieldKeySelector{
|
||||
StartUnixMilli: startUnixMilli,
|
||||
EndUnixMilli: endUnixMilli,
|
||||
Signal: signal,
|
||||
Source: source,
|
||||
Name: name,
|
||||
FieldContext: fieldContext,
|
||||
FieldDataType: fieldDataType,
|
||||
Limit: req.Limit,
|
||||
SelectorMatchType: telemetrytypes.FieldSelectorMatchTypeFuzzy,
|
||||
MetricContext: metricContext,
|
||||
}
|
||||
return &req, nil
|
||||
}
|
||||
|
||||
func parseFieldValueRequest(r *http.Request) (*telemetrytypes.FieldValueSelector, error) {
|
||||
keySelector, err := parseFieldKeyRequest(r)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, errors.TypeInvalidInput, errors.CodeInvalidInput, "failed to parse field key request")
|
||||
}
|
||||
|
||||
name := r.URL.Query().Get("name")
|
||||
if name != "" && keySelector.FieldContext == telemetrytypes.FieldContextUnspecified {
|
||||
parsedFieldKey := telemetrytypes.GetFieldKeyFromKeyText(name)
|
||||
if parsedFieldKey.FieldContext != telemetrytypes.FieldContextUnspecified {
|
||||
// Only apply inferred context if it is valid for the current signal
|
||||
if isContextValidForSignal(parsedFieldKey.FieldContext, keySelector.Signal) {
|
||||
name = parsedFieldKey.Name
|
||||
keySelector.FieldContext = parsedFieldKey.FieldContext
|
||||
}
|
||||
}
|
||||
}
|
||||
keySelector.Name = name
|
||||
existingQuery := r.URL.Query().Get("existingQuery")
|
||||
value := r.URL.Query().Get("searchText")
|
||||
|
||||
// Parse limit for fieldValue request, fallback to default 50 if parsing fails.
|
||||
limit, err := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||
if err != nil {
|
||||
limit = 50
|
||||
}
|
||||
|
||||
req := telemetrytypes.FieldValueSelector{
|
||||
FieldKeySelector: keySelector,
|
||||
ExistingQuery: existingQuery,
|
||||
Value: value,
|
||||
Limit: limit,
|
||||
}
|
||||
|
||||
return &req, nil
|
||||
}
|
||||
|
||||
func isContextValidForSignal(ctx telemetrytypes.FieldContext, signal telemetrytypes.Signal) bool {
|
||||
if ctx == telemetrytypes.FieldContextResource ||
|
||||
ctx == telemetrytypes.FieldContextAttribute ||
|
||||
ctx == telemetrytypes.FieldContextScope {
|
||||
return true
|
||||
}
|
||||
|
||||
switch signal.StringValue() {
|
||||
case telemetrytypes.SignalLogs.StringValue():
|
||||
return ctx == telemetrytypes.FieldContextLog || ctx == telemetrytypes.FieldContextBody
|
||||
case telemetrytypes.SignalTraces.StringValue():
|
||||
return ctx == telemetrytypes.FieldContextSpan || ctx == telemetrytypes.FieldContextEvent || ctx == telemetrytypes.FieldContextTrace
|
||||
case telemetrytypes.SignalMetrics.StringValue():
|
||||
return ctx == telemetrytypes.FieldContextMetric
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package signozapiserver
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/http/handler"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func (provider *provider) addFieldsRoutes(router *mux.Router) error {
|
||||
if err := router.Handle("/api/v1/fields/keys", handler.New(provider.authZ.ViewAccess(provider.fieldsHandler.GetFieldsKeys), handler.OpenAPIDef{
|
||||
ID: "GetFieldsKeys",
|
||||
Tags: []string{"fields"},
|
||||
Summary: "Get field keys",
|
||||
Description: "This endpoint returns field keys",
|
||||
Request: nil,
|
||||
RequestParams: new(telemetrytypes.PostableFieldKeysParams),
|
||||
RequestContentType: "",
|
||||
Response: new(telemetrytypes.GettableFieldKeys),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
|
||||
})).Methods(http.MethodGet).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/fields/values", handler.New(provider.authZ.ViewAccess(provider.fieldsHandler.GetFieldsValues), handler.OpenAPIDef{
|
||||
ID: "GetFieldsValues",
|
||||
Tags: []string{"fields"},
|
||||
Summary: "Get field values",
|
||||
Description: "This endpoint returns field values",
|
||||
Request: nil,
|
||||
RequestParams: new(telemetrytypes.PostableFieldValueParams),
|
||||
RequestContentType: "",
|
||||
Response: new(telemetrytypes.GettableFieldValues),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
|
||||
})).Methods(http.MethodGet).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
150
pkg/apiserver/signozapiserver/gateway.go
Normal file
150
pkg/apiserver/signozapiserver/gateway.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package signozapiserver
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/http/handler"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/types/gatewaytypes"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func (provider *provider) addGatewayRoutes(router *mux.Router) error {
|
||||
if err := router.Handle("/api/v2/gateway/ingestion_keys", handler.New(provider.authZ.AdminAccess(provider.gatewayHandler.GetIngestionKeys), handler.OpenAPIDef{
|
||||
ID: "GetIngestionKeys",
|
||||
Tags: []string{"gateway"},
|
||||
Summary: "Get ingestion keys for workspace",
|
||||
Description: "This endpoint returns the ingestion keys for a workspace",
|
||||
Request: nil,
|
||||
RequestContentType: "",
|
||||
Response: new(gatewaytypes.GettableIngestionKeys),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
|
||||
})).Methods(http.MethodGet).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v2/gateway/ingestion_keys/search", handler.New(provider.authZ.AdminAccess(provider.gatewayHandler.SearchIngestionKeys), handler.OpenAPIDef{
|
||||
ID: "SearchIngestionKeys",
|
||||
Tags: []string{"gateway"},
|
||||
Summary: "Search ingestion keys for workspace",
|
||||
Description: "This endpoint returns the ingestion keys for a workspace",
|
||||
Request: nil,
|
||||
RequestContentType: "",
|
||||
Response: new(gatewaytypes.GettableIngestionKeys),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
|
||||
})).Methods(http.MethodGet).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v2/gateway/ingestion_keys", handler.New(provider.authZ.AdminAccess(provider.gatewayHandler.CreateIngestionKey), handler.OpenAPIDef{
|
||||
ID: "CreateIngestionKey",
|
||||
Tags: []string{"gateway"},
|
||||
Summary: "Create ingestion key for workspace",
|
||||
Description: "This endpoint creates an ingestion key for the workspace",
|
||||
Request: new(gatewaytypes.PostableIngestionKey),
|
||||
RequestContentType: "application/json",
|
||||
Response: new(gatewaytypes.GettableCreatedIngestionKey),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
|
||||
})).Methods(http.MethodPost).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v2/gateway/ingestion_keys/{keyId}", handler.New(provider.authZ.AdminAccess(provider.gatewayHandler.UpdateIngestionKey), handler.OpenAPIDef{
|
||||
ID: "UpdateIngestionKey",
|
||||
Tags: []string{"gateway"},
|
||||
Summary: "Update ingestion key for workspace",
|
||||
Description: "This endpoint updates an ingestion key for the workspace",
|
||||
Request: new(gatewaytypes.PostableIngestionKey),
|
||||
RequestContentType: "application/json",
|
||||
Response: nil,
|
||||
ResponseContentType: "",
|
||||
SuccessStatusCode: http.StatusNoContent,
|
||||
ErrorStatusCodes: []int{},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
|
||||
})).Methods(http.MethodPatch).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v2/gateway/ingestion_keys/{keyId}", handler.New(provider.authZ.AdminAccess(provider.gatewayHandler.DeleteIngestionKey), handler.OpenAPIDef{
|
||||
ID: "DeleteIngestionKey",
|
||||
Tags: []string{"gateway"},
|
||||
Summary: "Delete ingestion key for workspace",
|
||||
Description: "This endpoint deletes an ingestion key for the workspace",
|
||||
Request: nil,
|
||||
RequestContentType: "",
|
||||
Response: nil,
|
||||
ResponseContentType: "",
|
||||
SuccessStatusCode: http.StatusNoContent,
|
||||
ErrorStatusCodes: []int{},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
|
||||
})).Methods(http.MethodDelete).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v2/gateway/ingestion_keys/{keyId}/limits", handler.New(provider.authZ.AdminAccess(provider.gatewayHandler.CreateIngestionKeyLimit), handler.OpenAPIDef{
|
||||
ID: "CreateIngestionKeyLimit",
|
||||
Tags: []string{"gateway"},
|
||||
Summary: "Create limit for the ingestion key",
|
||||
Description: "This endpoint creates an ingestion key limit",
|
||||
Request: new(gatewaytypes.PostableIngestionKeyLimit),
|
||||
RequestContentType: "application/json",
|
||||
Response: new(gatewaytypes.GettableCreatedIngestionKeyLimit),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusCreated,
|
||||
ErrorStatusCodes: []int{},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
|
||||
})).Methods(http.MethodPost).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v2/gateway/ingestion_keys/limits/{limitId}", handler.New(provider.authZ.AdminAccess(provider.gatewayHandler.UpdateIngestionKeyLimit), handler.OpenAPIDef{
|
||||
ID: "UpdateIngestionKeyLimit",
|
||||
Tags: []string{"gateway"},
|
||||
Summary: "Update limit for the ingestion key",
|
||||
Description: "This endpoint updates an ingestion key limit",
|
||||
Request: new(gatewaytypes.UpdatableIngestionKeyLimit),
|
||||
RequestContentType: "application/json",
|
||||
Response: nil,
|
||||
ResponseContentType: "",
|
||||
SuccessStatusCode: http.StatusNoContent,
|
||||
ErrorStatusCodes: []int{},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
|
||||
})).Methods(http.MethodPatch).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v2/gateway/ingestion_keys/limits/{limitId}", handler.New(provider.authZ.AdminAccess(provider.gatewayHandler.DeleteIngestionKeyLimit), handler.OpenAPIDef{
|
||||
ID: "DeleteIngestionKeyLimit",
|
||||
Tags: []string{"gateway"},
|
||||
Summary: "Delete limit for the ingestion key",
|
||||
Description: "This endpoint deletes an ingestion key limit",
|
||||
Request: nil,
|
||||
RequestContentType: "application/json",
|
||||
Response: nil,
|
||||
ResponseContentType: "",
|
||||
SuccessStatusCode: http.StatusNoContent,
|
||||
ErrorStatusCodes: []int{},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
|
||||
})).Methods(http.MethodDelete).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -7,12 +7,12 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/authz"
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/flagger"
|
||||
"github.com/SigNoz/signoz/pkg/gateway"
|
||||
"github.com/SigNoz/signoz/pkg/global"
|
||||
"github.com/SigNoz/signoz/pkg/http/handler"
|
||||
"github.com/SigNoz/signoz/pkg/http/middleware"
|
||||
"github.com/SigNoz/signoz/pkg/modules/authdomain"
|
||||
"github.com/SigNoz/signoz/pkg/modules/dashboard"
|
||||
"github.com/SigNoz/signoz/pkg/modules/fields"
|
||||
"github.com/SigNoz/signoz/pkg/modules/metricsexplorer"
|
||||
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||
"github.com/SigNoz/signoz/pkg/modules/preference"
|
||||
@@ -40,7 +40,7 @@ type provider struct {
|
||||
dashboardModule dashboard.Module
|
||||
dashboardHandler dashboard.Handler
|
||||
metricsExplorerHandler metricsexplorer.Handler
|
||||
fieldsHandler fields.Handler
|
||||
gatewayHandler gateway.Handler
|
||||
}
|
||||
|
||||
func NewFactory(
|
||||
@@ -57,28 +57,10 @@ func NewFactory(
|
||||
dashboardModule dashboard.Module,
|
||||
dashboardHandler dashboard.Handler,
|
||||
metricsExplorerHandler metricsexplorer.Handler,
|
||||
fieldsHandler fields.Handler,
|
||||
gatewayHandler gateway.Handler,
|
||||
) factory.ProviderFactory[apiserver.APIServer, apiserver.Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("signoz"), func(ctx context.Context, providerSettings factory.ProviderSettings, config apiserver.Config) (apiserver.APIServer, error) {
|
||||
return newProvider(
|
||||
ctx,
|
||||
providerSettings,
|
||||
config,
|
||||
orgGetter,
|
||||
authz,
|
||||
orgHandler,
|
||||
userHandler,
|
||||
sessionHandler,
|
||||
authDomainHandler,
|
||||
preferenceHandler,
|
||||
globalHandler,
|
||||
promoteHandler,
|
||||
flaggerHandler,
|
||||
dashboardModule,
|
||||
dashboardHandler,
|
||||
metricsExplorerHandler,
|
||||
fieldsHandler,
|
||||
)
|
||||
return newProvider(ctx, providerSettings, config, orgGetter, authz, orgHandler, userHandler, sessionHandler, authDomainHandler, preferenceHandler, globalHandler, promoteHandler, flaggerHandler, dashboardModule, dashboardHandler, metricsExplorerHandler, gatewayHandler)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -99,7 +81,7 @@ func newProvider(
|
||||
dashboardModule dashboard.Module,
|
||||
dashboardHandler dashboard.Handler,
|
||||
metricsExplorerHandler metricsexplorer.Handler,
|
||||
fieldsHandler fields.Handler,
|
||||
gatewayHandler gateway.Handler,
|
||||
) (apiserver.APIServer, error) {
|
||||
settings := factory.NewScopedProviderSettings(providerSettings, "github.com/SigNoz/signoz/pkg/apiserver/signozapiserver")
|
||||
router := mux.NewRouter().UseEncodedPath()
|
||||
@@ -119,7 +101,7 @@ func newProvider(
|
||||
dashboardModule: dashboardModule,
|
||||
dashboardHandler: dashboardHandler,
|
||||
metricsExplorerHandler: metricsExplorerHandler,
|
||||
fieldsHandler: fieldsHandler,
|
||||
gatewayHandler: gatewayHandler,
|
||||
}
|
||||
|
||||
provider.authZ = middleware.NewAuthZ(settings.Logger(), orgGetter, authz)
|
||||
@@ -176,7 +158,7 @@ func (provider *provider) AddToRouter(router *mux.Router) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := provider.addFieldsRoutes(router); err != nil {
|
||||
if err := provider.addGatewayRoutes(router); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user