Merge branch 'main' into field-map-condition-builder

This commit is contained in:
srikanthccv 2025-05-30 21:17:18 +05:30
commit e07f3bdfce
130 changed files with 17257 additions and 14670 deletions

View File

@ -3,6 +3,7 @@ package httplicensing
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"github.com/SigNoz/signoz/ee/query-service/constants"
"time" "time"
"github.com/SigNoz/signoz/ee/licensing/licensingstore/sqllicensingstore" "github.com/SigNoz/signoz/ee/licensing/licensingstore/sqllicensingstore"
@ -251,6 +252,13 @@ func (provider *provider) GetFeatureFlags(ctx context.Context) ([]*featuretypes.
} }
} }
if constants.IsDotMetricsEnabled {
gettableFeatures = append(gettableFeatures, &featuretypes.GettableFeature{
Name: featuretypes.DotMetricsEnabled,
Active: true,
})
}
return gettableFeatures, nil return gettableFeatures, nil
} }

View File

@ -4,6 +4,10 @@ import (
"os" "os"
) )
const (
DefaultSiteURL = "https://localhost:8080"
)
var LicenseSignozIo = "https://license.signoz.io/api/v1" var LicenseSignozIo = "https://license.signoz.io/api/v1"
var LicenseAPIKey = GetOrDefaultEnv("SIGNOZ_LICENSE_API_KEY", "") var LicenseAPIKey = GetOrDefaultEnv("SIGNOZ_LICENSE_API_KEY", "")
var SaasSegmentKey = GetOrDefaultEnv("SIGNOZ_SAAS_SEGMENT_KEY", "") var SaasSegmentKey = GetOrDefaultEnv("SIGNOZ_SAAS_SEGMENT_KEY", "")
@ -20,3 +24,22 @@ func GetOrDefaultEnv(key string, fallback string) string {
} }
return v return v
} }
// constant functions that override env vars
// GetDefaultSiteURL returns default site url, primarily
// used to send saml request and allowing backend to
// handle http redirect
func GetDefaultSiteURL() string {
return GetOrDefaultEnv("SIGNOZ_SITE_URL", DefaultSiteURL)
}
const DotMetricsEnabled = "DOT_METRICS_ENABLED"
var IsDotMetricsEnabled = false
func init() {
if GetOrDefaultEnv(DotMetricsEnabled, "false") == "true" {
IsDotMetricsEnabled = true
}
}

View File

@ -5,6 +5,8 @@ import { ErrorResponse, SuccessResponse } from 'types/api';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { TagFilter } from 'types/api/queryBuilder/queryBuilderData'; import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { UnderscoreToDotMap } from '../utils';
export interface K8sClustersListPayload { export interface K8sClustersListPayload {
filters: TagFilter; filters: TagFilter;
groupBy?: BaseAutocompleteData[]; groupBy?: BaseAutocompleteData[];
@ -40,23 +42,80 @@ export interface K8sClustersListResponse {
}; };
} }
export const clustersMetaMap = [
{ dot: 'k8s.cluster.name', under: 'k8s_cluster_name' },
{ dot: 'k8s.cluster.uid', under: 'k8s_cluster_uid' },
] as const;
export function mapClustersMeta(
raw: Record<string, unknown>,
): K8sClustersData['meta'] {
const out: Record<string, unknown> = { ...raw };
clustersMetaMap.forEach(({ dot, under }) => {
if (dot in raw) {
const v = raw[dot];
out[under] = typeof v === 'string' ? v : raw[under];
}
});
return out as K8sClustersData['meta'];
}
export const getK8sClustersList = async ( export const getK8sClustersList = async (
props: K8sClustersListPayload, props: K8sClustersListPayload,
signal?: AbortSignal, signal?: AbortSignal,
headers?: Record<string, string>, headers?: Record<string, string>,
dotMetricsEnabled = false,
): Promise<SuccessResponse<K8sClustersListResponse> | ErrorResponse> => { ): Promise<SuccessResponse<K8sClustersListResponse> | ErrorResponse> => {
try { try {
const response = await axios.post('/clusters/list', props, { const requestProps =
dotMetricsEnabled && Array.isArray(props.filters?.items)
? {
...props,
filters: {
...props.filters,
items: props.filters.items.reduce<typeof props.filters.items>(
(acc, item) => {
if (item.value === undefined) return acc;
if (
item.key &&
typeof item.key === 'object' &&
'key' in item.key &&
typeof item.key.key === 'string'
) {
const mappedKey = UnderscoreToDotMap[item.key.key] ?? item.key.key;
acc.push({
...item,
key: { ...item.key, key: mappedKey },
});
} else {
acc.push(item);
}
return acc;
},
[] as typeof props.filters.items,
),
},
}
: props;
const response = await axios.post('/clusters/list', requestProps, {
signal, signal,
headers, headers,
}); });
const payload: K8sClustersListResponse = response.data;
// one-liner meta mapping
payload.data.records = payload.data.records.map((record) => ({
...record,
meta: mapClustersMeta(record.meta as Record<string, unknown>),
}));
return { return {
statusCode: 200, statusCode: 200,
error: null, error: null,
message: 'Success', message: 'Success',
payload: response.data, payload,
params: props, params: requestProps,
}; };
} catch (error) { } catch (error) {
return ErrorResponseHandler(error as AxiosError); return ErrorResponseHandler(error as AxiosError);

View File

@ -5,6 +5,8 @@ import { ErrorResponse, SuccessResponse } from 'types/api';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { TagFilter } from 'types/api/queryBuilder/queryBuilderData'; import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { UnderscoreToDotMap } from '../utils';
export interface K8sDaemonSetsListPayload { export interface K8sDaemonSetsListPayload {
filters: TagFilter; filters: TagFilter;
groupBy?: BaseAutocompleteData[]; groupBy?: BaseAutocompleteData[];
@ -46,23 +48,82 @@ export interface K8sDaemonSetsListResponse {
}; };
} }
export const daemonSetsMetaMap = [
{ dot: 'k8s.namespace.name', under: 'k8s_namespace_name' },
{ dot: 'k8s.daemonset.name', under: 'k8s_daemonset_name' },
{ dot: 'k8s.cluster.name', under: 'k8s_cluster_name' },
] as const;
export function mapDaemonSetsMeta(
raw: Record<string, unknown>,
): K8sDaemonSetsData['meta'] {
const out: Record<string, unknown> = { ...raw };
daemonSetsMetaMap.forEach(({ dot, under }) => {
if (dot in raw) {
const v = raw[dot];
out[under] = typeof v === 'string' ? v : raw[under];
}
});
return out as K8sDaemonSetsData['meta'];
}
export const getK8sDaemonSetsList = async ( export const getK8sDaemonSetsList = async (
props: K8sDaemonSetsListPayload, props: K8sDaemonSetsListPayload,
signal?: AbortSignal, signal?: AbortSignal,
headers?: Record<string, string>, headers?: Record<string, string>,
dotMetricsEnabled = false,
): Promise<SuccessResponse<K8sDaemonSetsListResponse> | ErrorResponse> => { ): Promise<SuccessResponse<K8sDaemonSetsListResponse> | ErrorResponse> => {
try { try {
const response = await axios.post('/daemonsets/list', props, { // filter prep (unchanged)…
const requestProps =
dotMetricsEnabled && Array.isArray(props.filters?.items)
? {
...props,
filters: {
...props.filters,
items: props.filters.items.reduce<typeof props.filters.items>(
(acc, item) => {
if (item.value === undefined) return acc;
if (
item.key &&
typeof item.key === 'object' &&
'key' in item.key &&
typeof item.key.key === 'string'
) {
const mappedKey = UnderscoreToDotMap[item.key.key] ?? item.key.key;
acc.push({
...item,
key: { ...item.key, key: mappedKey },
});
} else {
acc.push(item);
}
return acc;
},
[] as typeof props.filters.items,
),
},
}
: props;
const response = await axios.post('/daemonsets/list', requestProps, {
signal, signal,
headers, headers,
}); });
const payload: K8sDaemonSetsListResponse = response.data;
// single-line meta mapping
payload.data.records = payload.data.records.map((record) => ({
...record,
meta: mapDaemonSetsMeta(record.meta as Record<string, unknown>),
}));
return { return {
statusCode: 200, statusCode: 200,
error: null, error: null,
message: 'Success', message: 'Success',
payload: response.data, payload,
params: props, params: requestProps,
}; };
} catch (error) { } catch (error) {
return ErrorResponseHandler(error as AxiosError); return ErrorResponseHandler(error as AxiosError);

View File

@ -5,6 +5,8 @@ import { ErrorResponse, SuccessResponse } from 'types/api';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { TagFilter } from 'types/api/queryBuilder/queryBuilderData'; import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { UnderscoreToDotMap } from '../utils';
export interface K8sDeploymentsListPayload { export interface K8sDeploymentsListPayload {
filters: TagFilter; filters: TagFilter;
groupBy?: BaseAutocompleteData[]; groupBy?: BaseAutocompleteData[];
@ -46,23 +48,81 @@ export interface K8sDeploymentsListResponse {
}; };
} }
export const deploymentsMetaMap = [
{ dot: 'k8s.cluster.name', under: 'k8s_cluster_name' },
{ dot: 'k8s.deployment.name', under: 'k8s_deployment_name' },
{ dot: 'k8s.namespace.name', under: 'k8s_namespace_name' },
] as const;
export function mapDeploymentsMeta(
raw: Record<string, unknown>,
): K8sDeploymentsData['meta'] {
const out: Record<string, unknown> = { ...raw };
deploymentsMetaMap.forEach(({ dot, under }) => {
if (dot in raw) {
const v = raw[dot];
out[under] = typeof v === 'string' ? v : raw[under];
}
});
return out as K8sDeploymentsData['meta'];
}
export const getK8sDeploymentsList = async ( export const getK8sDeploymentsList = async (
props: K8sDeploymentsListPayload, props: K8sDeploymentsListPayload,
signal?: AbortSignal, signal?: AbortSignal,
headers?: Record<string, string>, headers?: Record<string, string>,
dotMetricsEnabled = false,
): Promise<SuccessResponse<K8sDeploymentsListResponse> | ErrorResponse> => { ): Promise<SuccessResponse<K8sDeploymentsListResponse> | ErrorResponse> => {
try { try {
const response = await axios.post('/deployments/list', props, { const requestProps =
dotMetricsEnabled && Array.isArray(props.filters?.items)
? {
...props,
filters: {
...props.filters,
items: props.filters.items.reduce<typeof props.filters.items>(
(acc, item) => {
if (item.value === undefined) return acc;
if (
item.key &&
typeof item.key === 'object' &&
'key' in item.key &&
typeof item.key.key === 'string'
) {
const mappedKey = UnderscoreToDotMap[item.key.key] ?? item.key.key;
acc.push({
...item,
key: { ...item.key, key: mappedKey },
});
} else {
acc.push(item);
}
return acc;
},
[] as typeof props.filters.items,
),
},
}
: props;
const response = await axios.post('/deployments/list', requestProps, {
signal, signal,
headers, headers,
}); });
const payload: K8sDeploymentsListResponse = response.data;
// single-line mapping
payload.data.records = payload.data.records.map((record) => ({
...record,
meta: mapDeploymentsMeta(record.meta as Record<string, unknown>),
}));
return { return {
statusCode: 200, statusCode: 200,
error: null, error: null,
message: 'Success', message: 'Success',
payload: response.data, payload,
params: props, params: requestProps,
}; };
} catch (error) { } catch (error) {
return ErrorResponseHandler(error as AxiosError); return ErrorResponseHandler(error as AxiosError);

View File

@ -5,6 +5,8 @@ import { ErrorResponse, SuccessResponse } from 'types/api';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { TagFilter } from 'types/api/queryBuilder/queryBuilderData'; import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { UnderscoreToDotMap } from '../utils';
export interface K8sJobsListPayload { export interface K8sJobsListPayload {
filters: TagFilter; filters: TagFilter;
groupBy?: BaseAutocompleteData[]; groupBy?: BaseAutocompleteData[];
@ -48,23 +50,79 @@ export interface K8sJobsListResponse {
}; };
} }
export const jobsMetaMap = [
{ dot: 'k8s.cluster.name', under: 'k8s_cluster_name' },
{ dot: 'k8s.job.name', under: 'k8s_job_name' },
{ dot: 'k8s.namespace.name', under: 'k8s_namespace_name' },
] as const;
export function mapJobsMeta(raw: Record<string, unknown>): K8sJobsData['meta'] {
const out: Record<string, unknown> = { ...raw };
jobsMetaMap.forEach(({ dot, under }) => {
if (dot in raw) {
const v = raw[dot];
out[under] = typeof v === 'string' ? v : raw[under];
}
});
return out as K8sJobsData['meta'];
}
export const getK8sJobsList = async ( export const getK8sJobsList = async (
props: K8sJobsListPayload, props: K8sJobsListPayload,
signal?: AbortSignal, signal?: AbortSignal,
headers?: Record<string, string>, headers?: Record<string, string>,
dotMetricsEnabled = false,
): Promise<SuccessResponse<K8sJobsListResponse> | ErrorResponse> => { ): Promise<SuccessResponse<K8sJobsListResponse> | ErrorResponse> => {
try { try {
const response = await axios.post('/jobs/list', props, { const requestProps =
dotMetricsEnabled && Array.isArray(props.filters?.items)
? {
...props,
filters: {
...props.filters,
items: props.filters.items.reduce<typeof props.filters.items>(
(acc, item) => {
if (item.value === undefined) return acc;
if (
item.key &&
typeof item.key === 'object' &&
'key' in item.key &&
typeof item.key.key === 'string'
) {
const mappedKey = UnderscoreToDotMap[item.key.key] ?? item.key.key;
acc.push({
...item,
key: { ...item.key, key: mappedKey },
});
} else {
acc.push(item);
}
return acc;
},
[] as typeof props.filters.items,
),
},
}
: props;
const response = await axios.post('/jobs/list', requestProps, {
signal, signal,
headers, headers,
}); });
const payload: K8sJobsListResponse = response.data;
// one-liner meta mapping
payload.data.records = payload.data.records.map((record) => ({
...record,
meta: mapJobsMeta(record.meta as Record<string, unknown>),
}));
return { return {
statusCode: 200, statusCode: 200,
error: null, error: null,
message: 'Success', message: 'Success',
payload: response.data, payload,
params: props, params: requestProps,
}; };
} catch (error) { } catch (error) {
return ErrorResponseHandler(error as AxiosError); return ErrorResponseHandler(error as AxiosError);

View File

@ -5,6 +5,8 @@ import { ErrorResponse, SuccessResponse } from 'types/api';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { TagFilter } from 'types/api/queryBuilder/queryBuilderData'; import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { UnderscoreToDotMap } from '../utils';
export interface K8sNamespacesListPayload { export interface K8sNamespacesListPayload {
filters: TagFilter; filters: TagFilter;
groupBy?: BaseAutocompleteData[]; groupBy?: BaseAutocompleteData[];
@ -38,23 +40,79 @@ export interface K8sNamespacesListResponse {
}; };
} }
export const namespacesMetaMap = [
{ dot: 'k8s.cluster.name', under: 'k8s_cluster_name' },
{ dot: 'k8s.namespace.name', under: 'k8s_namespace_name' },
] as const;
export function mapNamespacesMeta(
raw: Record<string, unknown>,
): K8sNamespacesData['meta'] {
const out: Record<string, unknown> = { ...raw };
namespacesMetaMap.forEach(({ dot, under }) => {
if (dot in raw) {
const v = raw[dot];
out[under] = typeof v === 'string' ? v : raw[under];
}
});
return out as K8sNamespacesData['meta'];
}
export const getK8sNamespacesList = async ( export const getK8sNamespacesList = async (
props: K8sNamespacesListPayload, props: K8sNamespacesListPayload,
signal?: AbortSignal, signal?: AbortSignal,
headers?: Record<string, string>, headers?: Record<string, string>,
dotMetricsEnabled = false,
): Promise<SuccessResponse<K8sNamespacesListResponse> | ErrorResponse> => { ): Promise<SuccessResponse<K8sNamespacesListResponse> | ErrorResponse> => {
try { try {
const response = await axios.post('/namespaces/list', props, { const requestProps =
dotMetricsEnabled && Array.isArray(props.filters?.items)
? {
...props,
filters: {
...props.filters,
items: props.filters.items.reduce<typeof props.filters.items>(
(acc, item) => {
if (item.value === undefined) return acc;
if (
item.key &&
typeof item.key === 'object' &&
'key' in item.key &&
typeof item.key.key === 'string'
) {
const mappedKey = UnderscoreToDotMap[item.key.key] ?? item.key.key;
acc.push({
...item,
key: { ...item.key, key: mappedKey },
});
} else {
acc.push(item);
}
return acc;
},
[] as typeof props.filters.items,
),
},
}
: props;
const response = await axios.post('/namespaces/list', requestProps, {
signal, signal,
headers, headers,
}); });
const payload: K8sNamespacesListResponse = response.data;
payload.data.records = payload.data.records.map((record) => ({
...record,
meta: mapNamespacesMeta(record.meta as Record<string, unknown>),
}));
return { return {
statusCode: 200, statusCode: 200,
error: null, error: null,
message: 'Success', message: 'Success',
payload: response.data, payload,
params: props, params: requestProps,
}; };
} catch (error) { } catch (error) {
return ErrorResponseHandler(error as AxiosError); return ErrorResponseHandler(error as AxiosError);

View File

@ -5,6 +5,8 @@ import { ErrorResponse, SuccessResponse } from 'types/api';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { TagFilter } from 'types/api/queryBuilder/queryBuilderData'; import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { UnderscoreToDotMap } from '../utils';
export interface K8sNodesListPayload { export interface K8sNodesListPayload {
filters: TagFilter; filters: TagFilter;
groupBy?: BaseAutocompleteData[]; groupBy?: BaseAutocompleteData[];
@ -41,23 +43,81 @@ export interface K8sNodesListResponse {
}; };
} }
export const nodesMetaMap = [
{ dot: 'k8s.node.name', under: 'k8s_node_name' },
{ dot: 'k8s.node.uid', under: 'k8s_node_uid' },
{ dot: 'k8s.cluster.name', under: 'k8s_cluster_name' },
] as const;
export function mapNodesMeta(
raw: Record<string, unknown>,
): K8sNodesData['meta'] {
const out: Record<string, unknown> = { ...raw };
nodesMetaMap.forEach(({ dot, under }) => {
if (dot in raw) {
const v = raw[dot];
out[under] = typeof v === 'string' ? v : raw[under];
}
});
return out as K8sNodesData['meta'];
}
export const getK8sNodesList = async ( export const getK8sNodesList = async (
props: K8sNodesListPayload, props: K8sNodesListPayload,
signal?: AbortSignal, signal?: AbortSignal,
headers?: Record<string, string>, headers?: Record<string, string>,
dotMetricsEnabled = false,
): Promise<SuccessResponse<K8sNodesListResponse> | ErrorResponse> => { ): Promise<SuccessResponse<K8sNodesListResponse> | ErrorResponse> => {
try { try {
const response = await axios.post('/nodes/list', props, { const requestProps =
dotMetricsEnabled && Array.isArray(props.filters?.items)
? {
...props,
filters: {
...props.filters,
items: props.filters.items.reduce<typeof props.filters.items>(
(acc, item) => {
if (item.value === undefined) return acc;
if (
item.key &&
typeof item.key === 'object' &&
'key' in item.key &&
typeof item.key.key === 'string'
) {
const mappedKey = UnderscoreToDotMap[item.key.key] ?? item.key.key;
acc.push({
...item,
key: { ...item.key, key: mappedKey },
});
} else {
acc.push(item);
}
return acc;
},
[] as typeof props.filters.items,
),
},
}
: props;
const response = await axios.post('/nodes/list', requestProps, {
signal, signal,
headers, headers,
}); });
const payload: K8sNodesListResponse = response.data;
// one-liner to map dot→underscore
payload.data.records = payload.data.records.map((record) => ({
...record,
meta: mapNodesMeta(record.meta as Record<string, unknown>),
}));
return { return {
statusCode: 200, statusCode: 200,
error: null, error: null,
message: 'Success', message: 'Success',
payload: response.data, payload,
params: props, params: requestProps,
}; };
} catch (error) { } catch (error) {
return ErrorResponseHandler(error as AxiosError); return ErrorResponseHandler(error as AxiosError);

View File

@ -5,6 +5,8 @@ import { ErrorResponse, SuccessResponse } from 'types/api';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { TagFilter } from 'types/api/queryBuilder/queryBuilderData'; import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { UnderscoreToDotMap } from '../utils';
export interface K8sPodsListPayload { export interface K8sPodsListPayload {
filters: TagFilter; filters: TagFilter;
groupBy?: BaseAutocompleteData[]; groupBy?: BaseAutocompleteData[];
@ -69,23 +71,87 @@ export interface K8sPodsListResponse {
}; };
} }
export const podsMetaMap = [
{ dot: 'k8s.cronjob.name', under: 'k8s_cronjob_name' },
{ dot: 'k8s.daemonset.name', under: 'k8s_daemonset_name' },
{ dot: 'k8s.deployment.name', under: 'k8s_deployment_name' },
{ dot: 'k8s.job.name', under: 'k8s_job_name' },
{ dot: 'k8s.namespace.name', under: 'k8s_namespace_name' },
{ dot: 'k8s.node.name', under: 'k8s_node_name' },
{ dot: 'k8s.pod.name', under: 'k8s_pod_name' },
{ dot: 'k8s.pod.uid', under: 'k8s_pod_uid' },
{ dot: 'k8s.statefulset.name', under: 'k8s_statefulset_name' },
{ dot: 'k8s.cluster.name', under: 'k8s_cluster_name' },
] as const;
export function mapPodsMeta(raw: Record<string, unknown>): K8sPodsData['meta'] {
// clone everything
const out: Record<string, unknown> = { ...raw };
// overlay only the dot→under mappings
podsMetaMap.forEach(({ dot, under }) => {
if (dot in raw) {
const v = raw[dot];
out[under] = typeof v === 'string' ? v : raw[under];
}
});
return out as K8sPodsData['meta'];
}
// getK8sPodsList
export const getK8sPodsList = async ( export const getK8sPodsList = async (
props: K8sPodsListPayload, props: K8sPodsListPayload,
signal?: AbortSignal, signal?: AbortSignal,
headers?: Record<string, string>, headers?: Record<string, string>,
dotMetricsEnabled = false,
): Promise<SuccessResponse<K8sPodsListResponse> | ErrorResponse> => { ): Promise<SuccessResponse<K8sPodsListResponse> | ErrorResponse> => {
try { try {
const response = await axios.post('/pods/list', props, { const requestProps =
dotMetricsEnabled && Array.isArray(props.filters?.items)
? {
...props,
filters: {
...props.filters,
items: props.filters.items.reduce<typeof props.filters.items>(
(acc, item) => {
if (item.value === undefined) return acc;
if (
item.key &&
typeof item.key === 'object' &&
'key' in item.key &&
typeof item.key.key === 'string'
) {
const mappedKey = UnderscoreToDotMap[item.key.key] ?? item.key.key;
acc.push({
...item,
key: { ...item.key, key: mappedKey },
});
} else {
acc.push(item);
}
return acc;
},
[] as typeof props.filters.items,
),
},
}
: props;
const response = await axios.post('/pods/list', requestProps, {
signal, signal,
headers, headers,
}); });
const payload: K8sPodsListResponse = response.data;
payload.data.records = payload.data.records.map((record) => ({
...record,
meta: mapPodsMeta(record.meta as Record<string, unknown>),
}));
return { return {
statusCode: 200, statusCode: 200,
error: null, error: null,
message: 'Success', message: 'Success',
payload: response.data, payload,
params: props, params: requestProps,
}; };
} catch (error) { } catch (error) {
return ErrorResponseHandler(error as AxiosError); return ErrorResponseHandler(error as AxiosError);

View File

@ -5,6 +5,8 @@ import { ErrorResponse, SuccessResponse } from 'types/api';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { TagFilter } from 'types/api/queryBuilder/queryBuilderData'; import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { UnderscoreToDotMap } from '../utils';
export interface K8sVolumesListPayload { export interface K8sVolumesListPayload {
filters: TagFilter; filters: TagFilter;
groupBy?: BaseAutocompleteData[]; groupBy?: BaseAutocompleteData[];
@ -47,23 +49,92 @@ export interface K8sVolumesListResponse {
}; };
} }
export const volumesMetaMap: Array<{
dot: keyof Record<string, unknown>;
under: keyof K8sVolumesData['meta'];
}> = [
{ dot: 'k8s.cluster.name', under: 'k8s_cluster_name' },
{ dot: 'k8s.namespace.name', under: 'k8s_namespace_name' },
{ dot: 'k8s.node.name', under: 'k8s_node_name' },
{
dot: 'k8s.persistentvolumeclaim.name',
under: 'k8s_persistentvolumeclaim_name',
},
{ dot: 'k8s.pod.name', under: 'k8s_pod_name' },
{ dot: 'k8s.pod.uid', under: 'k8s_pod_uid' },
{ dot: 'k8s.statefulset.name', under: 'k8s_statefulset_name' },
];
export function mapVolumesMeta(
rawMeta: Record<string, unknown>,
): K8sVolumesData['meta'] {
// start with everything that was already there
const out: Record<string, unknown> = { ...rawMeta };
// for each dot→under rule, if the raw has the dot, overwrite the underscore
volumesMetaMap.forEach(({ dot, under }) => {
if (dot in rawMeta) {
const val = rawMeta[dot];
out[under] = typeof val === 'string' ? val : rawMeta[under];
}
});
return out as K8sVolumesData['meta'];
}
export const getK8sVolumesList = async ( export const getK8sVolumesList = async (
props: K8sVolumesListPayload, props: K8sVolumesListPayload,
signal?: AbortSignal, signal?: AbortSignal,
headers?: Record<string, string>, headers?: Record<string, string>,
dotMetricsEnabled = false,
): Promise<SuccessResponse<K8sVolumesListResponse> | ErrorResponse> => { ): Promise<SuccessResponse<K8sVolumesListResponse> | ErrorResponse> => {
try { try {
const response = await axios.post('/pvcs/list', props, { // Prepare filters
const requestProps =
dotMetricsEnabled && Array.isArray(props.filters?.items)
? {
...props,
filters: {
...props.filters,
items: props.filters.items.reduce<typeof props.filters.items>(
(acc, item) => {
if (item.value === undefined) return acc;
if (
item.key &&
typeof item.key === 'object' &&
'key' in item.key &&
typeof item.key.key === 'string'
) {
const mappedKey = UnderscoreToDotMap[item.key.key] ?? item.key.key;
acc.push({ ...item, key: { ...item.key, key: mappedKey } });
} else {
acc.push(item);
}
return acc;
},
[] as typeof props.filters.items,
),
},
}
: props;
const response = await axios.post('/pvcs/list', requestProps, {
signal, signal,
headers, headers,
}); });
const payload: K8sVolumesListResponse = response.data;
payload.data.records = payload.data.records.map((record) => ({
...record,
meta: mapVolumesMeta(record.meta as Record<string, unknown>),
}));
return { return {
statusCode: 200, statusCode: 200,
error: null, error: null,
message: 'Success', message: 'Success',
payload: response.data, payload,
params: props, params: requestProps,
}; };
} catch (error) { } catch (error) {
return ErrorResponseHandler(error as AxiosError); return ErrorResponseHandler(error as AxiosError);

View File

@ -5,6 +5,8 @@ import { ErrorResponse, SuccessResponse } from 'types/api';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { TagFilter } from 'types/api/queryBuilder/queryBuilderData'; import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { UnderscoreToDotMap } from '../utils';
export interface K8sStatefulSetsListPayload { export interface K8sStatefulSetsListPayload {
filters: TagFilter; filters: TagFilter;
groupBy?: BaseAutocompleteData[]; groupBy?: BaseAutocompleteData[];
@ -45,23 +47,78 @@ export interface K8sStatefulSetsListResponse {
}; };
} }
export const statefulSetsMetaMap = [
{ dot: 'k8s.statefulset.name', under: 'k8s_statefulset_name' },
{ dot: 'k8s.namespace.name', under: 'k8s_namespace_name' },
] as const;
export function mapStatefulSetsMeta(
raw: Record<string, unknown>,
): K8sStatefulSetsData['meta'] {
const out: Record<string, unknown> = { ...raw };
statefulSetsMetaMap.forEach(({ dot, under }) => {
if (dot in raw) {
const v = raw[dot];
out[under] = typeof v === 'string' ? v : raw[under];
}
});
return out as K8sStatefulSetsData['meta'];
}
export const getK8sStatefulSetsList = async ( export const getK8sStatefulSetsList = async (
props: K8sStatefulSetsListPayload, props: K8sStatefulSetsListPayload,
signal?: AbortSignal, signal?: AbortSignal,
headers?: Record<string, string>, headers?: Record<string, string>,
dotMetricsEnabled = false,
): Promise<SuccessResponse<K8sStatefulSetsListResponse> | ErrorResponse> => { ): Promise<SuccessResponse<K8sStatefulSetsListResponse> | ErrorResponse> => {
try { try {
const response = await axios.post('/statefulsets/list', props, { // Prepare filters
const requestProps =
dotMetricsEnabled && Array.isArray(props.filters?.items)
? {
...props,
filters: {
...props.filters,
items: props.filters.items.reduce<typeof props.filters.items>(
(acc, item) => {
if (item.value === undefined) return acc;
if (
item.key &&
typeof item.key === 'object' &&
'key' in item.key &&
typeof item.key.key === 'string'
) {
const mappedKey = UnderscoreToDotMap[item.key.key] ?? item.key.key;
acc.push({ ...item, key: { ...item.key, key: mappedKey } });
} else {
acc.push(item);
}
return acc;
},
[] as typeof props.filters.items,
),
},
}
: props;
const response = await axios.post('/statefulsets/list', requestProps, {
signal, signal,
headers, headers,
}); });
const payload: K8sStatefulSetsListResponse = response.data;
// apply our helper
payload.data.records = payload.data.records.map((record) => ({
...record,
meta: mapStatefulSetsMeta(record.meta as Record<string, unknown>),
}));
return { return {
statusCode: 200, statusCode: 200,
error: null, error: null,
message: 'Success', message: 'Success',
payload: response.data, payload,
params: props, params: requestProps,
}; };
} catch (error) { } catch (error) {
return ErrorResponseHandler(error as AxiosError); return ErrorResponseHandler(error as AxiosError);

View File

@ -17,3 +17,19 @@ export const Logout = (): void => {
history.push(ROUTES.LOGIN); history.push(ROUTES.LOGIN);
}; };
export const UnderscoreToDotMap: Record<string, string> = {
k8s_cluster_name: 'k8s.cluster.name',
k8s_cluster_uid: 'k8s.cluster.uid',
k8s_namespace_name: 'k8s.namespace.name',
k8s_node_name: 'k8s.node.name',
k8s_node_uid: 'k8s.node.uid',
k8s_pod_name: 'k8s.pod.name',
k8s_pod_uid: 'k8s.pod.uid',
k8s_deployment_name: 'k8s.deployment.name',
k8s_daemonset_name: 'k8s.daemonset.name',
k8s_statefulset_name: 'k8s.statefulset.name',
k8s_cronjob_name: 'k8s.cronjob.name',
k8s_job_name: 'k8s.job.name',
k8s_persistentvolumeclaim_name: 'k8s.persistentvolumeclaim.name',
};

View File

@ -23,6 +23,9 @@ import { useQueries, UseQueryResult } from 'react-query';
import { SuccessResponse } from 'types/api'; import { SuccessResponse } from 'types/api';
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange'; import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App';
interface MetricsTabProps { interface MetricsTabProps {
timeRange: { timeRange: {
startTime: number; startTime: number;
@ -45,9 +48,20 @@ function Metrics({
handleTimeChange, handleTimeChange,
isModalTimeSelection, isModalTimeSelection,
}: MetricsTabProps): JSX.Element { }: MetricsTabProps): JSX.Element {
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const queryPayloads = useMemo( const queryPayloads = useMemo(
() => getHostQueryPayload(hostName, timeRange.startTime, timeRange.endTime), () =>
[hostName, timeRange.startTime, timeRange.endTime], getHostQueryPayload(
hostName,
timeRange.startTime,
timeRange.endTime,
dotMetricsEnabled,
),
[hostName, timeRange.startTime, timeRange.endTime, dotMetricsEnabled],
); );
const queries = useQueries( const queries = useQueries(

View File

@ -10,4 +10,5 @@ export enum FeatureKeys {
ONBOARDING_V3 = 'ONBOARDING_V3', ONBOARDING_V3 = 'ONBOARDING_V3',
THIRD_PARTY_API = 'THIRD_PARTY_API', THIRD_PARTY_API = 'THIRD_PARTY_API',
TRACE_FUNNELS = 'TRACE_FUNNELS', TRACE_FUNNELS = 'TRACE_FUNNELS',
DOT_METRICS_ENABLED = 'DOT_METRICS_ENABLED',
} }

View File

@ -21,7 +21,10 @@ import ROUTES from 'constants/routes';
import { useGetCompositeQueryParam } from 'hooks/queryBuilder/useGetCompositeQueryParam'; import { useGetCompositeQueryParam } from 'hooks/queryBuilder/useGetCompositeQueryParam';
import { useNotifications } from 'hooks/useNotifications'; import { useNotifications } from 'hooks/useNotifications';
import useResourceAttribute from 'hooks/useResourceAttribute'; import useResourceAttribute from 'hooks/useResourceAttribute';
import { convertCompositeQueryToTraceSelectedTags } from 'hooks/useResourceAttribute/utils'; import {
convertCompositeQueryToTraceSelectedTags,
getResourceDeploymentKeys,
} from 'hooks/useResourceAttribute/utils';
import { TimestampInput } from 'hooks/useTimezoneFormatter/useTimezoneFormatter'; import { TimestampInput } from 'hooks/useTimezoneFormatter/useTimezoneFormatter';
import useUrlQuery from 'hooks/useUrlQuery'; import useUrlQuery from 'hooks/useUrlQuery';
import createQueryParams from 'lib/createQueryParams'; import createQueryParams from 'lib/createQueryParams';
@ -38,6 +41,8 @@ import { ErrorResponse, SuccessResponse } from 'types/api';
import { Exception, PayloadProps } from 'types/api/errors/getAll'; import { Exception, PayloadProps } from 'types/api/errors/getAll';
import { GlobalReducer } from 'types/reducer/globalTime'; import { GlobalReducer } from 'types/reducer/globalTime';
import { FeatureKeys } from '../../constants/features';
import { useAppContext } from '../../providers/App/App';
import { FilterDropdownExtendsProps } from './types'; import { FilterDropdownExtendsProps } from './types';
import { import {
extractFilterValues, extractFilterValues,
@ -405,6 +410,11 @@ function AllErrors(): JSX.Element {
}, },
]; ];
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const onChangeHandler: TableProps<Exception>['onChange'] = useCallback( const onChangeHandler: TableProps<Exception>['onChange'] = useCallback(
( (
paginations: TablePaginationConfig, paginations: TablePaginationConfig,
@ -438,7 +448,7 @@ function AllErrors(): JSX.Element {
useEffect(() => { useEffect(() => {
if (!isUndefined(errorCountResponse.data?.payload)) { if (!isUndefined(errorCountResponse.data?.payload)) {
const selectedEnvironments = queries.find( const selectedEnvironments = queries.find(
(val) => val.tagKey === 'resource_deployment_environment', (val) => val.tagKey === getResourceDeploymentKeys(dotMetricsEnabled),
)?.tagValue; )?.tagValue;
logEvent('Exception: List page visited', { logEvent('Exception: List page visited', {

View File

@ -10,6 +10,8 @@ import { Provider, useSelector } from 'react-redux';
import { MemoryRouter } from 'react-router-dom'; import { MemoryRouter } from 'react-router-dom';
import store from 'store'; import store from 'store';
import * as appContextHooks from '../../../providers/App/App';
import { LicenseEvent } from '../../../types/api/licensesV3/getActive';
import AllErrors from '../index'; import AllErrors from '../index';
import { import {
INIT_URL_WITH_COMMON_QUERY, INIT_URL_WITH_COMMON_QUERY,
@ -28,6 +30,30 @@ jest.mock('react-redux', () => ({
useSelector: jest.fn(), useSelector: jest.fn(),
})); }));
jest.spyOn(appContextHooks, 'useAppContext').mockReturnValue({
user: {
role: 'admin',
},
activeLicenseV3: {
event_queue: {
created_at: '0',
event: LicenseEvent.NO_EVENT,
scheduled_at: '0',
status: '',
updated_at: '0',
},
license: {
license_key: 'test-license-key',
license_type: 'trial',
org_id: 'test-org-id',
plan_id: 'test-plan-id',
plan_name: 'test-plan-name',
plan_type: 'trial',
plan_version: 'test-plan-version',
},
},
} as any);
function Exceptions({ initUrl }: { initUrl?: string[] }): JSX.Element { function Exceptions({ initUrl }: { initUrl?: string[] }): JSX.Element {
return ( return (
<MemoryRouter initialEntries={initUrl ?? ['/exceptions']}> <MemoryRouter initialEntries={initUrl ?? ['/exceptions']}>

View File

@ -10,6 +10,7 @@ import getAllUserPreferences from 'api/preferences/getAllUserPreference';
import updateUserPreferenceAPI from 'api/preferences/updateUserPreference'; import updateUserPreferenceAPI from 'api/preferences/updateUserPreference';
import Header from 'components/Header/Header'; import Header from 'components/Header/Header';
import { DEFAULT_ENTITY_VERSION } from 'constants/app'; import { DEFAULT_ENTITY_VERSION } from 'constants/app';
import { FeatureKeys } from 'constants/features';
import { LOCALSTORAGE } from 'constants/localStorage'; import { LOCALSTORAGE } from 'constants/localStorage';
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder'; import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys'; import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
@ -161,10 +162,20 @@ export default function Home(): JSX.Element {
enabled: !!query, enabled: !!query,
}); });
const { data: k8sPodsData } = useGetK8sPodsList(query as K8sPodsListPayload, { const { featureFlags } = useAppContext();
queryKey: ['K8sPodsList', query], const dotMetricsEnabled =
enabled: !!query, featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
}); ?.active || false;
const { data: k8sPodsData } = useGetK8sPodsList(
query as K8sPodsListPayload,
{
queryKey: ['K8sPodsList', query],
enabled: !!query,
},
undefined,
dotMetricsEnabled,
);
const [isLogsIngestionActive, setIsLogsIngestionActive] = useState(false); const [isLogsIngestionActive, setIsLogsIngestionActive] = useState(false);
const [isTracesIngestionActive, setIsTracesIngestionActive] = useState(false); const [isTracesIngestionActive, setIsTracesIngestionActive] = useState(false);

View File

@ -30,6 +30,7 @@ import { GlobalReducer } from 'types/reducer/globalTime';
import { Tags } from 'types/reducer/trace'; import { Tags } from 'types/reducer/trace';
import { USER_ROLES } from 'types/roles'; import { USER_ROLES } from 'types/roles';
import { FeatureKeys } from '../../../constants/features';
import { DOCS_LINKS } from '../constants'; import { DOCS_LINKS } from '../constants';
import { columns, TIME_PICKER_OPTIONS } from './constants'; import { columns, TIME_PICKER_OPTIONS } from './constants';
@ -210,6 +211,11 @@ function ServiceMetrics({
const topLevelOperations = useMemo(() => Object.entries(data || {}), [data]); const topLevelOperations = useMemo(() => Object.entries(data || {}), [data]);
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const queryRangeRequestData = useMemo( const queryRangeRequestData = useMemo(
() => () =>
getQueryRangeRequestData({ getQueryRangeRequestData({
@ -217,12 +223,14 @@ function ServiceMetrics({
minTime: timeRange.startTime * 1e6, minTime: timeRange.startTime * 1e6,
maxTime: timeRange.endTime * 1e6, maxTime: timeRange.endTime * 1e6,
globalSelectedInterval, globalSelectedInterval,
dotMetricsEnabled,
}), }),
[ [
globalSelectedInterval, globalSelectedInterval,
timeRange.endTime, timeRange.endTime,
timeRange.startTime, timeRange.startTime,
topLevelOperations, topLevelOperations,
dotMetricsEnabled,
], ],
); );

View File

@ -25,9 +25,11 @@ import { AppState } from 'store/reducers';
import { IBuilderQuery, Query } from 'types/api/queryBuilder/queryBuilderData'; import { IBuilderQuery, Query } from 'types/api/queryBuilder/queryBuilderData';
import { GlobalReducer } from 'types/reducer/globalTime'; import { GlobalReducer } from 'types/reducer/globalTime';
import { FeatureKeys } from '../../constants/features';
import { useAppContext } from '../../providers/App/App';
import HostsListControls from './HostsListControls'; import HostsListControls from './HostsListControls';
import HostsListTable from './HostsListTable'; import HostsListTable from './HostsListTable';
import { getHostListsQuery, HostsQuickFiltersConfig } from './utils'; import { getHostListsQuery, GetHostsQuickFiltersConfig } from './utils';
// eslint-disable-next-line sonarjs/cognitive-complexity // eslint-disable-next-line sonarjs/cognitive-complexity
function HostsList(): JSX.Element { function HostsList(): JSX.Element {
const { maxTime, minTime } = useSelector<AppState, GlobalReducer>( const { maxTime, minTime } = useSelector<AppState, GlobalReducer>(
@ -114,6 +116,11 @@ function HostsList(): JSX.Element {
entityVersion: '', entityVersion: '',
}); });
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const handleFiltersChange = useCallback( const handleFiltersChange = useCallback(
(value: IBuilderQuery['filters']): void => { (value: IBuilderQuery['filters']): void => {
const isNewFilterAdded = value.items.length !== filters.items.length; const isNewFilterAdded = value.items.length !== filters.items.length;
@ -182,7 +189,7 @@ function HostsList(): JSX.Element {
</div> </div>
<QuickFilters <QuickFilters
source={QuickFiltersSource.INFRA_MONITORING} source={QuickFiltersSource.INFRA_MONITORING}
config={HostsQuickFiltersConfig} config={GetHostsQuickFiltersConfig(dotMetricsEnabled)}
handleFilterVisibilityChange={handleFilterVisibilityChange} handleFilterVisibilityChange={handleFilterVisibilityChange}
onFilterChange={handleQuickFiltersChange} onFilterChange={handleQuickFiltersChange}
/> />

View File

@ -198,3 +198,48 @@ export const HostsQuickFiltersConfig: IQuickFiltersConfig[] = [
defaultOpen: true, defaultOpen: true,
}, },
]; ];
export function GetHostsQuickFiltersConfig(
dotMetricsEnabled: boolean,
): IQuickFiltersConfig[] {
// These keys dont change with dotMetricsEnabled
const hostNameKey = dotMetricsEnabled ? 'host.name' : 'host_name';
const osTypeKey = dotMetricsEnabled ? 'os.type' : 'os_type';
// This metric stays the same regardless of notation
const metricName = dotMetricsEnabled
? 'system.cpu.load_average.15m'
: 'system_cpu_load_average_15m';
return [
{
type: FiltersType.CHECKBOX,
title: 'Host Name',
attributeKey: {
key: hostNameKey,
dataType: DataTypes.String,
type: 'resource',
isColumn: false,
isJSON: false,
},
aggregateOperator: 'noop',
aggregateAttribute: metricName,
dataSource: DataSource.METRICS,
defaultOpen: true,
},
{
type: FiltersType.CHECKBOX,
title: 'OS Type',
attributeKey: {
key: osTypeKey,
dataType: DataTypes.String,
type: 'resource',
isColumn: false,
isJSON: false,
},
aggregateOperator: 'noop',
aggregateAttribute: metricName,
dataSource: DataSource.METRICS,
defaultOpen: true,
},
];
}

View File

@ -28,11 +28,13 @@ import { AppState } from 'store/reducers';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData'; import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
import { GlobalReducer } from 'types/reducer/globalTime'; import { GlobalReducer } from 'types/reducer/globalTime';
import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App';
import { getOrderByFromParams } from '../commonUtils'; import { getOrderByFromParams } from '../commonUtils';
import { import {
GetK8sEntityToAggregateAttribute,
INFRA_MONITORING_K8S_PARAMS_KEYS, INFRA_MONITORING_K8S_PARAMS_KEYS,
K8sCategory, K8sCategory,
K8sEntityToAggregateAttributeMapping,
} from '../constants'; } from '../constants';
import K8sHeader from '../K8sHeader'; import K8sHeader from '../K8sHeader';
import LoadingContainer from '../LoadingContainer'; import LoadingContainer from '../LoadingContainer';
@ -135,6 +137,11 @@ function K8sClustersList({
} }
}, [quickFiltersLastUpdated]); }, [quickFiltersLastUpdated]);
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const createFiltersForSelectedRowData = ( const createFiltersForSelectedRowData = (
selectedRowData: K8sClustersRowData, selectedRowData: K8sClustersRowData,
groupBy: IBuilderQuery['groupBy'], groupBy: IBuilderQuery['groupBy'],
@ -194,6 +201,8 @@ function K8sClustersList({
queryKey: ['clusterList', fetchGroupedByRowDataQuery], queryKey: ['clusterList', fetchGroupedByRowDataQuery],
enabled: !!fetchGroupedByRowDataQuery && !!selectedRowData, enabled: !!fetchGroupedByRowDataQuery && !!selectedRowData,
}, },
undefined,
dotMetricsEnabled,
); );
const { const {
@ -202,8 +211,10 @@ function K8sClustersList({
} = useGetAggregateKeys( } = useGetAggregateKeys(
{ {
dataSource: currentQuery.builder.queryData[0].dataSource, dataSource: currentQuery.builder.queryData[0].dataSource,
aggregateAttribute: aggregateAttribute: GetK8sEntityToAggregateAttribute(
K8sEntityToAggregateAttributeMapping[K8sCategory.CLUSTERS], K8sCategory.CLUSTERS,
dotMetricsEnabled,
),
aggregateOperator: 'noop', aggregateOperator: 'noop',
searchText: '', searchText: '',
tagType: '', tagType: '',
@ -249,6 +260,8 @@ function K8sClustersList({
queryKey: ['clusterList', query], queryKey: ['clusterList', query],
enabled: !!query, enabled: !!query,
}, },
undefined,
dotMetricsEnabled,
); );
const clustersData = useMemo(() => data?.payload?.data?.records || [], [data]); const clustersData = useMemo(() => data?.payload?.data?.records || [], [data]);

View File

@ -136,6 +136,11 @@ export const getK8sClustersListColumns = (
return columnsConfig as ColumnType<K8sClustersRowData>[]; return columnsConfig as ColumnType<K8sClustersRowData>[];
}; };
const dotToUnder: Record<string, keyof K8sClustersData['meta']> = {
'k8s.cluster.name': 'k8s_cluster_name',
'k8s.cluster.uid': 'k8s_cluster_uid',
};
const getGroupByEle = ( const getGroupByEle = (
cluster: K8sClustersData, cluster: K8sClustersData,
groupBy: IBuilderQuery['groupBy'], groupBy: IBuilderQuery['groupBy'],
@ -143,7 +148,13 @@ const getGroupByEle = (
const groupByValues: string[] = []; const groupByValues: string[] = [];
groupBy.forEach((group) => { groupBy.forEach((group) => {
groupByValues.push(cluster.meta[group.key as keyof typeof cluster.meta]); const rawKey = group.key as string;
// Choose mapped key if present, otherwise use rawKey
const metaKey = (dotToUnder[rawKey] ?? rawKey) as keyof typeof cluster.meta;
const value = cluster.meta[metaKey];
groupByValues.push(value);
}); });
return ( return (

View File

@ -29,11 +29,13 @@ import { AppState } from 'store/reducers';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData'; import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
import { GlobalReducer } from 'types/reducer/globalTime'; import { GlobalReducer } from 'types/reducer/globalTime';
import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App';
import { getOrderByFromParams } from '../commonUtils'; import { getOrderByFromParams } from '../commonUtils';
import { import {
GetK8sEntityToAggregateAttribute,
INFRA_MONITORING_K8S_PARAMS_KEYS, INFRA_MONITORING_K8S_PARAMS_KEYS,
K8sCategory, K8sCategory,
K8sEntityToAggregateAttributeMapping,
} from '../constants'; } from '../constants';
import K8sHeader from '../K8sHeader'; import K8sHeader from '../K8sHeader';
import LoadingContainer from '../LoadingContainer'; import LoadingContainer from '../LoadingContainer';
@ -137,6 +139,11 @@ function K8sDaemonSetsList({
} }
}, [quickFiltersLastUpdated]); }, [quickFiltersLastUpdated]);
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const createFiltersForSelectedRowData = ( const createFiltersForSelectedRowData = (
selectedRowData: K8sDaemonSetsRowData, selectedRowData: K8sDaemonSetsRowData,
groupBy: IBuilderQuery['groupBy'], groupBy: IBuilderQuery['groupBy'],
@ -196,6 +203,8 @@ function K8sDaemonSetsList({
queryKey: ['daemonSetList', fetchGroupedByRowDataQuery], queryKey: ['daemonSetList', fetchGroupedByRowDataQuery],
enabled: !!fetchGroupedByRowDataQuery && !!selectedRowData, enabled: !!fetchGroupedByRowDataQuery && !!selectedRowData,
}, },
undefined,
dotMetricsEnabled,
); );
const { const {
@ -204,8 +213,10 @@ function K8sDaemonSetsList({
} = useGetAggregateKeys( } = useGetAggregateKeys(
{ {
dataSource: currentQuery.builder.queryData[0].dataSource, dataSource: currentQuery.builder.queryData[0].dataSource,
aggregateAttribute: aggregateAttribute: GetK8sEntityToAggregateAttribute(
K8sEntityToAggregateAttributeMapping[K8sCategory.DAEMONSETS], K8sCategory.DAEMONSETS,
dotMetricsEnabled,
),
aggregateOperator: 'noop', aggregateOperator: 'noop',
searchText: '', searchText: '',
tagType: '', tagType: '',
@ -246,6 +257,8 @@ function K8sDaemonSetsList({
queryKey: ['daemonSetList', query], queryKey: ['daemonSetList', query],
enabled: !!query, enabled: !!query,
}, },
undefined,
dotMetricsEnabled,
); );
const daemonSetsData = useMemo(() => data?.payload?.data?.records || [], [ const daemonSetsData = useMemo(() => data?.payload?.data?.records || [], [

View File

@ -236,6 +236,12 @@ export const getK8sDaemonSetsListColumns = (
return columnsConfig as ColumnType<K8sDaemonSetsRowData>[]; return columnsConfig as ColumnType<K8sDaemonSetsRowData>[];
}; };
const dotToUnder: Record<string, keyof K8sDaemonSetsData['meta']> = {
'k8s.daemonset.name': 'k8s_daemonset_name',
'k8s.namespace.name': 'k8s_namespace_name',
'k8s.cluster.name': 'k8s_cluster_name',
};
const getGroupByEle = ( const getGroupByEle = (
daemonSet: K8sDaemonSetsData, daemonSet: K8sDaemonSetsData,
groupBy: IBuilderQuery['groupBy'], groupBy: IBuilderQuery['groupBy'],
@ -243,7 +249,13 @@ const getGroupByEle = (
const groupByValues: string[] = []; const groupByValues: string[] = [];
groupBy.forEach((group) => { groupBy.forEach((group) => {
groupByValues.push(daemonSet.meta[group.key as keyof typeof daemonSet.meta]); const rawKey = group.key as string;
// Choose mapped key if present, otherwise use rawKey
const metaKey = (dotToUnder[rawKey] ?? rawKey) as keyof typeof daemonSet.meta;
const value = daemonSet.meta[metaKey];
groupByValues.push(value);
}); });
return ( return (

View File

@ -29,11 +29,13 @@ import { AppState } from 'store/reducers';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData'; import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
import { GlobalReducer } from 'types/reducer/globalTime'; import { GlobalReducer } from 'types/reducer/globalTime';
import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App';
import { getOrderByFromParams } from '../commonUtils'; import { getOrderByFromParams } from '../commonUtils';
import { import {
GetK8sEntityToAggregateAttribute,
INFRA_MONITORING_K8S_PARAMS_KEYS, INFRA_MONITORING_K8S_PARAMS_KEYS,
K8sCategory, K8sCategory,
K8sEntityToAggregateAttributeMapping,
} from '../constants'; } from '../constants';
import K8sHeader from '../K8sHeader'; import K8sHeader from '../K8sHeader';
import LoadingContainer from '../LoadingContainer'; import LoadingContainer from '../LoadingContainer';
@ -138,6 +140,11 @@ function K8sDeploymentsList({
} }
}, [quickFiltersLastUpdated]); }, [quickFiltersLastUpdated]);
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const createFiltersForSelectedRowData = ( const createFiltersForSelectedRowData = (
selectedRowData: K8sDeploymentsRowData, selectedRowData: K8sDeploymentsRowData,
groupBy: IBuilderQuery['groupBy'], groupBy: IBuilderQuery['groupBy'],
@ -197,6 +204,8 @@ function K8sDeploymentsList({
queryKey: ['deploymentList', fetchGroupedByRowDataQuery], queryKey: ['deploymentList', fetchGroupedByRowDataQuery],
enabled: !!fetchGroupedByRowDataQuery && !!selectedRowData, enabled: !!fetchGroupedByRowDataQuery && !!selectedRowData,
}, },
undefined,
dotMetricsEnabled,
); );
const { const {
@ -205,8 +214,10 @@ function K8sDeploymentsList({
} = useGetAggregateKeys( } = useGetAggregateKeys(
{ {
dataSource: currentQuery.builder.queryData[0].dataSource, dataSource: currentQuery.builder.queryData[0].dataSource,
aggregateAttribute: aggregateAttribute: GetK8sEntityToAggregateAttribute(
K8sEntityToAggregateAttributeMapping[K8sCategory.DEPLOYMENTS], K8sCategory.DEPLOYMENTS,
dotMetricsEnabled,
),
aggregateOperator: 'noop', aggregateOperator: 'noop',
searchText: '', searchText: '',
tagType: '', tagType: '',
@ -247,6 +258,8 @@ function K8sDeploymentsList({
queryKey: ['deploymentList', query], queryKey: ['deploymentList', query],
enabled: !!query, enabled: !!query,
}, },
undefined,
dotMetricsEnabled,
); );
const deploymentsData = useMemo(() => data?.payload?.data?.records || [], [ const deploymentsData = useMemo(() => data?.payload?.data?.records || [], [

View File

@ -226,6 +226,12 @@ export const getK8sDeploymentsListColumns = (
return columnsConfig as ColumnType<K8sDeploymentsRowData>[]; return columnsConfig as ColumnType<K8sDeploymentsRowData>[];
}; };
const dotToUnder: Record<string, keyof K8sDeploymentsData['meta']> = {
'k8s.deployment.name': 'k8s_deployment_name',
'k8s.namespace.name': 'k8s_namespace_name',
'k8s.cluster.name': 'k8s_cluster_name',
};
const getGroupByEle = ( const getGroupByEle = (
deployment: K8sDeploymentsData, deployment: K8sDeploymentsData,
groupBy: IBuilderQuery['groupBy'], groupBy: IBuilderQuery['groupBy'],
@ -233,9 +239,14 @@ const getGroupByEle = (
const groupByValues: string[] = []; const groupByValues: string[] = [];
groupBy.forEach((group) => { groupBy.forEach((group) => {
groupByValues.push( const rawKey = group.key as string;
deployment.meta[group.key as keyof typeof deployment.meta],
); // Choose mapped key if present, otherwise use rawKey
const metaKey = (dotToUnder[rawKey] ??
rawKey) as keyof typeof deployment.meta;
const value = deployment.meta[metaKey];
groupByValues.push(value);
}); });
return ( return (

View File

@ -29,6 +29,9 @@ import { SuccessResponse } from 'types/api';
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange'; import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
import { Options } from 'uplot'; import { Options } from 'uplot';
import { FeatureKeys } from '../../../../constants/features';
import { useAppContext } from '../../../../providers/App/App';
interface EntityMetricsProps<T> { interface EntityMetricsProps<T> {
timeRange: { timeRange: {
startTime: number; startTime: number;
@ -49,6 +52,7 @@ interface EntityMetricsProps<T> {
node: T, node: T,
start: number, start: number,
end: number, end: number,
dotMetricsEnabled: boolean,
) => GetQueryResultsProps[]; ) => GetQueryResultsProps[];
queryKey: string; queryKey: string;
category: K8sCategory; category: K8sCategory;
@ -65,9 +69,25 @@ function EntityMetrics<T>({
queryKey, queryKey,
category, category,
}: EntityMetricsProps<T>): JSX.Element { }: EntityMetricsProps<T>): JSX.Element {
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const queryPayloads = useMemo( const queryPayloads = useMemo(
() => getEntityQueryPayload(entity, timeRange.startTime, timeRange.endTime), () =>
[getEntityQueryPayload, entity, timeRange.startTime, timeRange.endTime], getEntityQueryPayload(
entity,
timeRange.startTime,
timeRange.endTime,
dotMetricsEnabled,
),
[
getEntityQueryPayload,
entity,
timeRange.startTime,
timeRange.endTime,
dotMetricsEnabled,
],
); );
const queries = useQueries( const queries = useQueries(

View File

@ -26,19 +26,21 @@ import { useState } from 'react';
import { useSearchParams } from 'react-router-dom-v5-compat'; import { useSearchParams } from 'react-router-dom-v5-compat';
import { Query } from 'types/api/queryBuilder/queryBuilderData'; import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { FeatureKeys } from '../../constants/features';
import { useAppContext } from '../../providers/App/App';
import K8sClustersList from './Clusters/K8sClustersList'; import K8sClustersList from './Clusters/K8sClustersList';
import { import {
ClustersQuickFiltersConfig, GetClustersQuickFiltersConfig,
DaemonSetsQuickFiltersConfig, GetDaemonsetsQuickFiltersConfig,
DeploymentsQuickFiltersConfig, GetDeploymentsQuickFiltersConfig,
GetJobsQuickFiltersConfig,
GetNamespaceQuickFiltersConfig,
GetNodesQuickFiltersConfig,
GetPodsQuickFiltersConfig,
GetStatefulsetsQuickFiltersConfig,
GetVolumesQuickFiltersConfig,
INFRA_MONITORING_K8S_PARAMS_KEYS, INFRA_MONITORING_K8S_PARAMS_KEYS,
JobsQuickFiltersConfig,
K8sCategories, K8sCategories,
NamespaceQuickFiltersConfig,
NodesQuickFiltersConfig,
PodsQuickFiltersConfig,
StatefulsetsQuickFiltersConfig,
VolumesQuickFiltersConfig,
} from './constants'; } from './constants';
import K8sDaemonSetsList from './DaemonSets/K8sDaemonSetsList'; import K8sDaemonSetsList from './DaemonSets/K8sDaemonSetsList';
import K8sDeploymentsList from './Deployments/K8sDeploymentsList'; import K8sDeploymentsList from './Deployments/K8sDeploymentsList';
@ -74,6 +76,11 @@ export default function InfraMonitoringK8s(): JSX.Element {
entityVersion: '', entityVersion: '',
}); });
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const handleFilterChange = (query: Query): void => { const handleFilterChange = (query: Query): void => {
// update the current query with the new filters // update the current query with the new filters
// in infra monitoring k8s, we are using only one query, hence updating the 0th index of queryData // in infra monitoring k8s, we are using only one query, hence updating the 0th index of queryData
@ -109,7 +116,7 @@ export default function InfraMonitoringK8s(): JSX.Element {
children: ( children: (
<QuickFilters <QuickFilters
source={QuickFiltersSource.INFRA_MONITORING} source={QuickFiltersSource.INFRA_MONITORING}
config={PodsQuickFiltersConfig} config={GetPodsQuickFiltersConfig(dotMetricsEnabled)}
handleFilterVisibilityChange={handleFilterVisibilityChange} handleFilterVisibilityChange={handleFilterVisibilityChange}
onFilterChange={handleFilterChange} onFilterChange={handleFilterChange}
/> />
@ -129,7 +136,7 @@ export default function InfraMonitoringK8s(): JSX.Element {
children: ( children: (
<QuickFilters <QuickFilters
source={QuickFiltersSource.INFRA_MONITORING} source={QuickFiltersSource.INFRA_MONITORING}
config={NodesQuickFiltersConfig} config={GetNodesQuickFiltersConfig(dotMetricsEnabled)}
handleFilterVisibilityChange={handleFilterVisibilityChange} handleFilterVisibilityChange={handleFilterVisibilityChange}
onFilterChange={handleFilterChange} onFilterChange={handleFilterChange}
/> />
@ -152,7 +159,7 @@ export default function InfraMonitoringK8s(): JSX.Element {
children: ( children: (
<QuickFilters <QuickFilters
source={QuickFiltersSource.INFRA_MONITORING} source={QuickFiltersSource.INFRA_MONITORING}
config={NamespaceQuickFiltersConfig} config={GetNamespaceQuickFiltersConfig(dotMetricsEnabled)}
handleFilterVisibilityChange={handleFilterVisibilityChange} handleFilterVisibilityChange={handleFilterVisibilityChange}
onFilterChange={handleFilterChange} onFilterChange={handleFilterChange}
/> />
@ -172,7 +179,7 @@ export default function InfraMonitoringK8s(): JSX.Element {
children: ( children: (
<QuickFilters <QuickFilters
source={QuickFiltersSource.INFRA_MONITORING} source={QuickFiltersSource.INFRA_MONITORING}
config={ClustersQuickFiltersConfig} config={GetClustersQuickFiltersConfig(dotMetricsEnabled)}
handleFilterVisibilityChange={handleFilterVisibilityChange} handleFilterVisibilityChange={handleFilterVisibilityChange}
onFilterChange={handleFilterChange} onFilterChange={handleFilterChange}
/> />
@ -192,7 +199,7 @@ export default function InfraMonitoringK8s(): JSX.Element {
children: ( children: (
<QuickFilters <QuickFilters
source={QuickFiltersSource.INFRA_MONITORING} source={QuickFiltersSource.INFRA_MONITORING}
config={DeploymentsQuickFiltersConfig} config={GetDeploymentsQuickFiltersConfig(dotMetricsEnabled)}
handleFilterVisibilityChange={handleFilterVisibilityChange} handleFilterVisibilityChange={handleFilterVisibilityChange}
onFilterChange={handleFilterChange} onFilterChange={handleFilterChange}
/> />
@ -212,7 +219,7 @@ export default function InfraMonitoringK8s(): JSX.Element {
children: ( children: (
<QuickFilters <QuickFilters
source={QuickFiltersSource.INFRA_MONITORING} source={QuickFiltersSource.INFRA_MONITORING}
config={JobsQuickFiltersConfig} config={GetJobsQuickFiltersConfig(dotMetricsEnabled)}
handleFilterVisibilityChange={handleFilterVisibilityChange} handleFilterVisibilityChange={handleFilterVisibilityChange}
onFilterChange={handleFilterChange} onFilterChange={handleFilterChange}
/> />
@ -232,7 +239,7 @@ export default function InfraMonitoringK8s(): JSX.Element {
children: ( children: (
<QuickFilters <QuickFilters
source={QuickFiltersSource.INFRA_MONITORING} source={QuickFiltersSource.INFRA_MONITORING}
config={DaemonSetsQuickFiltersConfig} config={GetDaemonsetsQuickFiltersConfig(dotMetricsEnabled)}
handleFilterVisibilityChange={handleFilterVisibilityChange} handleFilterVisibilityChange={handleFilterVisibilityChange}
onFilterChange={handleFilterChange} onFilterChange={handleFilterChange}
/> />
@ -255,7 +262,7 @@ export default function InfraMonitoringK8s(): JSX.Element {
children: ( children: (
<QuickFilters <QuickFilters
source={QuickFiltersSource.INFRA_MONITORING} source={QuickFiltersSource.INFRA_MONITORING}
config={StatefulsetsQuickFiltersConfig} config={GetStatefulsetsQuickFiltersConfig(dotMetricsEnabled)}
handleFilterVisibilityChange={handleFilterVisibilityChange} handleFilterVisibilityChange={handleFilterVisibilityChange}
onFilterChange={handleFilterChange} onFilterChange={handleFilterChange}
/> />
@ -275,7 +282,7 @@ export default function InfraMonitoringK8s(): JSX.Element {
children: ( children: (
<QuickFilters <QuickFilters
source={QuickFiltersSource.INFRA_MONITORING} source={QuickFiltersSource.INFRA_MONITORING}
config={VolumesQuickFiltersConfig} config={GetVolumesQuickFiltersConfig(dotMetricsEnabled)}
handleFilterVisibilityChange={handleFilterVisibilityChange} handleFilterVisibilityChange={handleFilterVisibilityChange}
onFilterChange={handleFilterChange} onFilterChange={handleFilterChange}
/> />

View File

@ -30,395 +30,415 @@ export const getJobMetricsQueryPayload = (
job: K8sJobsData, job: K8sJobsData,
start: number, start: number,
end: number, end: number,
): GetQueryResultsProps[] => [ dotMetricsEnabled: boolean,
{ ): GetQueryResultsProps[] => {
selectedTime: 'GLOBAL_TIME', const k8sPodCpuUtilizationKey = dotMetricsEnabled
graphType: PANEL_TYPES.TIME_SERIES, ? 'k8s.pod.cpu.utilization'
query: { : 'k8s_pod_cpu_utilization';
builder: { const k8sPodMemoryUsageKey = dotMetricsEnabled
queryData: [ ? 'k8s.pod.memory.usage'
: 'k8s_pod_memory_usage';
const k8sPodNetworkIoKey = dotMetricsEnabled
? 'k8s.pod.network.io'
: 'k8s_pod_network_io';
const k8sPodNetworkErrorsKey = dotMetricsEnabled
? 'k8s.pod.network.errors'
: 'k8s_pod_network_errors';
const k8sJobNameKey = dotMetricsEnabled ? 'k8s.job.name' : 'k8s_job_name';
const k8sNamespaceNameKey = dotMetricsEnabled
? 'k8s.namespace.name'
: 'k8s_namespace_name';
return [
{
selectedTime: 'GLOBAL_TIME',
graphType: PANEL_TYPES.TIME_SERIES,
query: {
builder: {
queryData: [
{
aggregateAttribute: {
dataType: DataTypes.Float64,
id: 'k8s_pod_cpu_utilization--float64--Gauge--true',
isColumn: true,
isJSON: false,
key: k8sPodCpuUtilizationKey,
type: 'Gauge',
},
aggregateOperator: 'avg',
dataSource: DataSource.METRICS,
disabled: false,
expression: 'A',
filters: {
items: [
{
id: '6b59b690',
key: {
dataType: DataTypes.String,
id: 'k8s_job_name--string--tag--false',
isColumn: false,
isJSON: false,
key: k8sJobNameKey,
type: 'tag',
},
op: '=',
value: job.jobName,
},
{
id: '47b3adae',
key: {
dataType: DataTypes.String,
id: 'k8s_namespace_name--string--tag--false',
isColumn: false,
isJSON: false,
key: k8sNamespaceNameKey,
type: 'tag',
},
op: '=',
value: job.meta.k8s_namespace_name,
},
],
op: 'AND',
},
functions: [],
groupBy: [],
having: [],
legend: 'usage',
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
},
],
queryFormulas: [],
},
clickhouse_sql: [
{ {
aggregateAttribute: {
dataType: DataTypes.Float64,
id: 'k8s_pod_cpu_utilization--float64--Gauge--true',
isColumn: true,
isJSON: false,
key: 'k8s_pod_cpu_utilization',
type: 'Gauge',
},
aggregateOperator: 'avg',
dataSource: DataSource.METRICS,
disabled: false, disabled: false,
expression: 'A', legend: '',
filters: { name: 'A',
items: [ query: '',
{
id: '6b59b690',
key: {
dataType: DataTypes.String,
id: 'k8s_job_name--string--tag--false',
isColumn: false,
isJSON: false,
key: 'k8s_job_name',
type: 'tag',
},
op: '=',
value: job.jobName,
},
{
id: '47b3adae',
key: {
dataType: DataTypes.String,
id: 'k8s_namespace_name--string--tag--false',
isColumn: false,
isJSON: false,
key: 'k8s_namespace_name',
type: 'tag',
},
op: '=',
value: job.meta.k8s_namespace_name,
},
],
op: 'AND',
},
functions: [],
groupBy: [],
having: [],
legend: 'usage',
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
}, },
], ],
queryFormulas: [], id: v4(),
}, promql: [
clickhouse_sql: [
{
disabled: false,
legend: '',
name: 'A',
query: '',
},
],
id: v4(),
promql: [
{
disabled: false,
legend: '',
name: 'A',
query: '',
},
],
queryType: EQueryType.QUERY_BUILDER,
},
variables: {},
formatForWeb: false,
start,
end,
},
{
selectedTime: 'GLOBAL_TIME',
graphType: PANEL_TYPES.TIME_SERIES,
query: {
builder: {
queryData: [
{ {
aggregateAttribute: {
dataType: DataTypes.Float64,
id: 'k8s_pod_memory_usage--float64--Gauge--true',
isColumn: true,
isJSON: false,
key: 'k8s_pod_memory_usage',
type: 'Gauge',
},
aggregateOperator: 'avg',
dataSource: DataSource.METRICS,
disabled: false, disabled: false,
expression: 'A', legend: '',
filters: { name: 'A',
items: [ query: '',
{
id: '8c217f4d',
key: {
dataType: DataTypes.String,
id: 'k8s_job_name--string--tag--false',
isColumn: false,
isJSON: false,
key: 'k8s_job_name',
type: 'tag',
},
op: '=',
value: job.jobName,
},
{
id: '47b3adae',
key: {
dataType: DataTypes.String,
id: 'k8s_namespace_name--string--tag--false',
isColumn: false,
isJSON: false,
key: 'k8s_namespace_name',
type: 'tag',
},
op: '=',
value: job.meta.k8s_namespace_name,
},
],
op: 'AND',
},
functions: [],
groupBy: [],
having: [],
legend: 'usage',
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
}, },
], ],
queryFormulas: [], queryType: EQueryType.QUERY_BUILDER,
}, },
clickhouse_sql: [ variables: {},
{ formatForWeb: false,
disabled: false, start,
legend: '', end,
name: 'A',
query: '',
},
],
id: v4(),
promql: [
{
disabled: false,
legend: '',
name: 'A',
query: '',
},
],
queryType: EQueryType.QUERY_BUILDER,
}, },
variables: {}, {
formatForWeb: false, selectedTime: 'GLOBAL_TIME',
start, graphType: PANEL_TYPES.TIME_SERIES,
end, query: {
}, builder: {
{ queryData: [
selectedTime: 'GLOBAL_TIME', {
graphType: PANEL_TYPES.TIME_SERIES, aggregateAttribute: {
query: { dataType: DataTypes.Float64,
builder: { id: 'k8s_pod_memory_usage--float64--Gauge--true',
queryData: [ isColumn: true,
isJSON: false,
key: k8sPodMemoryUsageKey,
type: 'Gauge',
},
aggregateOperator: 'avg',
dataSource: DataSource.METRICS,
disabled: false,
expression: 'A',
filters: {
items: [
{
id: '8c217f4d',
key: {
dataType: DataTypes.String,
id: 'k8s_job_name--string--tag--false',
isColumn: false,
isJSON: false,
key: k8sJobNameKey,
type: 'tag',
},
op: '=',
value: job.jobName,
},
{
id: '47b3adae',
key: {
dataType: DataTypes.String,
id: 'k8s_namespace_name--string--tag--false',
isColumn: false,
isJSON: false,
key: k8sNamespaceNameKey,
type: 'tag',
},
op: '=',
value: job.meta.k8s_namespace_name,
},
],
op: 'AND',
},
functions: [],
groupBy: [],
having: [],
legend: 'usage',
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'avg',
},
],
queryFormulas: [],
},
clickhouse_sql: [
{ {
aggregateAttribute: {
dataType: DataTypes.Float64,
id: 'k8s_pod_network_io--float64--Sum--true',
isColumn: true,
isJSON: false,
key: 'k8s_pod_network_io',
type: 'Sum',
},
aggregateOperator: 'rate',
dataSource: DataSource.METRICS,
disabled: false, disabled: false,
expression: 'A', legend: '',
filters: { name: 'A',
items: [ query: '',
{
id: '2bbf9d0c',
key: {
dataType: DataTypes.String,
id: 'k8s_job_name--string--tag--false',
isColumn: false,
isJSON: false,
key: 'k8s_job_name',
type: 'tag',
},
op: '=',
value: job.jobName,
},
{
id: '47b3adae',
key: {
dataType: DataTypes.String,
id: 'k8s_namespace_name--string--tag--false',
isColumn: false,
isJSON: false,
key: 'k8s_namespace_name',
type: 'tag',
},
op: '=',
value: job.meta.k8s_namespace_name,
},
],
op: 'AND',
},
functions: [],
groupBy: [
{
dataType: DataTypes.String,
id: 'direction--string--tag--false',
isColumn: false,
isJSON: false,
key: 'direction',
type: 'tag',
},
{
dataType: DataTypes.String,
id: 'interface--string--tag--false',
isColumn: false,
isJSON: false,
key: 'interface',
type: 'tag',
},
],
having: [],
legend: '{{direction}} :: {{interface}}',
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
}, },
], ],
queryFormulas: [], id: v4(),
}, promql: [
clickhouse_sql: [
{
disabled: false,
legend: '',
name: 'A',
query: '',
},
],
id: v4(),
promql: [
{
disabled: false,
legend: '',
name: 'A',
query: '',
},
],
queryType: EQueryType.QUERY_BUILDER,
},
variables: {},
formatForWeb: false,
start,
end,
},
{
selectedTime: 'GLOBAL_TIME',
graphType: PANEL_TYPES.TIME_SERIES,
query: {
builder: {
queryData: [
{ {
aggregateAttribute: {
dataType: DataTypes.Float64,
id: 'k8s_pod_network_errors--float64--Sum--true',
isColumn: true,
isJSON: false,
key: 'k8s_pod_network_errors',
type: 'Sum',
},
aggregateOperator: 'increase',
dataSource: DataSource.METRICS,
disabled: false, disabled: false,
expression: 'A', legend: '',
filters: { name: 'A',
items: [ query: '',
{
id: '448e6cf7',
key: {
dataType: DataTypes.String,
id: 'k8s_job_name--string--tag--false',
isColumn: false,
isJSON: false,
key: 'k8s_job_name',
type: 'tag',
},
op: '=',
value: job.jobName,
},
{
id: '47b3adae',
key: {
dataType: DataTypes.String,
id: 'k8s_namespace_name--string--tag--false',
isColumn: false,
isJSON: false,
key: 'k8s_namespace_name',
type: 'tag',
},
op: '=',
value: job.meta.k8s_namespace_name,
},
],
op: 'AND',
},
functions: [],
groupBy: [
{
dataType: DataTypes.String,
id: 'direction--string--tag--false',
isColumn: false,
isJSON: false,
key: 'direction',
type: 'tag',
},
{
dataType: DataTypes.String,
id: 'interface--string--tag--false',
isColumn: false,
isJSON: false,
key: 'interface',
type: 'tag',
},
],
having: [],
legend: '{{direction}} :: {{interface}}',
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'increase',
}, },
], ],
queryFormulas: [], queryType: EQueryType.QUERY_BUILDER,
}, },
clickhouse_sql: [ variables: {},
{ formatForWeb: false,
disabled: false, start,
legend: '', end,
name: 'A',
query: '',
},
],
id: v4(),
promql: [
{
disabled: false,
legend: '',
name: 'A',
query: '',
},
],
queryType: EQueryType.QUERY_BUILDER,
}, },
variables: {}, {
formatForWeb: false, selectedTime: 'GLOBAL_TIME',
start, graphType: PANEL_TYPES.TIME_SERIES,
end, query: {
}, builder: {
]; queryData: [
{
aggregateAttribute: {
dataType: DataTypes.Float64,
id: 'k8s_pod_network_io--float64--Sum--true',
isColumn: true,
isJSON: false,
key: k8sPodNetworkIoKey,
type: 'Sum',
},
aggregateOperator: 'rate',
dataSource: DataSource.METRICS,
disabled: false,
expression: 'A',
filters: {
items: [
{
id: '2bbf9d0c',
key: {
dataType: DataTypes.String,
id: 'k8s_job_name--string--tag--false',
isColumn: false,
isJSON: false,
key: k8sJobNameKey,
type: 'tag',
},
op: '=',
value: job.jobName,
},
{
id: '47b3adae',
key: {
dataType: DataTypes.String,
id: 'k8s_namespace_name--string--tag--false',
isColumn: false,
isJSON: false,
key: k8sNamespaceNameKey,
type: 'tag',
},
op: '=',
value: job.meta.k8s_namespace_name,
},
],
op: 'AND',
},
functions: [],
groupBy: [
{
dataType: DataTypes.String,
id: 'direction--string--tag--false',
isColumn: false,
isJSON: false,
key: 'direction',
type: 'tag',
},
{
dataType: DataTypes.String,
id: 'interface--string--tag--false',
isColumn: false,
isJSON: false,
key: 'interface',
type: 'tag',
},
],
having: [],
legend: '{{direction}} :: {{interface}}',
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'rate',
},
],
queryFormulas: [],
},
clickhouse_sql: [
{
disabled: false,
legend: '',
name: 'A',
query: '',
},
],
id: v4(),
promql: [
{
disabled: false,
legend: '',
name: 'A',
query: '',
},
],
queryType: EQueryType.QUERY_BUILDER,
},
variables: {},
formatForWeb: false,
start,
end,
},
{
selectedTime: 'GLOBAL_TIME',
graphType: PANEL_TYPES.TIME_SERIES,
query: {
builder: {
queryData: [
{
aggregateAttribute: {
dataType: DataTypes.Float64,
id: 'k8s_pod_network_errors--float64--Sum--true',
isColumn: true,
isJSON: false,
key: k8sPodNetworkErrorsKey,
type: 'Sum',
},
aggregateOperator: 'increase',
dataSource: DataSource.METRICS,
disabled: false,
expression: 'A',
filters: {
items: [
{
id: '448e6cf7',
key: {
dataType: DataTypes.String,
id: 'k8s_job_name--string--tag--false',
isColumn: false,
isJSON: false,
key: k8sJobNameKey,
type: 'tag',
},
op: '=',
value: job.jobName,
},
{
id: '47b3adae',
key: {
dataType: DataTypes.String,
id: 'k8s_namespace_name--string--tag--false',
isColumn: false,
isJSON: false,
key: k8sNamespaceNameKey,
type: 'tag',
},
op: '=',
value: job.meta.k8s_namespace_name,
},
],
op: 'AND',
},
functions: [],
groupBy: [
{
dataType: DataTypes.String,
id: 'direction--string--tag--false',
isColumn: false,
isJSON: false,
key: 'direction',
type: 'tag',
},
{
dataType: DataTypes.String,
id: 'interface--string--tag--false',
isColumn: false,
isJSON: false,
key: 'interface',
type: 'tag',
},
],
having: [],
legend: '{{direction}} :: {{interface}}',
limit: null,
orderBy: [],
queryName: 'A',
reduceTo: 'avg',
spaceAggregation: 'sum',
stepInterval: 60,
timeAggregation: 'increase',
},
],
queryFormulas: [],
},
clickhouse_sql: [
{
disabled: false,
legend: '',
name: 'A',
query: '',
},
],
id: v4(),
promql: [
{
disabled: false,
legend: '',
name: 'A',
query: '',
},
],
queryType: EQueryType.QUERY_BUILDER,
},
variables: {},
formatForWeb: false,
start,
end,
},
];
};

View File

@ -29,11 +29,13 @@ import { AppState } from 'store/reducers';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData'; import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
import { GlobalReducer } from 'types/reducer/globalTime'; import { GlobalReducer } from 'types/reducer/globalTime';
import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App';
import { getOrderByFromParams } from '../commonUtils'; import { getOrderByFromParams } from '../commonUtils';
import { import {
GetK8sEntityToAggregateAttribute,
INFRA_MONITORING_K8S_PARAMS_KEYS, INFRA_MONITORING_K8S_PARAMS_KEYS,
K8sCategory, K8sCategory,
K8sEntityToAggregateAttributeMapping,
} from '../constants'; } from '../constants';
import K8sHeader from '../K8sHeader'; import K8sHeader from '../K8sHeader';
import LoadingContainer from '../LoadingContainer'; import LoadingContainer from '../LoadingContainer';
@ -132,6 +134,11 @@ function K8sJobsList({
} }
}, [quickFiltersLastUpdated]); }, [quickFiltersLastUpdated]);
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const createFiltersForSelectedRowData = ( const createFiltersForSelectedRowData = (
selectedRowData: K8sJobsRowData, selectedRowData: K8sJobsRowData,
groupBy: IBuilderQuery['groupBy'], groupBy: IBuilderQuery['groupBy'],
@ -185,10 +192,15 @@ function K8sJobsList({
isLoading: isLoadingGroupedByRowData, isLoading: isLoadingGroupedByRowData,
isError: isErrorGroupedByRowData, isError: isErrorGroupedByRowData,
refetch: fetchGroupedByRowData, refetch: fetchGroupedByRowData,
} = useGetK8sJobsList(fetchGroupedByRowDataQuery as K8sJobsListPayload, { } = useGetK8sJobsList(
queryKey: ['jobList', fetchGroupedByRowDataQuery], fetchGroupedByRowDataQuery as K8sJobsListPayload,
enabled: !!fetchGroupedByRowDataQuery && !!selectedRowData, {
}); queryKey: ['jobList', fetchGroupedByRowDataQuery],
enabled: !!fetchGroupedByRowDataQuery && !!selectedRowData,
},
undefined,
dotMetricsEnabled,
);
const { const {
data: groupByFiltersData, data: groupByFiltersData,
@ -196,7 +208,10 @@ function K8sJobsList({
} = useGetAggregateKeys( } = useGetAggregateKeys(
{ {
dataSource: currentQuery.builder.queryData[0].dataSource, dataSource: currentQuery.builder.queryData[0].dataSource,
aggregateAttribute: K8sEntityToAggregateAttributeMapping[K8sCategory.JOBS], aggregateAttribute: GetK8sEntityToAggregateAttribute(
K8sCategory.JOBS,
dotMetricsEnabled,
),
aggregateOperator: 'noop', aggregateOperator: 'noop',
searchText: '', searchText: '',
tagType: '', tagType: '',
@ -242,6 +257,8 @@ function K8sJobsList({
queryKey: ['jobList', query], queryKey: ['jobList', query],
enabled: !!query, enabled: !!query,
}, },
undefined,
dotMetricsEnabled,
); );
const jobsData = useMemo(() => data?.payload?.data?.records || [], [data]); const jobsData = useMemo(() => data?.payload?.data?.records || [], [data]);

View File

@ -263,6 +263,12 @@ export const getK8sJobsListColumns = (
return columnsConfig as ColumnType<K8sJobsRowData>[]; return columnsConfig as ColumnType<K8sJobsRowData>[];
}; };
const dotToUnder: Record<string, keyof K8sJobsData['meta']> = {
'k8s.job.name': 'k8s_job_name',
'k8s.namespace.name': 'k8s_namespace_name',
'k8s.cluster.name': 'k8s_cluster_name',
};
const getGroupByEle = ( const getGroupByEle = (
job: K8sJobsData, job: K8sJobsData,
groupBy: IBuilderQuery['groupBy'], groupBy: IBuilderQuery['groupBy'],
@ -270,7 +276,13 @@ const getGroupByEle = (
const groupByValues: string[] = []; const groupByValues: string[] = [];
groupBy.forEach((group) => { groupBy.forEach((group) => {
groupByValues.push(job.meta[group.key as keyof typeof job.meta]); const rawKey = group.key as string;
// Choose mapped key if present, otherwise use rawKey
const metaKey = (dotToUnder[rawKey] ?? rawKey) as keyof typeof job.meta;
const value = job.meta[metaKey];
groupByValues.push(value);
}); });
return ( return (

View File

@ -28,11 +28,13 @@ import { AppState } from 'store/reducers';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData'; import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
import { GlobalReducer } from 'types/reducer/globalTime'; import { GlobalReducer } from 'types/reducer/globalTime';
import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App';
import { getOrderByFromParams } from '../commonUtils'; import { getOrderByFromParams } from '../commonUtils';
import { import {
GetK8sEntityToAggregateAttribute,
INFRA_MONITORING_K8S_PARAMS_KEYS, INFRA_MONITORING_K8S_PARAMS_KEYS,
K8sCategory, K8sCategory,
K8sEntityToAggregateAttributeMapping,
} from '../constants'; } from '../constants';
import K8sHeader from '../K8sHeader'; import K8sHeader from '../K8sHeader';
import LoadingContainer from '../LoadingContainer'; import LoadingContainer from '../LoadingContainer';
@ -136,6 +138,11 @@ function K8sNamespacesList({
} }
}, [quickFiltersLastUpdated]); }, [quickFiltersLastUpdated]);
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const createFiltersForSelectedRowData = ( const createFiltersForSelectedRowData = (
selectedRowData: K8sNamespacesRowData, selectedRowData: K8sNamespacesRowData,
groupBy: IBuilderQuery['groupBy'], groupBy: IBuilderQuery['groupBy'],
@ -195,6 +202,8 @@ function K8sNamespacesList({
queryKey: ['namespaceList', fetchGroupedByRowDataQuery], queryKey: ['namespaceList', fetchGroupedByRowDataQuery],
enabled: !!fetchGroupedByRowDataQuery && !!selectedRowData, enabled: !!fetchGroupedByRowDataQuery && !!selectedRowData,
}, },
undefined,
dotMetricsEnabled,
); );
const { const {
@ -203,8 +212,10 @@ function K8sNamespacesList({
} = useGetAggregateKeys( } = useGetAggregateKeys(
{ {
dataSource: currentQuery.builder.queryData[0].dataSource, dataSource: currentQuery.builder.queryData[0].dataSource,
aggregateAttribute: aggregateAttribute: GetK8sEntityToAggregateAttribute(
K8sEntityToAggregateAttributeMapping[K8sCategory.NAMESPACES], K8sCategory.NAMESPACES,
dotMetricsEnabled,
),
aggregateOperator: 'noop', aggregateOperator: 'noop',
searchText: '', searchText: '',
tagType: '', tagType: '',
@ -245,6 +256,8 @@ function K8sNamespacesList({
queryKey: ['namespaceList', query], queryKey: ['namespaceList', query],
enabled: !!query, enabled: !!query,
}, },
undefined,
dotMetricsEnabled,
); );
const namespacesData = useMemo(() => data?.payload?.data?.records || [], [ const namespacesData = useMemo(() => data?.payload?.data?.records || [], [

View File

@ -122,6 +122,11 @@ export const getK8sNamespacesListColumns = (
return columnsConfig as ColumnType<K8sNamespacesRowData>[]; return columnsConfig as ColumnType<K8sNamespacesRowData>[];
}; };
const dotToUnder: Record<string, keyof K8sNamespacesData['meta']> = {
'k8s.namespace.name': 'k8s_namespace_name',
'k8s.cluster.name': 'k8s_cluster_name',
};
const getGroupByEle = ( const getGroupByEle = (
namespace: K8sNamespacesData, namespace: K8sNamespacesData,
groupBy: IBuilderQuery['groupBy'], groupBy: IBuilderQuery['groupBy'],
@ -129,7 +134,13 @@ const getGroupByEle = (
const groupByValues: string[] = []; const groupByValues: string[] = [];
groupBy.forEach((group) => { groupBy.forEach((group) => {
groupByValues.push(namespace.meta[group.key as keyof typeof namespace.meta]); const rawKey = group.key as string;
// Choose mapped key if present, otherwise use rawKey
const metaKey = (dotToUnder[rawKey] ?? rawKey) as keyof typeof namespace.meta;
const value = namespace.meta[metaKey];
groupByValues.push(value);
}); });
return ( return (

View File

@ -28,11 +28,13 @@ import { AppState } from 'store/reducers';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData'; import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
import { GlobalReducer } from 'types/reducer/globalTime'; import { GlobalReducer } from 'types/reducer/globalTime';
import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App';
import { getOrderByFromParams } from '../commonUtils'; import { getOrderByFromParams } from '../commonUtils';
import { import {
GetK8sEntityToAggregateAttribute,
INFRA_MONITORING_K8S_PARAMS_KEYS, INFRA_MONITORING_K8S_PARAMS_KEYS,
K8sCategory, K8sCategory,
K8sEntityToAggregateAttributeMapping,
} from '../constants'; } from '../constants';
import K8sHeader from '../K8sHeader'; import K8sHeader from '../K8sHeader';
import LoadingContainer from '../LoadingContainer'; import LoadingContainer from '../LoadingContainer';
@ -130,6 +132,11 @@ function K8sNodesList({
} }
}, [quickFiltersLastUpdated]); }, [quickFiltersLastUpdated]);
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const createFiltersForSelectedRowData = ( const createFiltersForSelectedRowData = (
selectedRowData: K8sNodesRowData, selectedRowData: K8sNodesRowData,
groupBy: IBuilderQuery['groupBy'], groupBy: IBuilderQuery['groupBy'],
@ -183,10 +190,15 @@ function K8sNodesList({
isLoading: isLoadingGroupedByRowData, isLoading: isLoadingGroupedByRowData,
isError: isErrorGroupedByRowData, isError: isErrorGroupedByRowData,
refetch: fetchGroupedByRowData, refetch: fetchGroupedByRowData,
} = useGetK8sNodesList(fetchGroupedByRowDataQuery as K8sNodesListPayload, { } = useGetK8sNodesList(
queryKey: ['nodeList', fetchGroupedByRowDataQuery], fetchGroupedByRowDataQuery as K8sNodesListPayload,
enabled: !!fetchGroupedByRowDataQuery && !!selectedRowData, {
}); queryKey: ['nodeList', fetchGroupedByRowDataQuery],
enabled: !!fetchGroupedByRowDataQuery && !!selectedRowData,
},
undefined,
dotMetricsEnabled,
);
const { const {
data: groupByFiltersData, data: groupByFiltersData,
@ -194,7 +206,10 @@ function K8sNodesList({
} = useGetAggregateKeys( } = useGetAggregateKeys(
{ {
dataSource: currentQuery.builder.queryData[0].dataSource, dataSource: currentQuery.builder.queryData[0].dataSource,
aggregateAttribute: K8sEntityToAggregateAttributeMapping[K8sCategory.NODES], aggregateAttribute: GetK8sEntityToAggregateAttribute(
K8sCategory.NODES,
dotMetricsEnabled,
),
aggregateOperator: 'noop', aggregateOperator: 'noop',
searchText: '', searchText: '',
tagType: '', tagType: '',
@ -240,6 +255,8 @@ function K8sNodesList({
queryKey: ['nodeList', query], queryKey: ['nodeList', query],
enabled: !!query, enabled: !!query,
}, },
undefined,
dotMetricsEnabled,
); );
const nodesData = useMemo(() => data?.payload?.data?.records || [], [data]); const nodesData = useMemo(() => data?.payload?.data?.records || [], [data]);

View File

@ -152,6 +152,12 @@ export const getK8sNodesListColumns = (
return columnsConfig as ColumnType<K8sNodesRowData>[]; return columnsConfig as ColumnType<K8sNodesRowData>[];
}; };
const dotToUnder: Record<string, keyof K8sNodesData['meta']> = {
'k8s.node.name': 'k8s_node_name',
'k8s.cluster.name': 'k8s_cluster_name',
'k8s.node.uid': 'k8s_node_uid',
};
const getGroupByEle = ( const getGroupByEle = (
node: K8sNodesData, node: K8sNodesData,
groupBy: IBuilderQuery['groupBy'], groupBy: IBuilderQuery['groupBy'],
@ -159,7 +165,14 @@ const getGroupByEle = (
const groupByValues: string[] = []; const groupByValues: string[] = [];
groupBy.forEach((group) => { groupBy.forEach((group) => {
groupByValues.push(node.meta[group.key as keyof typeof node.meta]); const rawKey = group.key as string;
// Choose mapped key if present, otherwise use rawKey
const metaKey = (dotToUnder[rawKey] ?? rawKey) as keyof typeof node.meta;
const value = node.meta[metaKey];
groupByValues.push(value);
}); });
return ( return (

View File

@ -29,11 +29,13 @@ import { AppState } from 'store/reducers';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData'; import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
import { GlobalReducer } from 'types/reducer/globalTime'; import { GlobalReducer } from 'types/reducer/globalTime';
import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App';
import { getOrderByFromParams } from '../commonUtils'; import { getOrderByFromParams } from '../commonUtils';
import { import {
GetK8sEntityToAggregateAttribute,
INFRA_MONITORING_K8S_PARAMS_KEYS, INFRA_MONITORING_K8S_PARAMS_KEYS,
K8sCategory, K8sCategory,
K8sEntityToAggregateAttributeMapping,
} from '../constants'; } from '../constants';
import K8sHeader from '../K8sHeader'; import K8sHeader from '../K8sHeader';
import LoadingContainer from '../LoadingContainer'; import LoadingContainer from '../LoadingContainer';
@ -118,13 +120,21 @@ function K8sPodsList({
[currentQuery?.builder?.queryData], [currentQuery?.builder?.queryData],
); );
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const { const {
data: groupByFiltersData, data: groupByFiltersData,
isLoading: isLoadingGroupByFilters, isLoading: isLoadingGroupByFilters,
} = useGetAggregateKeys( } = useGetAggregateKeys(
{ {
dataSource: currentQuery.builder.queryData[0].dataSource, dataSource: currentQuery.builder.queryData[0].dataSource,
aggregateAttribute: K8sEntityToAggregateAttributeMapping[K8sCategory.PODS], aggregateAttribute: GetK8sEntityToAggregateAttribute(
K8sCategory.PODS,
dotMetricsEnabled,
),
aggregateOperator: 'noop', aggregateOperator: 'noop',
searchText: '', searchText: '',
tagType: '', tagType: '',
@ -201,6 +211,8 @@ function K8sPodsList({
queryKey: ['hostList', query], queryKey: ['hostList', query],
enabled: !!query, enabled: !!query,
}, },
undefined,
dotMetricsEnabled,
); );
const createFiltersForSelectedRowData = ( const createFiltersForSelectedRowData = (
@ -255,10 +267,15 @@ function K8sPodsList({
isLoading: isLoadingGroupedByRowData, isLoading: isLoadingGroupedByRowData,
isError: isErrorGroupedByRowData, isError: isErrorGroupedByRowData,
refetch: fetchGroupedByRowData, refetch: fetchGroupedByRowData,
} = useGetK8sPodsList(fetchGroupedByRowDataQuery as K8sPodsListPayload, { } = useGetK8sPodsList(
queryKey: ['hostList', fetchGroupedByRowDataQuery], fetchGroupedByRowDataQuery as K8sPodsListPayload,
enabled: !!fetchGroupedByRowDataQuery && !!selectedRowData, {
}); queryKey: ['hostList', fetchGroupedByRowDataQuery],
enabled: !!fetchGroupedByRowDataQuery && !!selectedRowData,
},
undefined,
dotMetricsEnabled,
);
const podsData = useMemo(() => data?.payload?.data?.records || [], [data]); const podsData = useMemo(() => data?.payload?.data?.records || [], [data]);
const totalCount = data?.payload?.data?.total || 0; const totalCount = data?.payload?.data?.total || 0;

File diff suppressed because it is too large Load Diff

View File

@ -29,11 +29,13 @@ import { AppState } from 'store/reducers';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData'; import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
import { GlobalReducer } from 'types/reducer/globalTime'; import { GlobalReducer } from 'types/reducer/globalTime';
import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App';
import { getOrderByFromParams } from '../commonUtils'; import { getOrderByFromParams } from '../commonUtils';
import { import {
GetK8sEntityToAggregateAttribute,
INFRA_MONITORING_K8S_PARAMS_KEYS, INFRA_MONITORING_K8S_PARAMS_KEYS,
K8sCategory, K8sCategory,
K8sEntityToAggregateAttributeMapping,
} from '../constants'; } from '../constants';
import K8sHeader from '../K8sHeader'; import K8sHeader from '../K8sHeader';
import LoadingContainer from '../LoadingContainer'; import LoadingContainer from '../LoadingContainer';
@ -137,6 +139,11 @@ function K8sStatefulSetsList({
} }
}, [quickFiltersLastUpdated]); }, [quickFiltersLastUpdated]);
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const createFiltersForSelectedRowData = ( const createFiltersForSelectedRowData = (
selectedRowData: K8sStatefulSetsRowData, selectedRowData: K8sStatefulSetsRowData,
groupBy: IBuilderQuery['groupBy'], groupBy: IBuilderQuery['groupBy'],
@ -196,6 +203,8 @@ function K8sStatefulSetsList({
queryKey: ['statefulSetList', fetchGroupedByRowDataQuery], queryKey: ['statefulSetList', fetchGroupedByRowDataQuery],
enabled: !!fetchGroupedByRowDataQuery && !!selectedRowData, enabled: !!fetchGroupedByRowDataQuery && !!selectedRowData,
}, },
undefined,
dotMetricsEnabled,
); );
const { const {
@ -204,8 +213,10 @@ function K8sStatefulSetsList({
} = useGetAggregateKeys( } = useGetAggregateKeys(
{ {
dataSource: currentQuery.builder.queryData[0].dataSource, dataSource: currentQuery.builder.queryData[0].dataSource,
aggregateAttribute: aggregateAttribute: GetK8sEntityToAggregateAttribute(
K8sEntityToAggregateAttributeMapping[K8sCategory.STATEFULSETS], K8sCategory.STATEFULSETS,
dotMetricsEnabled,
),
aggregateOperator: 'noop', aggregateOperator: 'noop',
searchText: '', searchText: '',
tagType: '', tagType: '',
@ -251,6 +262,8 @@ function K8sStatefulSetsList({
queryKey: ['statefulSetList', query], queryKey: ['statefulSetList', query],
enabled: !!query, enabled: !!query,
}, },
undefined,
dotMetricsEnabled,
); );
const statefulSetsData = useMemo(() => data?.payload?.data?.records || [], [ const statefulSetsData = useMemo(() => data?.payload?.data?.records || [], [

View File

@ -236,6 +236,11 @@ export const getK8sStatefulSetsListColumns = (
return columnsConfig as ColumnType<K8sStatefulSetsRowData>[]; return columnsConfig as ColumnType<K8sStatefulSetsRowData>[];
}; };
const dotToUnder: Record<string, keyof K8sStatefulSetsData['meta']> = {
'k8s.namespace.name': 'k8s_namespace_name',
'k8s.statefulset.name': 'k8s_statefulset_name',
};
const getGroupByEle = ( const getGroupByEle = (
statefulSet: K8sStatefulSetsData, statefulSet: K8sStatefulSetsData,
groupBy: IBuilderQuery['groupBy'], groupBy: IBuilderQuery['groupBy'],
@ -243,9 +248,14 @@ const getGroupByEle = (
const groupByValues: string[] = []; const groupByValues: string[] = [];
groupBy.forEach((group) => { groupBy.forEach((group) => {
groupByValues.push( const rawKey = group.key as string;
statefulSet.meta[group.key as keyof typeof statefulSet.meta],
); // Choose mapped key if present, otherwise use rawKey
const metaKey = (dotToUnder[rawKey] ??
rawKey) as keyof typeof statefulSet.meta;
const value = statefulSet.meta[metaKey];
groupByValues.push(value);
}); });
return ( return (

View File

@ -29,11 +29,13 @@ import { AppState } from 'store/reducers';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData'; import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
import { GlobalReducer } from 'types/reducer/globalTime'; import { GlobalReducer } from 'types/reducer/globalTime';
import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App';
import { getOrderByFromParams } from '../commonUtils'; import { getOrderByFromParams } from '../commonUtils';
import { import {
GetK8sEntityToAggregateAttribute,
INFRA_MONITORING_K8S_PARAMS_KEYS, INFRA_MONITORING_K8S_PARAMS_KEYS,
K8sCategory, K8sCategory,
K8sEntityToAggregateAttributeMapping,
} from '../constants'; } from '../constants';
import K8sHeader from '../K8sHeader'; import K8sHeader from '../K8sHeader';
import LoadingContainer from '../LoadingContainer'; import LoadingContainer from '../LoadingContainer';
@ -137,6 +139,11 @@ function K8sVolumesList({
} }
}, [quickFiltersLastUpdated]); }, [quickFiltersLastUpdated]);
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const createFiltersForSelectedRowData = ( const createFiltersForSelectedRowData = (
selectedRowData: K8sVolumesRowData, selectedRowData: K8sVolumesRowData,
groupBy: IBuilderQuery['groupBy'], groupBy: IBuilderQuery['groupBy'],
@ -190,10 +197,15 @@ function K8sVolumesList({
isLoading: isLoadingGroupedByRowData, isLoading: isLoadingGroupedByRowData,
isError: isErrorGroupedByRowData, isError: isErrorGroupedByRowData,
refetch: fetchGroupedByRowData, refetch: fetchGroupedByRowData,
} = useGetK8sVolumesList(fetchGroupedByRowDataQuery as K8sVolumesListPayload, { } = useGetK8sVolumesList(
queryKey: ['volumeList', fetchGroupedByRowDataQuery], fetchGroupedByRowDataQuery as K8sVolumesListPayload,
enabled: !!fetchGroupedByRowDataQuery && !!selectedRowData, {
}); queryKey: ['volumeList', fetchGroupedByRowDataQuery],
enabled: !!fetchGroupedByRowDataQuery && !!selectedRowData,
},
undefined,
dotMetricsEnabled,
);
const { const {
data: groupByFiltersData, data: groupByFiltersData,
@ -201,7 +213,10 @@ function K8sVolumesList({
} = useGetAggregateKeys( } = useGetAggregateKeys(
{ {
dataSource: currentQuery.builder.queryData[0].dataSource, dataSource: currentQuery.builder.queryData[0].dataSource,
aggregateAttribute: K8sEntityToAggregateAttributeMapping[K8sCategory.NODES], aggregateAttribute: GetK8sEntityToAggregateAttribute(
K8sCategory.NODES,
dotMetricsEnabled,
),
aggregateOperator: 'noop', aggregateOperator: 'noop',
searchText: '', searchText: '',
tagType: '', tagType: '',
@ -247,6 +262,8 @@ function K8sVolumesList({
queryKey: ['volumeList', query], queryKey: ['volumeList', query],
enabled: !!query, enabled: !!query,
}, },
undefined,
dotMetricsEnabled,
); );
const volumesData = useMemo(() => data?.payload?.data?.records || [], [data]); const volumesData = useMemo(() => data?.payload?.data?.records || [], [data]);

View File

@ -142,6 +142,16 @@ export const getK8sVolumesListColumns = (
return columnsConfig as ColumnType<K8sVolumesRowData>[]; return columnsConfig as ColumnType<K8sVolumesRowData>[];
}; };
const dotToUnder: Record<string, keyof K8sVolumesData['meta']> = {
'k8s.namespace.name': 'k8s_namespace_name',
'k8s.node.name': 'k8s_node_name',
'k8s.pod.name': 'k8s_pod_name',
'k8s.pod.uid': 'k8s_pod_uid',
'k8s.statefulset.name': 'k8s_statefulset_name',
'k8s.cluster.name': 'k8s_cluster_name',
'k8s.persistentvolumeclaim.name': 'k8s_persistentvolumeclaim_name',
};
const getGroupByEle = ( const getGroupByEle = (
volume: K8sVolumesData, volume: K8sVolumesData,
groupBy: IBuilderQuery['groupBy'], groupBy: IBuilderQuery['groupBy'],
@ -149,7 +159,13 @@ const getGroupByEle = (
const groupByValues: string[] = []; const groupByValues: string[] = [];
groupBy.forEach((group) => { groupBy.forEach((group) => {
groupByValues.push(volume.meta[group.key as keyof typeof volume.meta]); const rawKey = group.key as string;
const metaKey = (dotToUnder[rawKey] ?? rawKey) as keyof typeof volume.meta;
const value = volume.meta[metaKey];
groupByValues.push(value);
}); });
return ( return (

File diff suppressed because it is too large Load Diff

View File

@ -299,6 +299,19 @@ export const getK8sPodsListColumns = (
return updatedColumnsConfig as ColumnType<K8sPodsRowData>[]; return updatedColumnsConfig as ColumnType<K8sPodsRowData>[];
}; };
const dotToUnder: Record<string, keyof K8sPodsData['meta']> = {
'k8s.cronjob.name': 'k8s_cronjob_name',
'k8s.daemonset.name': 'k8s_daemonset_name',
'k8s.deployment.name': 'k8s_deployment_name',
'k8s.job.name': 'k8s_job_name',
'k8s.namespace.name': 'k8s_namespace_name',
'k8s.node.name': 'k8s_node_name',
'k8s.pod.name': 'k8s_pod_name',
'k8s.pod.uid': 'k8s_pod_uid',
'k8s.statefulset.name': 'k8s_statefulset_name',
'k8s.cluster.name': 'k8s_cluster_name',
};
const getGroupByEle = ( const getGroupByEle = (
pod: K8sPodsData, pod: K8sPodsData,
groupBy: IBuilderQuery['groupBy'], groupBy: IBuilderQuery['groupBy'],
@ -306,7 +319,13 @@ const getGroupByEle = (
const groupByValues: string[] = []; const groupByValues: string[] = [];
groupBy.forEach((group) => { groupBy.forEach((group) => {
groupByValues.push(pod.meta[group.key as keyof typeof pod.meta]); const rawKey = group.key as string;
// Choose mapped key if present, otherwise use rawKey
const metaKey = (dotToUnder[rawKey] ?? rawKey) as keyof typeof pod.meta;
const value = pod.meta[metaKey];
groupByValues.push(value);
}); });
return ( return (

View File

@ -15,6 +15,8 @@ import { SuccessResponse } from 'types/api';
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange'; import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
import uPlot from 'uplot'; import uPlot from 'uplot';
import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App';
import { import {
getHostQueryPayload, getHostQueryPayload,
getNodeQueryPayload, getNodeQueryPayload,
@ -49,12 +51,23 @@ function NodeMetrics({
}; };
}, [logLineTimestamp]); }, [logLineTimestamp]);
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const queryPayloads = useMemo(() => { const queryPayloads = useMemo(() => {
if (nodeName) { if (nodeName) {
return getNodeQueryPayload(clusterName, nodeName, start, end); return getNodeQueryPayload(
clusterName,
nodeName,
start,
end,
dotMetricsEnabled,
);
} }
return getHostQueryPayload(hostName, start, end); return getHostQueryPayload(hostName, start, end, dotMetricsEnabled);
}, [nodeName, hostName, clusterName, start, end]); }, [nodeName, hostName, clusterName, start, end, dotMetricsEnabled]);
const widgetInfo = nodeName ? nodeWidgetInfo : hostWidgetInfo; const widgetInfo = nodeName ? nodeWidgetInfo : hostWidgetInfo;
const queries = useQueries( const queries = useQueries(

View File

@ -8,6 +8,7 @@ import { useResizeObserver } from 'hooks/useDimensions';
import { GetMetricQueryRange } from 'lib/dashboard/getQueryResults'; import { GetMetricQueryRange } from 'lib/dashboard/getQueryResults';
import { getUPlotChartOptions } from 'lib/uPlotLib/getUplotChartOptions'; import { getUPlotChartOptions } from 'lib/uPlotLib/getUplotChartOptions';
import { getUPlotChartData } from 'lib/uPlotLib/utils/getUplotChartData'; import { getUPlotChartData } from 'lib/uPlotLib/utils/getUplotChartData';
import { useAppContext } from 'providers/App/App';
import { useTimezone } from 'providers/Timezone'; import { useTimezone } from 'providers/Timezone';
import { useMemo, useRef } from 'react'; import { useMemo, useRef } from 'react';
import { useQueries, UseQueryResult } from 'react-query'; import { useQueries, UseQueryResult } from 'react-query';
@ -15,6 +16,7 @@ import { SuccessResponse } from 'types/api';
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange'; import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
import uPlot from 'uplot'; import uPlot from 'uplot';
import { FeatureKeys } from '../../../constants/features';
import { getPodQueryPayload, podWidgetInfo } from './constants'; import { getPodQueryPayload, podWidgetInfo } from './constants';
function PodMetrics({ function PodMetrics({
@ -41,9 +43,15 @@ function PodMetrics({
verticalLineTimestamp: logTimestamp.unix(), verticalLineTimestamp: logTimestamp.unix(),
}; };
}, [logLineTimestamp]); }, [logLineTimestamp]);
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const queryPayloads = useMemo( const queryPayloads = useMemo(
() => getPodQueryPayload(clusterName, podName, start, end), () => getPodQueryPayload(clusterName, podName, start, end, dotMetricsEnabled),
[clusterName, end, podName, start], [clusterName, end, podName, start, dotMetricsEnabled],
); );
const queries = useQueries( const queries = useQueries(
queryPayloads.map((payload) => ({ queryPayloads.map((payload) => ({

View File

@ -21,6 +21,7 @@ export const databaseCallsRPS = ({
servicename, servicename,
legend, legend,
tagFilterItems, tagFilterItems,
dotMetricsEnabled,
}: DatabaseCallsRPSProps): QueryBuilderData => { }: DatabaseCallsRPSProps): QueryBuilderData => {
const autocompleteData: BaseAutocompleteData[] = [ const autocompleteData: BaseAutocompleteData[] = [
{ {
@ -34,7 +35,7 @@ export const databaseCallsRPS = ({
{ {
dataType: DataTypes.String, dataType: DataTypes.String,
isColumn: false, isColumn: false,
key: 'db_system', key: dotMetricsEnabled ? WidgetKeys.Db_system : WidgetKeys.Db_system_norm,
type: 'tag', type: 'tag',
}, },
]; ];
@ -43,7 +44,9 @@ export const databaseCallsRPS = ({
{ {
id: '', id: '',
key: { key: {
key: WidgetKeys.Service_name, key: dotMetricsEnabled
? WidgetKeys.Service_name
: WidgetKeys.Service_name_norm,
dataType: DataTypes.String, dataType: DataTypes.String,
isColumn: false, isColumn: false,
type: MetricsType.Resource, type: MetricsType.Resource,
@ -75,6 +78,7 @@ export const databaseCallsRPS = ({
export const databaseCallsAvgDuration = ({ export const databaseCallsAvgDuration = ({
servicename, servicename,
tagFilterItems, tagFilterItems,
dotMetricsEnabled,
}: DatabaseCallProps): QueryBuilderData => { }: DatabaseCallProps): QueryBuilderData => {
const autocompleteDataA: BaseAutocompleteData = { const autocompleteDataA: BaseAutocompleteData = {
key: WidgetKeys.SignozDbLatencySum, key: WidgetKeys.SignozDbLatencySum,
@ -93,7 +97,9 @@ export const databaseCallsAvgDuration = ({
{ {
id: '', id: '',
key: { key: {
key: WidgetKeys.Service_name, key: dotMetricsEnabled
? WidgetKeys.Service_name
: WidgetKeys.Service_name_norm,
dataType: DataTypes.String, dataType: DataTypes.String,
isColumn: false, isColumn: false,
type: MetricsType.Resource, type: MetricsType.Resource,

View File

@ -33,6 +33,7 @@ export const externalCallErrorPercent = ({
servicename, servicename,
legend, legend,
tagFilterItems, tagFilterItems,
dotMetricsEnabled,
}: ExternalCallDurationByAddressProps): QueryBuilderData => { }: ExternalCallDurationByAddressProps): QueryBuilderData => {
const autocompleteDataA: BaseAutocompleteData = { const autocompleteDataA: BaseAutocompleteData = {
key: WidgetKeys.SignozExternalCallLatencyCount, key: WidgetKeys.SignozExternalCallLatencyCount,
@ -51,7 +52,9 @@ export const externalCallErrorPercent = ({
{ {
id: '', id: '',
key: { key: {
key: WidgetKeys.Service_name, key: dotMetricsEnabled
? WidgetKeys.Service_name
: WidgetKeys.Service_name_norm,
dataType: DataTypes.String, dataType: DataTypes.String,
isColumn: false, isColumn: false,
type: MetricsType.Resource, type: MetricsType.Resource,
@ -62,7 +65,7 @@ export const externalCallErrorPercent = ({
{ {
id: '', id: '',
key: { key: {
key: WidgetKeys.StatusCode, key: dotMetricsEnabled ? WidgetKeys.StatusCode : WidgetKeys.StatusCodeNorm,
dataType: DataTypes.Int64, dataType: DataTypes.Int64,
isColumn: false, isColumn: false,
type: MetricsType.Tag, type: MetricsType.Tag,
@ -76,7 +79,9 @@ export const externalCallErrorPercent = ({
{ {
id: '', id: '',
key: { key: {
key: WidgetKeys.Service_name, key: dotMetricsEnabled
? WidgetKeys.Service_name
: WidgetKeys.Service_name_norm,
dataType: DataTypes.String, dataType: DataTypes.String,
isColumn: false, isColumn: false,
type: MetricsType.Resource, type: MetricsType.Resource,
@ -121,6 +126,7 @@ export const externalCallErrorPercent = ({
export const externalCallDuration = ({ export const externalCallDuration = ({
servicename, servicename,
tagFilterItems, tagFilterItems,
dotMetricsEnabled,
}: ExternalCallProps): QueryBuilderData => { }: ExternalCallProps): QueryBuilderData => {
const autocompleteDataA: BaseAutocompleteData = { const autocompleteDataA: BaseAutocompleteData = {
dataType: DataTypes.Float64, dataType: DataTypes.Float64,
@ -144,7 +150,9 @@ export const externalCallDuration = ({
key: { key: {
dataType: DataTypes.String, dataType: DataTypes.String,
isColumn: false, isColumn: false,
key: WidgetKeys.Service_name, key: dotMetricsEnabled
? WidgetKeys.Service_name
: WidgetKeys.Service_name_norm,
type: MetricsType.Resource, type: MetricsType.Resource,
}, },
op: OPERATORS.IN, op: OPERATORS.IN,
@ -184,6 +192,7 @@ export const externalCallRpsByAddress = ({
servicename, servicename,
legend, legend,
tagFilterItems, tagFilterItems,
dotMetricsEnabled,
}: ExternalCallDurationByAddressProps): QueryBuilderData => { }: ExternalCallDurationByAddressProps): QueryBuilderData => {
const autocompleteData: BaseAutocompleteData[] = [ const autocompleteData: BaseAutocompleteData[] = [
{ {
@ -200,7 +209,9 @@ export const externalCallRpsByAddress = ({
key: { key: {
dataType: DataTypes.String, dataType: DataTypes.String,
isColumn: false, isColumn: false,
key: WidgetKeys.Service_name, key: dotMetricsEnabled
? WidgetKeys.Service_name
: WidgetKeys.Service_name_norm,
type: MetricsType.Resource, type: MetricsType.Resource,
}, },
op: OPERATORS.IN, op: OPERATORS.IN,
@ -231,6 +242,7 @@ export const externalCallDurationByAddress = ({
servicename, servicename,
legend, legend,
tagFilterItems, tagFilterItems,
dotMetricsEnabled,
}: ExternalCallDurationByAddressProps): QueryBuilderData => { }: ExternalCallDurationByAddressProps): QueryBuilderData => {
const autocompleteDataA: BaseAutocompleteData = { const autocompleteDataA: BaseAutocompleteData = {
dataType: DataTypes.Float64, dataType: DataTypes.Float64,
@ -253,7 +265,9 @@ export const externalCallDurationByAddress = ({
key: { key: {
dataType: DataTypes.String, dataType: DataTypes.String,
isColumn: false, isColumn: false,
key: WidgetKeys.Service_name, key: dotMetricsEnabled
? WidgetKeys.Service_name
: WidgetKeys.Service_name_norm,
type: MetricsType.Resource, type: MetricsType.Resource,
}, },
op: OPERATORS.IN, op: OPERATORS.IN,

View File

@ -37,10 +37,18 @@ export const latency = ({
tagFilterItems, tagFilterItems,
isSpanMetricEnable = false, isSpanMetricEnable = false,
topLevelOperationsRoute, topLevelOperationsRoute,
dotMetricsEnabled,
}: LatencyProps): QueryBuilderData => { }: LatencyProps): QueryBuilderData => {
const signozLatencyBucketMetrics = dotMetricsEnabled
? WidgetKeys.Signoz_latency_bucket
: WidgetKeys.Signoz_latency_bucket_norm;
const signozMetricsServiceName = dotMetricsEnabled
? WidgetKeys.Service_name
: WidgetKeys.Service_name_norm;
const newAutoCompleteData: BaseAutocompleteData = { const newAutoCompleteData: BaseAutocompleteData = {
key: isSpanMetricEnable key: isSpanMetricEnable
? WidgetKeys.Signoz_latency_bucket ? signozLatencyBucketMetrics
: WidgetKeys.DurationNano, : WidgetKeys.DurationNano,
dataType: DataTypes.Float64, dataType: DataTypes.Float64,
isColumn: true, isColumn: true,
@ -53,7 +61,7 @@ export const latency = ({
{ {
id: '', id: '',
key: { key: {
key: isSpanMetricEnable ? WidgetKeys.Service_name : WidgetKeys.ServiceName, key: isSpanMetricEnable ? signozMetricsServiceName : WidgetKeys.ServiceName,
dataType: DataTypes.String, dataType: DataTypes.String,
type: isSpanMetricEnable ? MetricsType.Resource : MetricsType.Tag, type: isSpanMetricEnable ? MetricsType.Resource : MetricsType.Tag,
isColumn: !isSpanMetricEnable, isColumn: !isSpanMetricEnable,
@ -295,23 +303,30 @@ export const apDexMetricsQueryBuilderQueries = ({
threashold, threashold,
delta, delta,
metricsBuckets, metricsBuckets,
dotMetricsEnabled,
}: ApDexMetricsQueryBuilderQueriesProps): QueryBuilderData => { }: ApDexMetricsQueryBuilderQueriesProps): QueryBuilderData => {
const autoCompleteDataA: BaseAutocompleteData = { const autoCompleteDataA: BaseAutocompleteData = {
key: WidgetKeys.SignozLatencyCount, key: dotMetricsEnabled
? WidgetKeys.SignozLatencyCount
: WidgetKeys.SignozLatencyCountNorm,
dataType: DataTypes.Float64, dataType: DataTypes.Float64,
isColumn: true, isColumn: true,
type: '', type: '',
}; };
const autoCompleteDataB: BaseAutocompleteData = { const autoCompleteDataB: BaseAutocompleteData = {
key: WidgetKeys.Signoz_latency_bucket, key: dotMetricsEnabled
? WidgetKeys.Signoz_latency_bucket
: WidgetKeys.Signoz_latency_bucket_norm,
dataType: DataTypes.Float64, dataType: DataTypes.Float64,
isColumn: true, isColumn: true,
type: '', type: '',
}; };
const autoCompleteDataC: BaseAutocompleteData = { const autoCompleteDataC: BaseAutocompleteData = {
key: WidgetKeys.Signoz_latency_bucket, key: dotMetricsEnabled
? WidgetKeys.Signoz_latency_bucket
: WidgetKeys.Signoz_latency_bucket_norm,
dataType: DataTypes.Float64, dataType: DataTypes.Float64,
isColumn: true, isColumn: true,
type: '', type: '',
@ -321,7 +336,9 @@ export const apDexMetricsQueryBuilderQueries = ({
{ {
id: '', id: '',
key: { key: {
key: WidgetKeys.Service_name, key: dotMetricsEnabled
? WidgetKeys.Service_name
: WidgetKeys.Service_name_norm,
dataType: DataTypes.String, dataType: DataTypes.String,
isColumn: false, isColumn: false,
type: MetricsType.Tag, type: MetricsType.Tag,
@ -347,7 +364,7 @@ export const apDexMetricsQueryBuilderQueries = ({
{ {
id: '', id: '',
key: { key: {
key: WidgetKeys.StatusCode, key: dotMetricsEnabled ? WidgetKeys.StatusCode : WidgetKeys.StatusCodeNorm,
dataType: DataTypes.String, dataType: DataTypes.String,
isColumn: false, isColumn: false,
type: MetricsType.Tag, type: MetricsType.Tag,
@ -369,7 +386,9 @@ export const apDexMetricsQueryBuilderQueries = ({
{ {
id: '', id: '',
key: { key: {
key: WidgetKeys.Service_name, key: dotMetricsEnabled
? WidgetKeys.Service_name
: WidgetKeys.Service_name_norm,
dataType: DataTypes.String, dataType: DataTypes.String,
isColumn: false, isColumn: false,
type: MetricsType.Tag, type: MetricsType.Tag,
@ -406,7 +425,7 @@ export const apDexMetricsQueryBuilderQueries = ({
{ {
id: '', id: '',
key: { key: {
key: WidgetKeys.StatusCode, key: dotMetricsEnabled ? WidgetKeys.StatusCode : WidgetKeys.StatusCodeNorm,
dataType: DataTypes.String, dataType: DataTypes.String,
isColumn: false, isColumn: false,
type: MetricsType.Tag, type: MetricsType.Tag,
@ -417,7 +436,9 @@ export const apDexMetricsQueryBuilderQueries = ({
{ {
id: '', id: '',
key: { key: {
key: WidgetKeys.Service_name, key: dotMetricsEnabled
? WidgetKeys.Service_name
: WidgetKeys.Service_name_norm,
dataType: DataTypes.String, dataType: DataTypes.String,
isColumn: false, isColumn: false,
type: MetricsType.Tag, type: MetricsType.Tag,
@ -482,10 +503,13 @@ export const operationPerSec = ({
servicename, servicename,
tagFilterItems, tagFilterItems,
topLevelOperations, topLevelOperations,
dotMetricsEnabled,
}: OperationPerSecProps): QueryBuilderData => { }: OperationPerSecProps): QueryBuilderData => {
const autocompleteData: BaseAutocompleteData[] = [ const autocompleteData: BaseAutocompleteData[] = [
{ {
key: WidgetKeys.SignozLatencyCount, key: dotMetricsEnabled
? WidgetKeys.SignozLatencyCount
: WidgetKeys.SignozLatencyCountNorm,
dataType: DataTypes.Float64, dataType: DataTypes.Float64,
isColumn: true, isColumn: true,
type: '', type: '',
@ -497,7 +521,9 @@ export const operationPerSec = ({
{ {
id: '', id: '',
key: { key: {
key: WidgetKeys.Service_name, key: dotMetricsEnabled
? WidgetKeys.Service_name
: WidgetKeys.Service_name_norm,
dataType: DataTypes.String, dataType: DataTypes.String,
isColumn: false, isColumn: false,
type: MetricsType.Resource, type: MetricsType.Resource,
@ -540,6 +566,7 @@ export const errorPercentage = ({
servicename, servicename,
tagFilterItems, tagFilterItems,
topLevelOperations, topLevelOperations,
dotMetricsEnabled,
}: OperationPerSecProps): QueryBuilderData => { }: OperationPerSecProps): QueryBuilderData => {
const autocompleteDataA: BaseAutocompleteData = { const autocompleteDataA: BaseAutocompleteData = {
key: WidgetKeys.SignozCallsTotal, key: WidgetKeys.SignozCallsTotal,
@ -560,7 +587,9 @@ export const errorPercentage = ({
{ {
id: '', id: '',
key: { key: {
key: WidgetKeys.Service_name, key: dotMetricsEnabled
? WidgetKeys.Service_name
: WidgetKeys.Service_name_norm,
dataType: DataTypes.String, dataType: DataTypes.String,
isColumn: false, isColumn: false,
type: MetricsType.Resource, type: MetricsType.Resource,
@ -582,7 +611,9 @@ export const errorPercentage = ({
{ {
id: '', id: '',
key: { key: {
key: WidgetKeys.StatusCode, key: dotMetricsEnabled
? WidgetKeys.Service_name
: WidgetKeys.StatusCodeNorm,
dataType: DataTypes.Int64, dataType: DataTypes.Int64,
isColumn: false, isColumn: false,
type: MetricsType.Tag, type: MetricsType.Tag,
@ -597,7 +628,9 @@ export const errorPercentage = ({
{ {
id: '', id: '',
key: { key: {
key: WidgetKeys.Service_name, key: dotMetricsEnabled
? WidgetKeys.Service_name
: WidgetKeys.Service_name_norm,
dataType: DataTypes.String, dataType: DataTypes.String,
isColumn: false, isColumn: false,
type: MetricsType.Resource, type: MetricsType.Resource,

View File

@ -21,9 +21,12 @@ import { getQueryBuilderQuerieswithFormula } from './MetricsPageQueriesFactory';
export const topOperationQueries = ({ export const topOperationQueries = ({
servicename, servicename,
dotMetricsEnabled,
}: TopOperationQueryFactoryProps): QueryBuilderData => { }: TopOperationQueryFactoryProps): QueryBuilderData => {
const latencyAutoCompleteData: BaseAutocompleteData = { const latencyAutoCompleteData: BaseAutocompleteData = {
key: WidgetKeys.Signoz_latency_bucket, key: dotMetricsEnabled
? WidgetKeys.Signoz_latency_bucket
: WidgetKeys.Signoz_latency_bucket_norm,
dataType: DataTypes.Float64, dataType: DataTypes.Float64,
isColumn: true, isColumn: true,
type: '', type: '',
@ -37,7 +40,9 @@ export const topOperationQueries = ({
}; };
const numOfCallAutoCompleteData: BaseAutocompleteData = { const numOfCallAutoCompleteData: BaseAutocompleteData = {
key: WidgetKeys.SignozLatencyCount, key: dotMetricsEnabled
? WidgetKeys.SignozLatencyCount
: WidgetKeys.SignozLatencyCountNorm,
dataType: DataTypes.Float64, dataType: DataTypes.Float64,
isColumn: true, isColumn: true,
type: '', type: '',
@ -47,7 +52,9 @@ export const topOperationQueries = ({
{ {
id: '', id: '',
key: { key: {
key: WidgetKeys.Service_name, key: dotMetricsEnabled
? WidgetKeys.Service_name
: WidgetKeys.Service_name_norm,
dataType: DataTypes.String, dataType: DataTypes.String,
isColumn: false, isColumn: false,
type: MetricsType.Resource, type: MetricsType.Resource,
@ -63,7 +70,9 @@ export const topOperationQueries = ({
key: { key: {
dataType: DataTypes.String, dataType: DataTypes.String,
isColumn: false, isColumn: false,
key: WidgetKeys.Service_name, key: dotMetricsEnabled
? WidgetKeys.Service_name
: WidgetKeys.Service_name_norm,
type: MetricsType.Resource, type: MetricsType.Resource,
}, },
op: OPERATORS.IN, op: OPERATORS.IN,
@ -74,7 +83,7 @@ export const topOperationQueries = ({
key: { key: {
dataType: DataTypes.Int64, dataType: DataTypes.Int64,
isColumn: false, isColumn: false,
key: WidgetKeys.StatusCode, key: dotMetricsEnabled ? WidgetKeys.StatusCode : WidgetKeys.StatusCodeNorm,
type: MetricsType.Tag, type: MetricsType.Tag,
}, },
op: OPERATORS.IN, op: OPERATORS.IN,

View File

@ -11,6 +11,7 @@ import {
import useResourceAttribute from 'hooks/useResourceAttribute'; import useResourceAttribute from 'hooks/useResourceAttribute';
import { import {
convertRawQueriesToTraceSelectedTags, convertRawQueriesToTraceSelectedTags,
getResourceDeploymentKeys,
resourceAttributesToTagFilterItems, resourceAttributesToTagFilterItems,
} from 'hooks/useResourceAttribute/utils'; } from 'hooks/useResourceAttribute/utils';
import { useSafeNavigate } from 'hooks/useSafeNavigate'; import { useSafeNavigate } from 'hooks/useSafeNavigate';
@ -26,6 +27,8 @@ import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
import { EQueryType } from 'types/common/dashboard'; import { EQueryType } from 'types/common/dashboard';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App';
import { GraphTitle, MENU_ITEMS, SERVICE_CHART_ID } from '../constant'; import { GraphTitle, MENU_ITEMS, SERVICE_CHART_ID } from '../constant';
import { getWidgetQueryBuilder } from '../MetricsApplication.factory'; import { getWidgetQueryBuilder } from '../MetricsApplication.factory';
import { Card, GraphContainer, Row } from '../styles'; import { Card, GraphContainer, Row } from '../styles';
@ -80,7 +83,12 @@ function DBCall(): JSX.Element {
[queries], [queries],
); );
const legend = '{{db_system}}'; const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const legend = dotMetricsEnabled ? '{{db.system}}' : '{{db_system}}';
const databaseCallsRPSWidget = useMemo( const databaseCallsRPSWidget = useMemo(
() => () =>
@ -92,6 +100,7 @@ function DBCall(): JSX.Element {
servicename, servicename,
legend, legend,
tagFilterItems, tagFilterItems,
dotMetricsEnabled,
}), }),
clickhouse_sql: [], clickhouse_sql: [],
id: uuid(), id: uuid(),
@ -102,7 +111,7 @@ function DBCall(): JSX.Element {
id: SERVICE_CHART_ID.dbCallsRPS, id: SERVICE_CHART_ID.dbCallsRPS,
fillSpans: false, fillSpans: false,
}), }),
[servicename, tagFilterItems], [servicename, tagFilterItems, dotMetricsEnabled, legend],
); );
const databaseCallsAverageDurationWidget = useMemo( const databaseCallsAverageDurationWidget = useMemo(
() => () =>
@ -113,6 +122,7 @@ function DBCall(): JSX.Element {
builder: databaseCallsAvgDuration({ builder: databaseCallsAvgDuration({
servicename, servicename,
tagFilterItems, tagFilterItems,
dotMetricsEnabled,
}), }),
clickhouse_sql: [], clickhouse_sql: [],
id: uuid(), id: uuid(),
@ -123,7 +133,7 @@ function DBCall(): JSX.Element {
id: GraphTitle.DATABASE_CALLS_AVG_DURATION, id: GraphTitle.DATABASE_CALLS_AVG_DURATION,
fillSpans: true, fillSpans: true,
}), }),
[servicename, tagFilterItems], [servicename, tagFilterItems, dotMetricsEnabled],
); );
const stepInterval = useMemo( const stepInterval = useMemo(
@ -141,7 +151,7 @@ function DBCall(): JSX.Element {
useEffect(() => { useEffect(() => {
if (!logEventCalledRef.current) { if (!logEventCalledRef.current) {
const selectedEnvironments = queries.find( const selectedEnvironments = queries.find(
(val) => val.tagKey === 'resource_deployment_environment', (val) => val.tagKey === getResourceDeploymentKeys(dotMetricsEnabled),
)?.tagValue; )?.tagValue;
logEvent('APM: Service detail page visited', { logEvent('APM: Service detail page visited', {

View File

@ -13,6 +13,7 @@ import {
import useResourceAttribute from 'hooks/useResourceAttribute'; import useResourceAttribute from 'hooks/useResourceAttribute';
import { import {
convertRawQueriesToTraceSelectedTags, convertRawQueriesToTraceSelectedTags,
getResourceDeploymentKeys,
resourceAttributesToTagFilterItems, resourceAttributesToTagFilterItems,
} from 'hooks/useResourceAttribute/utils'; } from 'hooks/useResourceAttribute/utils';
import { useSafeNavigate } from 'hooks/useSafeNavigate'; import { useSafeNavigate } from 'hooks/useSafeNavigate';
@ -28,6 +29,8 @@ import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { EQueryType } from 'types/common/dashboard'; import { EQueryType } from 'types/common/dashboard';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App';
import { GraphTitle, legend, MENU_ITEMS } from '../constant'; import { GraphTitle, legend, MENU_ITEMS } from '../constant';
import { getWidgetQueryBuilder } from '../MetricsApplication.factory'; import { getWidgetQueryBuilder } from '../MetricsApplication.factory';
import { Card, GraphContainer, Row } from '../styles'; import { Card, GraphContainer, Row } from '../styles';
@ -75,6 +78,10 @@ function External(): JSX.Element {
handleNonInQueryRange(resourceAttributesToTagFilterItems(queries)) || [], handleNonInQueryRange(resourceAttributesToTagFilterItems(queries)) || [],
[queries], [queries],
); );
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const externalCallErrorWidget = useMemo( const externalCallErrorWidget = useMemo(
() => () =>
@ -86,6 +93,7 @@ function External(): JSX.Element {
servicename, servicename,
legend: legend.address, legend: legend.address,
tagFilterItems, tagFilterItems,
dotMetricsEnabled,
}), }),
clickhouse_sql: [], clickhouse_sql: [],
id: uuid(), id: uuid(),
@ -95,7 +103,7 @@ function External(): JSX.Element {
yAxisUnit: '%', yAxisUnit: '%',
id: GraphTitle.EXTERNAL_CALL_ERROR_PERCENTAGE, id: GraphTitle.EXTERNAL_CALL_ERROR_PERCENTAGE,
}), }),
[servicename, tagFilterItems], [servicename, tagFilterItems, dotMetricsEnabled],
); );
const selectedTraceTags = useMemo( const selectedTraceTags = useMemo(
@ -112,6 +120,7 @@ function External(): JSX.Element {
builder: externalCallDuration({ builder: externalCallDuration({
servicename, servicename,
tagFilterItems, tagFilterItems,
dotMetricsEnabled,
}), }),
clickhouse_sql: [], clickhouse_sql: [],
id: uuid(), id: uuid(),
@ -122,7 +131,7 @@ function External(): JSX.Element {
id: GraphTitle.EXTERNAL_CALL_DURATION, id: GraphTitle.EXTERNAL_CALL_DURATION,
fillSpans: true, fillSpans: true,
}), }),
[servicename, tagFilterItems], [servicename, tagFilterItems, dotMetricsEnabled],
); );
const errorApmToTraceQuery = useGetAPMToTracesQueries({ const errorApmToTraceQuery = useGetAPMToTracesQueries({
@ -158,7 +167,7 @@ function External(): JSX.Element {
useEffect(() => { useEffect(() => {
if (!logEventCalledRef.current) { if (!logEventCalledRef.current) {
const selectedEnvironments = queries.find( const selectedEnvironments = queries.find(
(val) => val.tagKey === 'resource_deployment_environment', (val) => val.tagKey === getResourceDeploymentKeys(dotMetricsEnabled),
)?.tagValue; )?.tagValue;
logEvent('APM: Service detail page visited', { logEvent('APM: Service detail page visited', {
@ -181,6 +190,7 @@ function External(): JSX.Element {
servicename, servicename,
legend: legend.address, legend: legend.address,
tagFilterItems, tagFilterItems,
dotMetricsEnabled,
}), }),
clickhouse_sql: [], clickhouse_sql: [],
id: uuid(), id: uuid(),
@ -191,7 +201,7 @@ function External(): JSX.Element {
id: GraphTitle.EXTERNAL_CALL_RPS_BY_ADDRESS, id: GraphTitle.EXTERNAL_CALL_RPS_BY_ADDRESS,
fillSpans: true, fillSpans: true,
}), }),
[servicename, tagFilterItems], [servicename, tagFilterItems, dotMetricsEnabled],
); );
const externalCallDurationAddressWidget = useMemo( const externalCallDurationAddressWidget = useMemo(
@ -204,6 +214,7 @@ function External(): JSX.Element {
servicename, servicename,
legend: legend.address, legend: legend.address,
tagFilterItems, tagFilterItems,
dotMetricsEnabled,
}), }),
clickhouse_sql: [], clickhouse_sql: [],
id: uuid(), id: uuid(),
@ -214,7 +225,7 @@ function External(): JSX.Element {
id: GraphTitle.EXTERNAL_CALL_DURATION_BY_ADDRESS, id: GraphTitle.EXTERNAL_CALL_DURATION_BY_ADDRESS,
fillSpans: true, fillSpans: true,
}), }),
[servicename, tagFilterItems], [servicename, tagFilterItems, dotMetricsEnabled],
); );
const apmToTraceQuery = useGetAPMToTracesQueries({ const apmToTraceQuery = useGetAPMToTracesQueries({

View File

@ -11,6 +11,7 @@ import { getQueryString } from 'container/SideNav/helper';
import useResourceAttribute from 'hooks/useResourceAttribute'; import useResourceAttribute from 'hooks/useResourceAttribute';
import { import {
convertRawQueriesToTraceSelectedTags, convertRawQueriesToTraceSelectedTags,
getResourceDeploymentKeys,
resourceAttributesToTagFilterItems, resourceAttributesToTagFilterItems,
} from 'hooks/useResourceAttribute/utils'; } from 'hooks/useResourceAttribute/utils';
import { useSafeNavigate } from 'hooks/useSafeNavigate'; import { useSafeNavigate } from 'hooks/useSafeNavigate';
@ -92,12 +93,15 @@ function Application(): JSX.Element {
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
[handleSetTimeStamp], [handleSetTimeStamp],
); );
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const logEventCalledRef = useRef(false); const logEventCalledRef = useRef(false);
useEffect(() => { useEffect(() => {
if (!logEventCalledRef.current) { if (!logEventCalledRef.current) {
const selectedEnvironments = queries.find( const selectedEnvironments = queries.find(
(val) => val.tagKey === 'resource_deployment_environment', (val) => val.tagKey === getResourceDeploymentKeys(dotMetricsEnabled),
)?.tagValue; )?.tagValue;
logEvent('APM: Service detail page visited', { logEvent('APM: Service detail page visited', {
@ -155,6 +159,7 @@ function Application(): JSX.Element {
servicename, servicename,
tagFilterItems, tagFilterItems,
topLevelOperations: topLevelOperationsRoute, topLevelOperations: topLevelOperationsRoute,
dotMetricsEnabled,
}), }),
clickhouse_sql: [], clickhouse_sql: [],
id: uuid(), id: uuid(),
@ -164,7 +169,7 @@ function Application(): JSX.Element {
yAxisUnit: 'ops', yAxisUnit: 'ops',
id: SERVICE_CHART_ID.rps, id: SERVICE_CHART_ID.rps,
}), }),
[servicename, tagFilterItems, topLevelOperationsRoute], [servicename, tagFilterItems, topLevelOperationsRoute, dotMetricsEnabled],
); );
const errorPercentageWidget = useMemo( const errorPercentageWidget = useMemo(
@ -177,6 +182,7 @@ function Application(): JSX.Element {
servicename, servicename,
tagFilterItems, tagFilterItems,
topLevelOperations: topLevelOperationsRoute, topLevelOperations: topLevelOperationsRoute,
dotMetricsEnabled,
}), }),
clickhouse_sql: [], clickhouse_sql: [],
id: uuid(), id: uuid(),
@ -187,7 +193,7 @@ function Application(): JSX.Element {
id: SERVICE_CHART_ID.errorPercentage, id: SERVICE_CHART_ID.errorPercentage,
fillSpans: true, fillSpans: true,
}), }),
[servicename, tagFilterItems, topLevelOperationsRoute], [servicename, tagFilterItems, topLevelOperationsRoute, dotMetricsEnabled],
); );
const stepInterval = useMemo( const stepInterval = useMemo(

View File

@ -20,6 +20,8 @@ import { useParams } from 'react-router-dom';
import { EQueryType } from 'types/common/dashboard'; import { EQueryType } from 'types/common/dashboard';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import { FeatureKeys } from '../../../../../constants/features';
import { useAppContext } from '../../../../../providers/App/App';
import { IServiceName } from '../../types'; import { IServiceName } from '../../types';
import { ApDexMetricsProps } from './types'; import { ApDexMetricsProps } from './types';
@ -34,7 +36,10 @@ function ApDexMetrics({
}: ApDexMetricsProps): JSX.Element { }: ApDexMetricsProps): JSX.Element {
const { servicename: encodedServiceName } = useParams<IServiceName>(); const { servicename: encodedServiceName } = useParams<IServiceName>();
const servicename = decodeURIComponent(encodedServiceName); const servicename = decodeURIComponent(encodedServiceName);
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const apDexMetricsWidget = useMemo( const apDexMetricsWidget = useMemo(
() => () =>
getWidgetQueryBuilder({ getWidgetQueryBuilder({
@ -48,6 +53,7 @@ function ApDexMetrics({
threashold: thresholdValue || 0, threashold: thresholdValue || 0,
delta: delta || false, delta: delta || false,
metricsBuckets: metricsBuckets || [], metricsBuckets: metricsBuckets || [],
dotMetricsEnabled,
}), }),
clickhouse_sql: [], clickhouse_sql: [],
id: uuid(), id: uuid(),
@ -73,6 +79,7 @@ function ApDexMetrics({
tagFilterItems, tagFilterItems,
thresholdValue, thresholdValue,
topLevelOperationsRoute, topLevelOperationsRoute,
dotMetricsEnabled,
], ],
); );

View File

@ -56,6 +56,10 @@ function ServiceOverview({
[isSpanMetricEnable, queries], [isSpanMetricEnable, queries],
); );
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const latencyWidget = useMemo( const latencyWidget = useMemo(
() => () =>
getWidgetQueryBuilder({ getWidgetQueryBuilder({
@ -67,6 +71,7 @@ function ServiceOverview({
tagFilterItems, tagFilterItems,
isSpanMetricEnable, isSpanMetricEnable,
topLevelOperationsRoute, topLevelOperationsRoute,
dotMetricsEnabled,
}), }),
clickhouse_sql: [], clickhouse_sql: [],
id: uuid(), id: uuid(),
@ -76,7 +81,13 @@ function ServiceOverview({
yAxisUnit: 'ns', yAxisUnit: 'ns',
id: SERVICE_CHART_ID.latency, id: SERVICE_CHART_ID.latency,
}), }),
[isSpanMetricEnable, servicename, tagFilterItems, topLevelOperationsRoute], [
isSpanMetricEnable,
servicename,
tagFilterItems,
topLevelOperationsRoute,
dotMetricsEnabled,
],
); );
const isQueryEnabled = const isQueryEnabled =

View File

@ -18,6 +18,8 @@ import { EQueryType } from 'types/common/dashboard';
import { GlobalReducer } from 'types/reducer/globalTime'; import { GlobalReducer } from 'types/reducer/globalTime';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import { FeatureKeys } from '../../../../constants/features';
import { useAppContext } from '../../../../providers/App/App';
import { IServiceName } from '../types'; import { IServiceName } from '../types';
import { title } from './config'; import { title } from './config';
import ColumnWithLink from './TableRenderer/ColumnWithLink'; import ColumnWithLink from './TableRenderer/ColumnWithLink';
@ -40,6 +42,11 @@ function TopOperationMetrics(): JSX.Element {
convertRawQueriesToTraceSelectedTags(queries) || [], convertRawQueriesToTraceSelectedTags(queries) || [],
); );
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const keyOperationWidget = useMemo( const keyOperationWidget = useMemo(
() => () =>
getWidgetQueryBuilder({ getWidgetQueryBuilder({
@ -48,13 +55,14 @@ function TopOperationMetrics(): JSX.Element {
promql: [], promql: [],
builder: topOperationQueries({ builder: topOperationQueries({
servicename, servicename,
dotMetricsEnabled,
}), }),
clickhouse_sql: [], clickhouse_sql: [],
id: uuid(), id: uuid(),
}, },
panelTypes: PANEL_TYPES.TABLE, panelTypes: PANEL_TYPES.TABLE,
}), }),
[servicename], [servicename, dotMetricsEnabled],
); );
const updatedQuery = useStepInterval(keyOperationWidget.query); const updatedQuery = useStepInterval(keyOperationWidget.query);

View File

@ -10,6 +10,7 @@ export interface IServiceName {
export interface TopOperationQueryFactoryProps { export interface TopOperationQueryFactoryProps {
servicename: IServiceName['servicename']; servicename: IServiceName['servicename'];
dotMetricsEnabled: boolean;
} }
export interface ExternalCallDurationByAddressProps extends ExternalCallProps { export interface ExternalCallDurationByAddressProps extends ExternalCallProps {
@ -19,6 +20,7 @@ export interface ExternalCallDurationByAddressProps extends ExternalCallProps {
export interface ExternalCallProps { export interface ExternalCallProps {
servicename: IServiceName['servicename']; servicename: IServiceName['servicename'];
tagFilterItems: TagFilterItem[]; tagFilterItems: TagFilterItem[];
dotMetricsEnabled: boolean;
} }
export interface BuilderQueriesProps { export interface BuilderQueriesProps {
@ -50,6 +52,7 @@ export interface OperationPerSecProps {
servicename: IServiceName['servicename']; servicename: IServiceName['servicename'];
tagFilterItems: TagFilterItem[]; tagFilterItems: TagFilterItem[];
topLevelOperations: string[]; topLevelOperations: string[];
dotMetricsEnabled: boolean;
} }
export interface LatencyProps { export interface LatencyProps {
@ -57,6 +60,7 @@ export interface LatencyProps {
tagFilterItems: TagFilterItem[]; tagFilterItems: TagFilterItem[];
isSpanMetricEnable?: boolean; isSpanMetricEnable?: boolean;
topLevelOperationsRoute: string[]; topLevelOperationsRoute: string[];
dotMetricsEnabled: boolean;
} }
export interface ApDexProps { export interface ApDexProps {
@ -74,4 +78,5 @@ export interface TableRendererProps {
export interface ApDexMetricsQueryBuilderQueriesProps extends ApDexProps { export interface ApDexMetricsQueryBuilderQueriesProps extends ApDexProps {
delta: boolean; delta: boolean;
metricsBuckets: number[]; metricsBuckets: number[];
dotMetricsEnabled: boolean;
} }

View File

@ -85,12 +85,15 @@ export enum WidgetKeys {
HasError = 'hasError', HasError = 'hasError',
Address = 'address', Address = 'address',
DurationNano = 'durationNano', DurationNano = 'durationNano',
StatusCode = 'status_code', StatusCodeNorm = 'status_code',
StatusCode = 'status.code',
Operation = 'operation', Operation = 'operation',
OperationName = 'operationName', OperationName = 'operationName',
Service_name = 'service_name', Service_name_norm = 'service_name',
Service_name = 'service.name',
ServiceName = 'serviceName', ServiceName = 'serviceName',
SignozLatencyCount = 'signoz_latency_count', SignozLatencyCountNorm = 'signoz_latency_count',
SignozLatencyCount = 'signoz_latency.count',
SignozDBLatencyCount = 'signoz_db_latency_count', SignozDBLatencyCount = 'signoz_db_latency_count',
DatabaseCallCount = 'signoz_database_call_count', DatabaseCallCount = 'signoz_database_call_count',
DatabaseCallLatencySum = 'signoz_database_call_latency_sum', DatabaseCallLatencySum = 'signoz_database_call_latency_sum',
@ -98,7 +101,10 @@ export enum WidgetKeys {
SignozCallsTotal = 'signoz_calls_total', SignozCallsTotal = 'signoz_calls_total',
SignozExternalCallLatencyCount = 'signoz_external_call_latency_count', SignozExternalCallLatencyCount = 'signoz_external_call_latency_count',
SignozExternalCallLatencySum = 'signoz_external_call_latency_sum', SignozExternalCallLatencySum = 'signoz_external_call_latency_sum',
Signoz_latency_bucket = 'signoz_latency_bucket', Signoz_latency_bucket_norm = 'signoz_latency_bucket',
Signoz_latency_bucket = 'signoz_latency.bucket',
Db_system = 'db.system',
Db_system_norm = 'db_system',
} }
export const topOperationMetricsDownloadOptions: DownloadOptions = { export const topOperationMetricsDownloadOptions: DownloadOptions = {

View File

@ -25,10 +25,11 @@ export interface NavigateToTraceProps {
} }
export interface DatabaseCallsRPSProps extends DatabaseCallProps { export interface DatabaseCallsRPSProps extends DatabaseCallProps {
legend: '{{db_system}}'; legend: string;
} }
export interface DatabaseCallProps { export interface DatabaseCallProps {
servicename: IServiceName['servicename']; servicename: IServiceName['servicename'];
tagFilterItems: TagFilterItem[]; tagFilterItems: TagFilterItem[];
dotMetricsEnabled: boolean;
} }

View File

@ -5,11 +5,13 @@ import { InspectMetricsSeries } from 'api/metricsExplorer/getInspectMetricsDetai
import { MetricType } from 'api/metricsExplorer/getMetricsList'; import { MetricType } from 'api/metricsExplorer/getMetricsList';
import * as useInspectMetricsHooks from 'hooks/metricsExplorer/useGetInspectMetricsDetails'; import * as useInspectMetricsHooks from 'hooks/metricsExplorer/useGetInspectMetricsDetails';
import * as useGetMetricDetailsHooks from 'hooks/metricsExplorer/useGetMetricDetails'; import * as useGetMetricDetailsHooks from 'hooks/metricsExplorer/useGetMetricDetails';
import * as appContextHooks from 'providers/App/App';
import { QueryClient, QueryClientProvider } from 'react-query'; import { QueryClient, QueryClientProvider } from 'react-query';
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import store from 'store'; import store from 'store';
import ROUTES from '../../../../constants/routes'; import ROUTES from '../../../../constants/routes';
import { LicenseEvent } from '../../../../types/api/licensesV3/getActive';
import Inspect from '../Inspect'; import Inspect from '../Inspect';
import { InspectionStep } from '../types'; import { InspectionStep } from '../types';
@ -27,6 +29,30 @@ const mockTimeSeries: InspectMetricsSeries[] = [
}, },
]; ];
jest.spyOn(appContextHooks, 'useAppContext').mockReturnValue({
user: {
role: 'admin',
},
activeLicenseV3: {
event_queue: {
created_at: '0',
event: LicenseEvent.NO_EVENT,
scheduled_at: '0',
status: '',
updated_at: '0',
},
license: {
license_key: 'test-license-key',
license_type: 'trial',
org_id: 'test-org-id',
plan_id: 'test-plan-id',
plan_name: 'test-plan-name',
plan_type: 'trial',
plan_version: 'test-plan-version',
},
},
} as any);
jest.spyOn(useGetMetricDetailsHooks, 'useGetMetricDetails').mockReturnValue({ jest.spyOn(useGetMetricDetailsHooks, 'useGetMetricDetails').mockReturnValue({
data: { data: {
metricDetails: { metricDetails: {

View File

@ -1,11 +1,13 @@
/* eslint-disable react/jsx-props-no-spreading */ /* eslint-disable react/jsx-props-no-spreading */
import { render, screen } from '@testing-library/react'; import { render, screen } from '@testing-library/react';
import { MetricType } from 'api/metricsExplorer/getMetricsList'; import { MetricType } from 'api/metricsExplorer/getMetricsList';
import * as appContextHooks from 'providers/App/App';
import { QueryClient, QueryClientProvider } from 'react-query'; import { QueryClient, QueryClientProvider } from 'react-query';
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import store from 'store'; import store from 'store';
import ROUTES from '../../../../constants/routes'; import ROUTES from '../../../../constants/routes';
import { LicenseEvent } from '../../../../types/api/licensesV3/getActive';
import QueryBuilder from '../QueryBuilder'; import QueryBuilder from '../QueryBuilder';
import { import {
InspectionStep, InspectionStep,
@ -20,6 +22,30 @@ jest.mock('react-router-dom', () => ({
}), }),
})); }));
jest.spyOn(appContextHooks, 'useAppContext').mockReturnValue({
user: {
role: 'admin',
},
activeLicenseV3: {
event_queue: {
created_at: '0',
event: LicenseEvent.NO_EVENT,
scheduled_at: '0',
status: '',
updated_at: '0',
},
license: {
license_key: 'test-license-key',
license_type: 'trial',
org_id: 'test-org-id',
plan_id: 'test-plan-id',
plan_name: 'test-plan-name',
plan_type: 'trial',
plan_version: 'test-plan-version',
},
},
} as any);
const queryClient = new QueryClient(); const queryClient = new QueryClient();
describe('QueryBuilder', () => { describe('QueryBuilder', () => {

View File

@ -1,12 +0,0 @@
import * as Sentry from '@sentry/react';
import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback';
function Views(): JSX.Element {
return (
<Sentry.ErrorBoundary fallback={<ErrorBoundaryFallback />}>
Views
</Sentry.ErrorBoundary>
);
}
export default Views;

View File

@ -1,3 +0,0 @@
import Views from './Views';
export default Views;

View File

@ -1,6 +1,6 @@
import { Button, Divider, Form, Modal } from 'antd'; import { Button, Divider, Form, FormInstance, Modal } from 'antd';
import { useAppContext } from 'providers/App/App'; import { useAppContext } from 'providers/App/App';
import React, { useCallback, useEffect, useMemo } from 'react'; import React, { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { ActionMode, ActionType, PipelineData } from 'types/api/pipeline/def'; import { ActionMode, ActionType, PipelineData } from 'types/api/pipeline/def';
import { v4 } from 'uuid'; import { v4 } from 'uuid';
@ -10,6 +10,7 @@ import { getEditedDataSource, getRecordIndex } from '../utils';
import { renderPipelineForm } from './utils'; import { renderPipelineForm } from './utils';
function AddNewPipeline({ function AddNewPipeline({
form,
isActionType, isActionType,
setActionType, setActionType,
selectedPipelineData, selectedPipelineData,
@ -17,22 +18,12 @@ function AddNewPipeline({
setCurrPipelineData, setCurrPipelineData,
currPipelineData, currPipelineData,
}: AddNewPipelineProps): JSX.Element { }: AddNewPipelineProps): JSX.Element {
const [form] = Form.useForm();
const { t } = useTranslation('pipeline'); const { t } = useTranslation('pipeline');
const { user } = useAppContext(); const { user } = useAppContext();
const isEdit = isActionType === 'edit-pipeline'; const isEdit = isActionType === 'edit-pipeline';
const isAdd = isActionType === 'add-pipeline'; const isAdd = isActionType === 'add-pipeline';
useEffect(() => {
if (isEdit) {
form.setFieldsValue(selectedPipelineData);
}
if (isAdd) {
form.resetFields();
}
}, [form, isEdit, isAdd, selectedPipelineData]);
const onFinish = (values: PipelineData): void => { const onFinish = (values: PipelineData): void => {
const newPipeLineData: PipelineData = { const newPipeLineData: PipelineData = {
id: v4(), id: v4(),
@ -135,6 +126,7 @@ function AddNewPipeline({
} }
interface AddNewPipelineProps { interface AddNewPipelineProps {
form: FormInstance<PipelineData>;
isActionType: string; isActionType: string;
setActionType: (actionType?: ActionType) => void; setActionType: (actionType?: ActionType) => void;
selectedPipelineData: PipelineData | undefined; selectedPipelineData: PipelineData | undefined;

View File

@ -1,7 +1,7 @@
import './styles.scss'; import './styles.scss';
import { ExclamationCircleOutlined, PlusOutlined } from '@ant-design/icons'; import { ExclamationCircleOutlined, PlusOutlined } from '@ant-design/icons';
import { Card, Modal, Table, Typography } from 'antd'; import { Card, Form, Modal, Table, Typography } from 'antd';
import { ExpandableConfig } from 'antd/es/table/interface'; import { ExpandableConfig } from 'antd/es/table/interface';
import logEvent from 'api/common/logEvent'; import logEvent from 'api/common/logEvent';
import savePipeline from 'api/pipeline/post'; import savePipeline from 'api/pipeline/post';
@ -95,6 +95,7 @@ function PipelineListsView({
pipelineData, pipelineData,
refetchPipelineLists, refetchPipelineLists,
}: PipelineListsViewProps): JSX.Element { }: PipelineListsViewProps): JSX.Element {
const [pipelineForm] = Form.useForm<PipelineData>();
const { t } = useTranslation(['pipeline', 'common']); const { t } = useTranslation(['pipeline', 'common']);
const [modal, contextHolder] = Modal.useModal(); const [modal, contextHolder] = Modal.useModal();
const { notifications } = useNotifications(); const { notifications } = useNotifications();
@ -179,8 +180,9 @@ function PipelineListsView({
(record: PipelineData) => (): void => { (record: PipelineData) => (): void => {
setActionType(ActionType.EditPipeline); setActionType(ActionType.EditPipeline);
setSelectedPipelineData(record); setSelectedPipelineData(record);
pipelineForm.setFieldsValue(record);
}, },
[setActionType], [setActionType, pipelineForm],
); );
const pipelineDeleteHandler = useCallback( const pipelineDeleteHandler = useCallback(
@ -382,12 +384,13 @@ function PipelineListsView({
const addNewPipelineHandler = useCallback((): void => { const addNewPipelineHandler = useCallback((): void => {
setActionType(ActionType.AddPipeline); setActionType(ActionType.AddPipeline);
pipelineForm.resetFields();
logEvent('Logs: Pipelines: Clicked Add New Pipeline', { logEvent('Logs: Pipelines: Clicked Add New Pipeline', {
source: 'signoz-ui', source: 'signoz-ui',
}); });
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [setActionType]); }, [setActionType, pipelineForm]);
const footer = useCallback((): JSX.Element | undefined => { const footer = useCallback((): JSX.Element | undefined => {
if (isEditingActionMode) { if (isEditingActionMode) {
@ -495,6 +498,7 @@ function PipelineListsView({
<> <>
{contextHolder} {contextHolder}
<AddNewPipeline <AddNewPipeline
form={pipelineForm}
isActionType={isActionType} isActionType={isActionType}
setActionType={setActionType} setActionType={setActionType}
selectedPipelineData={selectedPipelineData} selectedPipelineData={selectedPipelineData}

View File

@ -1,4 +1,6 @@
import { Form } from 'antd';
import { render } from 'tests/test-utils'; import { render } from 'tests/test-utils';
import { PipelineData } from 'types/api/pipeline/def';
import { pipelineMockData } from '../mocks/pipeline'; import { pipelineMockData } from '../mocks/pipeline';
import AddNewPipeline from '../PipelineListsView/AddNewPipeline'; import AddNewPipeline from '../PipelineListsView/AddNewPipeline';
@ -36,22 +38,28 @@ beforeAll(() => {
matchMedia(); matchMedia();
}); });
function AddNewPipelineWrapper(): JSX.Element {
const setActionType = jest.fn();
const selectedPipelineData = pipelineMockData[0];
const isActionType = 'add-pipeline';
const [pipelineForm] = Form.useForm<PipelineData>();
return (
<AddNewPipeline
isActionType={isActionType}
setActionType={setActionType}
selectedPipelineData={selectedPipelineData}
setShowSaveButton={jest.fn()}
setCurrPipelineData={jest.fn()}
currPipelineData={pipelineMockData}
form={pipelineForm}
/>
);
}
describe('PipelinePage container test', () => { describe('PipelinePage container test', () => {
it('should render AddNewPipeline section', () => { it('should render AddNewPipeline section', () => {
const setActionType = jest.fn(); const { asFragment } = render(<AddNewPipelineWrapper />);
const selectedPipelineData = pipelineMockData[0];
const isActionType = 'add-pipeline';
const { asFragment } = render(
<AddNewPipeline
isActionType={isActionType}
setActionType={setActionType}
selectedPipelineData={selectedPipelineData}
setShowSaveButton={jest.fn()}
setCurrPipelineData={jest.fn()}
currPipelineData={pipelineMockData}
/>,
);
expect(asFragment()).toMatchSnapshot(); expect(asFragment()).toMatchSnapshot();
}); });
}); });

View File

@ -1,4 +1,5 @@
/* eslint-disable sonarjs/no-duplicate-string */ /* eslint-disable sonarjs/no-duplicate-string */
import { screen } from '@testing-library/react';
import { findByText, fireEvent, render, waitFor } from 'tests/test-utils'; import { findByText, fireEvent, render, waitFor } from 'tests/test-utils';
import { pipelineApiResponseMockData } from '../mocks/pipeline'; import { pipelineApiResponseMockData } from '../mocks/pipeline';
@ -243,4 +244,34 @@ describe('PipelinePage container test', () => {
expect(saveBtn).toBeInTheDocument(); expect(saveBtn).toBeInTheDocument();
await fireEvent.click(saveBtn); await fireEvent.click(saveBtn);
}); });
it('should have populated form fields when edit pipeline is clicked', async () => {
render(
<PipelineListsView
setActionType={jest.fn()}
isActionMode="editing-mode"
setActionMode={jest.fn()}
pipelineData={pipelineApiResponseMockData}
isActionType="edit-pipeline"
refetchPipelineLists={jest.fn()}
/>,
);
// content assertion
expect(document.querySelectorAll('[data-icon="edit"]').length).toBe(2);
// expand action
const expandIcon = document.querySelectorAll(
'.ant-table-row-expand-icon-cell > span[class*="anticon-right"]',
);
expect(expandIcon.length).toBe(2);
await fireEvent.click(expandIcon[0]);
const editBtn = document.querySelectorAll('[data-icon="edit"]');
// click on edit btn
await fireEvent.click(editBtn[0] as HTMLElement);
// to have length 2
expect(screen.queryAllByText('source = nginx').length).toBe(2);
});
}); });

View File

@ -51,6 +51,8 @@ import { getUserOperatingSystem, UserOperatingSystem } from 'utils/getUserOS';
import { popupContainer } from 'utils/selectPopupContainer'; import { popupContainer } from 'utils/selectPopupContainer';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import { FeatureKeys } from '../../../../constants/features';
import { useAppContext } from '../../../../providers/App/App';
import { selectStyle } from './config'; import { selectStyle } from './config';
import { PLACEHOLDER } from './constant'; import { PLACEHOLDER } from './constant';
import ExampleQueriesRendererForLogs from './ExampleQueriesRendererForLogs'; import ExampleQueriesRendererForLogs from './ExampleQueriesRendererForLogs';
@ -85,6 +87,11 @@ function QueryBuilderSearch({
const [isEditingTag, setIsEditingTag] = useState(false); const [isEditingTag, setIsEditingTag] = useState(false);
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const { const {
updateTag, updateTag,
handleClearTag, handleClearTag,
@ -104,6 +111,7 @@ function QueryBuilderSearch({
exampleQueries, exampleQueries,
} = useAutoComplete( } = useAutoComplete(
query, query,
dotMetricsEnabled,
whereClauseConfig, whereClauseConfig,
isLogsExplorerPage, isLogsExplorerPage,
isInfraMonitoring, isInfraMonitoring,
@ -121,6 +129,7 @@ function QueryBuilderSearch({
const { sourceKeys, handleRemoveSourceKey } = useFetchKeysAndValues( const { sourceKeys, handleRemoveSourceKey } = useFetchKeysAndValues(
searchValue, searchValue,
query, query,
dotMetricsEnabled,
searchKey, searchKey,
isLogsExplorerPage, isLogsExplorerPage,
isInfraMonitoring, isInfraMonitoring,

View File

@ -9,12 +9,15 @@ import {
convertMetricKeyToTrace, convertMetricKeyToTrace,
getEnvironmentTagKeys, getEnvironmentTagKeys,
getEnvironmentTagValues, getEnvironmentTagValues,
getResourceDeploymentKeys,
} from 'hooks/useResourceAttribute/utils'; } from 'hooks/useResourceAttribute/utils';
import { ReactNode, useEffect, useMemo, useState } from 'react'; import { ReactNode, useEffect, useMemo, useState } from 'react';
import { SelectOption } from 'types/common/select'; import { SelectOption } from 'types/common/select';
import { popupContainer } from 'utils/selectPopupContainer'; import { popupContainer } from 'utils/selectPopupContainer';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import { FeatureKeys } from '../../constants/features';
import { useAppContext } from '../../providers/App/App';
import QueryChip from './components/QueryChip'; import QueryChip from './components/QueryChip';
import { QueryChipItem, SearchContainer } from './styles'; import { QueryChipItem, SearchContainer } from './styles';
@ -39,24 +42,27 @@ function ResourceAttributesFilter({
SelectOption<string, string>[] SelectOption<string, string>[]
>([]); >([]);
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const resourceDeploymentKey = getResourceDeploymentKeys(dotMetricsEnabled);
const [selectedEnvironments, setSelectedEnvironments] = useState<string[]>([]); const [selectedEnvironments, setSelectedEnvironments] = useState<string[]>([]);
const queriesExcludingEnvironment = useMemo( const queriesExcludingEnvironment = useMemo(
() => () => queries.filter((query) => query.tagKey !== resourceDeploymentKey),
queries.filter( [queries, resourceDeploymentKey],
(query) => query.tagKey !== 'resource_deployment_environment',
),
[queries],
); );
const isEmpty = useMemo( const isEmpty = useMemo(
() => isResourceEmpty(queriesExcludingEnvironment, staging, selectedQuery), () => isResourceEmpty(queriesExcludingEnvironment, staging, selectedQuery),
[queriesExcludingEnvironment, selectedQuery, staging], [queriesExcludingEnvironment, selectedQuery, staging],
); );
useEffect(() => { useEffect(() => {
const resourceDeploymentEnvironmentQuery = queries.filter( const resourceDeploymentEnvironmentQuery = queries.filter(
(query) => query.tagKey === 'resource_deployment_environment', (query) => query.tagKey === resourceDeploymentKey,
); );
if (resourceDeploymentEnvironmentQuery?.length > 0) { if (resourceDeploymentEnvironmentQuery?.length > 0) {
@ -64,17 +70,17 @@ function ResourceAttributesFilter({
} else { } else {
setSelectedEnvironments([]); setSelectedEnvironments([]);
} }
}, [queries]); }, [queries, resourceDeploymentKey]);
useEffect(() => { useEffect(() => {
getEnvironmentTagKeys().then((tagKeys) => { getEnvironmentTagKeys(dotMetricsEnabled).then((tagKeys) => {
if (tagKeys && Array.isArray(tagKeys) && tagKeys.length > 0) { if (tagKeys && Array.isArray(tagKeys) && tagKeys.length > 0) {
getEnvironmentTagValues().then((tagValues) => { getEnvironmentTagValues(dotMetricsEnabled).then((tagValues) => {
setEnvironments(tagValues); setEnvironments(tagValues);
}); });
} }
}); });
}, []); }, [dotMetricsEnabled]);
return ( return (
<div className="resourceAttributesFilter-container"> <div className="resourceAttributesFilter-container">

View File

@ -1,5 +1,10 @@
import { convertMetricKeyToTrace } from 'hooks/useResourceAttribute/utils'; import {
convertMetricKeyToTrace,
getResourceDeploymentKeys,
} from 'hooks/useResourceAttribute/utils';
import { FeatureKeys } from '../../../../constants/features';
import { useAppContext } from '../../../../providers/App/App';
import { QueryChipContainer, QueryChipItem } from '../../styles'; import { QueryChipContainer, QueryChipItem } from '../../styles';
import { IQueryChipProps } from './types'; import { IQueryChipProps } from './types';
@ -8,12 +13,17 @@ function QueryChip({ queryData, onClose }: IQueryChipProps): JSX.Element {
onClose(queryData.id); onClose(queryData.id);
}; };
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
return ( return (
<QueryChipContainer> <QueryChipContainer>
<QueryChipItem>{convertMetricKeyToTrace(queryData.tagKey)}</QueryChipItem> <QueryChipItem>{convertMetricKeyToTrace(queryData.tagKey)}</QueryChipItem>
<QueryChipItem>{queryData.operator}</QueryChipItem> <QueryChipItem>{queryData.operator}</QueryChipItem>
<QueryChipItem <QueryChipItem
closable={queryData.tagKey !== 'resource_deployment_environment'} closable={queryData.tagKey !== getResourceDeploymentKeys(dotMetricsEnabled)}
onClose={onCloseHandler} onClose={onCloseHandler}
> >
{queryData.tagValue.join(', ')} {queryData.tagValue.join(', ')}

View File

@ -3,6 +3,8 @@ import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers'; import { AppState } from 'store/reducers';
import { GlobalReducer } from 'types/reducer/globalTime'; import { GlobalReducer } from 'types/reducer/globalTime';
import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App';
import { ServiceMetricsProps } from '../types'; import { ServiceMetricsProps } from '../types';
import { getQueryRangeRequestData } from '../utils'; import { getQueryRangeRequestData } from '../utils';
import ServiceMetricTable from './ServiceMetricTable'; import ServiceMetricTable from './ServiceMetricTable';
@ -15,6 +17,11 @@ function ServiceMetricsApplication({
GlobalReducer GlobalReducer
>((state) => state.globalTime); >((state) => state.globalTime);
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const queryRangeRequestData = useMemo( const queryRangeRequestData = useMemo(
() => () =>
getQueryRangeRequestData({ getQueryRangeRequestData({
@ -22,8 +29,15 @@ function ServiceMetricsApplication({
minTime, minTime,
maxTime, maxTime,
globalSelectedInterval, globalSelectedInterval,
dotMetricsEnabled,
}), }),
[globalSelectedInterval, maxTime, minTime, topLevelOperations], [
globalSelectedInterval,
maxTime,
minTime,
topLevelOperations,
dotMetricsEnabled,
],
); );
return ( return (
<ServiceMetricTable <ServiceMetricTable

View File

@ -19,11 +19,14 @@ import {
export const serviceMetricsQuery = ( export const serviceMetricsQuery = (
topLevelOperation: [keyof ServiceDataProps, string[]], topLevelOperation: [keyof ServiceDataProps, string[]],
dotMetricsEnabled: boolean,
): QueryBuilderData => { ): QueryBuilderData => {
const p99AutoCompleteData: BaseAutocompleteData = { const p99AutoCompleteData: BaseAutocompleteData = {
dataType: DataTypes.Float64, dataType: DataTypes.Float64,
isColumn: true, isColumn: true,
key: WidgetKeys.Signoz_latency_bucket, key: dotMetricsEnabled
? WidgetKeys.Signoz_latency_bucket
: WidgetKeys.Signoz_latency_bucket_norm,
type: '', type: '',
}; };
@ -54,7 +57,9 @@ export const serviceMetricsQuery = (
key: { key: {
dataType: DataTypes.String, dataType: DataTypes.String,
isColumn: false, isColumn: false,
key: WidgetKeys.Service_name, key: dotMetricsEnabled
? WidgetKeys.Service_name
: WidgetKeys.Service_name_norm,
type: MetricsType.Resource, type: MetricsType.Resource,
}, },
op: OPERATORS.IN, op: OPERATORS.IN,
@ -79,7 +84,9 @@ export const serviceMetricsQuery = (
key: { key: {
dataType: DataTypes.String, dataType: DataTypes.String,
isColumn: false, isColumn: false,
key: WidgetKeys.Service_name, key: dotMetricsEnabled
? WidgetKeys.Service_name
: WidgetKeys.Service_name_norm,
type: MetricsType.Resource, type: MetricsType.Resource,
}, },
op: OPERATORS.IN, op: OPERATORS.IN,
@ -90,7 +97,7 @@ export const serviceMetricsQuery = (
key: { key: {
dataType: DataTypes.Int64, dataType: DataTypes.Int64,
isColumn: false, isColumn: false,
key: WidgetKeys.StatusCode, key: dotMetricsEnabled ? WidgetKeys.StatusCode : WidgetKeys.StatusCodeNorm,
type: MetricsType.Tag, type: MetricsType.Tag,
}, },
op: OPERATORS.IN, op: OPERATORS.IN,
@ -115,7 +122,9 @@ export const serviceMetricsQuery = (
key: { key: {
dataType: DataTypes.String, dataType: DataTypes.String,
isColumn: false, isColumn: false,
key: WidgetKeys.Service_name, key: dotMetricsEnabled
? WidgetKeys.Service_name
: WidgetKeys.Service_name_norm,
type: MetricsType.Resource, type: MetricsType.Resource,
}, },
op: OPERATORS.IN, op: OPERATORS.IN,
@ -140,7 +149,9 @@ export const serviceMetricsQuery = (
key: { key: {
dataType: DataTypes.String, dataType: DataTypes.String,
isColumn: false, isColumn: false,
key: WidgetKeys.Service_name, key: dotMetricsEnabled
? WidgetKeys.Service_name
: WidgetKeys.Service_name_norm,
type: MetricsType.Resource, type: MetricsType.Resource,
}, },
op: OPERATORS.IN, op: OPERATORS.IN,
@ -195,7 +206,9 @@ export const serviceMetricsQuery = (
{ {
dataType: DataTypes.String, dataType: DataTypes.String,
isColumn: false, isColumn: false,
key: WidgetKeys.Service_name, key: dotMetricsEnabled
? WidgetKeys.Service_name
: WidgetKeys.Service_name_norm,
type: MetricsType.Tag, type: MetricsType.Tag,
}, },
]; ];

View File

@ -5,7 +5,10 @@ import { SKIP_ONBOARDING } from 'constants/onboarding';
import useErrorNotification from 'hooks/useErrorNotification'; import useErrorNotification from 'hooks/useErrorNotification';
import { useQueryService } from 'hooks/useQueryService'; import { useQueryService } from 'hooks/useQueryService';
import useResourceAttribute from 'hooks/useResourceAttribute'; import useResourceAttribute from 'hooks/useResourceAttribute';
import { convertRawQueriesToTraceSelectedTags } from 'hooks/useResourceAttribute/utils'; import {
convertRawQueriesToTraceSelectedTags,
getResourceDeploymentKeys,
} from 'hooks/useResourceAttribute/utils';
import { isUndefined } from 'lodash-es'; import { isUndefined } from 'lodash-es';
import { useEffect, useMemo, useRef, useState } from 'react'; import { useEffect, useMemo, useRef, useState } from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
@ -13,6 +16,8 @@ import { AppState } from 'store/reducers';
import { GlobalReducer } from 'types/reducer/globalTime'; import { GlobalReducer } from 'types/reducer/globalTime';
import { Tags } from 'types/reducer/trace'; import { Tags } from 'types/reducer/trace';
import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App';
import SkipOnBoardingModal from '../SkipOnBoardModal'; import SkipOnBoardingModal from '../SkipOnBoardModal';
import ServiceTraceTable from './ServiceTracesTable'; import ServiceTraceTable from './ServiceTracesTable';
@ -34,6 +39,11 @@ function ServiceTraces(): JSX.Element {
selectedTags, selectedTags,
}); });
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
useErrorNotification(error); useErrorNotification(error);
const services = data || []; const services = data || [];
@ -51,7 +61,7 @@ function ServiceTraces(): JSX.Element {
useEffect(() => { useEffect(() => {
if (!logEventCalledRef.current && !isUndefined(data)) { if (!logEventCalledRef.current && !isUndefined(data)) {
const selectedEnvironments = queries.find( const selectedEnvironments = queries.find(
(val) => val.tagKey === 'resource_deployment_environment', (val) => val.tagKey === getResourceDeploymentKeys(dotMetricsEnabled),
)?.tagValue; )?.tagValue;
const rps = data.reduce((total, service) => total + service.callRate, 0); const rps = data.reduce((total, service) => total + service.callRate, 0);

View File

@ -29,6 +29,7 @@ export interface GetQueryRangeRequestDataProps {
maxTime: number; maxTime: number;
minTime: number; minTime: number;
globalSelectedInterval: Time | TimeV2 | CustomTimeType; globalSelectedInterval: Time | TimeV2 | CustomTimeType;
dotMetricsEnabled: boolean;
} }
export interface GetServiceListFromQueryProps { export interface GetServiceListFromQueryProps {

View File

@ -28,6 +28,7 @@ export const getQueryRangeRequestData = ({
maxTime, maxTime,
minTime, minTime,
globalSelectedInterval, globalSelectedInterval,
dotMetricsEnabled,
}: GetQueryRangeRequestDataProps): GetQueryResultsProps[] => { }: GetQueryRangeRequestDataProps): GetQueryResultsProps[] => {
const requestData: GetQueryResultsProps[] = []; const requestData: GetQueryResultsProps[] = [];
topLevelOperations.forEach((operation) => { topLevelOperations.forEach((operation) => {
@ -35,7 +36,7 @@ export const getQueryRangeRequestData = ({
query: { query: {
queryType: EQueryType.QUERY_BUILDER, queryType: EQueryType.QUERY_BUILDER,
promql: [], promql: [],
builder: serviceMetricsQuery(operation), builder: serviceMetricsQuery(operation, dotMetricsEnabled),
clickhouse_sql: [], clickhouse_sql: [],
id: uuid(), id: uuid(),
}, },

View File

@ -17,6 +17,7 @@ type UseGetK8sClustersList = (
>, >,
headers?: Record<string, string>, headers?: Record<string, string>,
dotMetricsEnabled?: boolean,
) => UseQueryResult< ) => UseQueryResult<
SuccessResponse<K8sClustersListResponse> | ErrorResponse, SuccessResponse<K8sClustersListResponse> | ErrorResponse,
Error Error
@ -28,6 +29,7 @@ export const useGetK8sClustersList: UseGetK8sClustersList = (
options, options,
headers, headers,
dotMetricsEnabled?: boolean,
) => { ) => {
const queryKey = useMemo(() => { const queryKey = useMemo(() => {
if (options?.queryKey && Array.isArray(options.queryKey)) { if (options?.queryKey && Array.isArray(options.queryKey)) {
@ -45,7 +47,8 @@ export const useGetK8sClustersList: UseGetK8sClustersList = (
SuccessResponse<K8sClustersListResponse> | ErrorResponse, SuccessResponse<K8sClustersListResponse> | ErrorResponse,
Error Error
>({ >({
queryFn: ({ signal }) => getK8sClustersList(requestData, signal, headers), queryFn: ({ signal }) =>
getK8sClustersList(requestData, signal, headers, dotMetricsEnabled),
...options, ...options,

View File

@ -17,6 +17,7 @@ type UseGetK8sDaemonSetsList = (
>, >,
headers?: Record<string, string>, headers?: Record<string, string>,
dotMetricsEnabled?: boolean,
) => UseQueryResult< ) => UseQueryResult<
SuccessResponse<K8sDaemonSetsListResponse> | ErrorResponse, SuccessResponse<K8sDaemonSetsListResponse> | ErrorResponse,
Error Error
@ -28,6 +29,7 @@ export const useGetK8sDaemonSetsList: UseGetK8sDaemonSetsList = (
options, options,
headers, headers,
dotMetricsEnabled,
) => { ) => {
const queryKey = useMemo(() => { const queryKey = useMemo(() => {
if (options?.queryKey && Array.isArray(options.queryKey)) { if (options?.queryKey && Array.isArray(options.queryKey)) {
@ -45,7 +47,8 @@ export const useGetK8sDaemonSetsList: UseGetK8sDaemonSetsList = (
SuccessResponse<K8sDaemonSetsListResponse> | ErrorResponse, SuccessResponse<K8sDaemonSetsListResponse> | ErrorResponse,
Error Error
>({ >({
queryFn: ({ signal }) => getK8sDaemonSetsList(requestData, signal, headers), queryFn: ({ signal }) =>
getK8sDaemonSetsList(requestData, signal, headers, dotMetricsEnabled),
...options, ...options,

View File

@ -15,6 +15,7 @@ type UseGetK8sDeploymentsList = (
Error Error
>, >,
headers?: Record<string, string>, headers?: Record<string, string>,
dotMetricsEnabled?: boolean,
) => UseQueryResult< ) => UseQueryResult<
SuccessResponse<K8sDeploymentsListResponse> | ErrorResponse, SuccessResponse<K8sDeploymentsListResponse> | ErrorResponse,
Error Error
@ -24,6 +25,7 @@ export const useGetK8sDeploymentsList: UseGetK8sDeploymentsList = (
requestData, requestData,
options, options,
headers, headers,
dotMetricsEnabled,
) => { ) => {
const queryKey = useMemo(() => { const queryKey = useMemo(() => {
if (options?.queryKey && Array.isArray(options.queryKey)) { if (options?.queryKey && Array.isArray(options.queryKey)) {
@ -41,7 +43,8 @@ export const useGetK8sDeploymentsList: UseGetK8sDeploymentsList = (
SuccessResponse<K8sDeploymentsListResponse> | ErrorResponse, SuccessResponse<K8sDeploymentsListResponse> | ErrorResponse,
Error Error
>({ >({
queryFn: ({ signal }) => getK8sDeploymentsList(requestData, signal, headers), queryFn: ({ signal }) =>
getK8sDeploymentsList(requestData, signal, headers, dotMetricsEnabled),
...options, ...options,
queryKey, queryKey,
}); });

View File

@ -17,6 +17,7 @@ type UseGetK8sJobsList = (
>, >,
headers?: Record<string, string>, headers?: Record<string, string>,
dotMetricsEnabled?: boolean,
) => UseQueryResult< ) => UseQueryResult<
SuccessResponse<K8sJobsListResponse> | ErrorResponse, SuccessResponse<K8sJobsListResponse> | ErrorResponse,
Error Error
@ -28,6 +29,7 @@ export const useGetK8sJobsList: UseGetK8sJobsList = (
options, options,
headers, headers,
dotMetricsEnabled,
) => { ) => {
const queryKey = useMemo(() => { const queryKey = useMemo(() => {
if (options?.queryKey && Array.isArray(options.queryKey)) { if (options?.queryKey && Array.isArray(options.queryKey)) {
@ -42,7 +44,8 @@ export const useGetK8sJobsList: UseGetK8sJobsList = (
}, [options?.queryKey, requestData]); }, [options?.queryKey, requestData]);
return useQuery<SuccessResponse<K8sJobsListResponse> | ErrorResponse, Error>({ return useQuery<SuccessResponse<K8sJobsListResponse> | ErrorResponse, Error>({
queryFn: ({ signal }) => getK8sJobsList(requestData, signal, headers), queryFn: ({ signal }) =>
getK8sJobsList(requestData, signal, headers, dotMetricsEnabled),
...options, ...options,

View File

@ -15,6 +15,7 @@ type UseGetK8sNamespacesList = (
Error Error
>, >,
headers?: Record<string, string>, headers?: Record<string, string>,
dotMetricsEnabled?: boolean,
) => UseQueryResult< ) => UseQueryResult<
SuccessResponse<K8sNamespacesListResponse> | ErrorResponse, SuccessResponse<K8sNamespacesListResponse> | ErrorResponse,
Error Error
@ -24,6 +25,7 @@ export const useGetK8sNamespacesList: UseGetK8sNamespacesList = (
requestData, requestData,
options, options,
headers, headers,
dotMetricsEnabled,
) => { ) => {
const queryKey = useMemo(() => { const queryKey = useMemo(() => {
if (options?.queryKey && Array.isArray(options.queryKey)) { if (options?.queryKey && Array.isArray(options.queryKey)) {
@ -41,7 +43,8 @@ export const useGetK8sNamespacesList: UseGetK8sNamespacesList = (
SuccessResponse<K8sNamespacesListResponse> | ErrorResponse, SuccessResponse<K8sNamespacesListResponse> | ErrorResponse,
Error Error
>({ >({
queryFn: ({ signal }) => getK8sNamespacesList(requestData, signal, headers), queryFn: ({ signal }) =>
getK8sNamespacesList(requestData, signal, headers, dotMetricsEnabled),
...options, ...options,
queryKey, queryKey,
}); });

View File

@ -15,6 +15,7 @@ type UseGetK8sNodesList = (
Error Error
>, >,
headers?: Record<string, string>, headers?: Record<string, string>,
dotMetricsEnabled?: boolean,
) => UseQueryResult< ) => UseQueryResult<
SuccessResponse<K8sNodesListResponse> | ErrorResponse, SuccessResponse<K8sNodesListResponse> | ErrorResponse,
Error Error
@ -24,6 +25,7 @@ export const useGetK8sNodesList: UseGetK8sNodesList = (
requestData, requestData,
options, options,
headers, headers,
dotMetricsEnabled,
) => { ) => {
const queryKey = useMemo(() => { const queryKey = useMemo(() => {
if (options?.queryKey && Array.isArray(options.queryKey)) { if (options?.queryKey && Array.isArray(options.queryKey)) {
@ -38,7 +40,8 @@ export const useGetK8sNodesList: UseGetK8sNodesList = (
}, [options?.queryKey, requestData]); }, [options?.queryKey, requestData]);
return useQuery<SuccessResponse<K8sNodesListResponse> | ErrorResponse, Error>({ return useQuery<SuccessResponse<K8sNodesListResponse> | ErrorResponse, Error>({
queryFn: ({ signal }) => getK8sNodesList(requestData, signal, headers), queryFn: ({ signal }) =>
getK8sNodesList(requestData, signal, headers, dotMetricsEnabled),
...options, ...options,
queryKey, queryKey,
}); });

View File

@ -15,6 +15,7 @@ type UseGetK8sPodsList = (
Error Error
>, >,
headers?: Record<string, string>, headers?: Record<string, string>,
dotMetricsEnabled?: boolean,
) => UseQueryResult< ) => UseQueryResult<
SuccessResponse<K8sPodsListResponse> | ErrorResponse, SuccessResponse<K8sPodsListResponse> | ErrorResponse,
Error Error
@ -24,6 +25,7 @@ export const useGetK8sPodsList: UseGetK8sPodsList = (
requestData, requestData,
options, options,
headers, headers,
dotMetricsEnabled,
) => { ) => {
const queryKey = useMemo(() => { const queryKey = useMemo(() => {
if (options?.queryKey && Array.isArray(options.queryKey)) { if (options?.queryKey && Array.isArray(options.queryKey)) {
@ -38,7 +40,8 @@ export const useGetK8sPodsList: UseGetK8sPodsList = (
}, [options?.queryKey, requestData]); }, [options?.queryKey, requestData]);
return useQuery<SuccessResponse<K8sPodsListResponse> | ErrorResponse, Error>({ return useQuery<SuccessResponse<K8sPodsListResponse> | ErrorResponse, Error>({
queryFn: ({ signal }) => getK8sPodsList(requestData, signal, headers), queryFn: ({ signal }) =>
getK8sPodsList(requestData, signal, headers, dotMetricsEnabled),
...options, ...options,
queryKey, queryKey,
}); });

View File

@ -17,6 +17,7 @@ type UseGetK8sStatefulSetsList = (
>, >,
headers?: Record<string, string>, headers?: Record<string, string>,
dotMetricsEnabled?: boolean,
) => UseQueryResult< ) => UseQueryResult<
SuccessResponse<K8sStatefulSetsListResponse> | ErrorResponse, SuccessResponse<K8sStatefulSetsListResponse> | ErrorResponse,
Error Error
@ -28,6 +29,7 @@ export const useGetK8sStatefulSetsList: UseGetK8sStatefulSetsList = (
options, options,
headers, headers,
dotMetricsEnabled,
) => { ) => {
const queryKey = useMemo(() => { const queryKey = useMemo(() => {
if (options?.queryKey && Array.isArray(options.queryKey)) { if (options?.queryKey && Array.isArray(options.queryKey)) {
@ -45,7 +47,8 @@ export const useGetK8sStatefulSetsList: UseGetK8sStatefulSetsList = (
SuccessResponse<K8sStatefulSetsListResponse> | ErrorResponse, SuccessResponse<K8sStatefulSetsListResponse> | ErrorResponse,
Error Error
>({ >({
queryFn: ({ signal }) => getK8sStatefulSetsList(requestData, signal, headers), queryFn: ({ signal }) =>
getK8sStatefulSetsList(requestData, signal, headers, dotMetricsEnabled),
...options, ...options,

View File

@ -15,6 +15,7 @@ type UseGetK8sVolumesList = (
Error Error
>, >,
headers?: Record<string, string>, headers?: Record<string, string>,
dotMetricsEnabled?: boolean,
) => UseQueryResult< ) => UseQueryResult<
SuccessResponse<K8sVolumesListResponse> | ErrorResponse, SuccessResponse<K8sVolumesListResponse> | ErrorResponse,
Error Error
@ -24,6 +25,7 @@ export const useGetK8sVolumesList: UseGetK8sVolumesList = (
requestData, requestData,
options, options,
headers, headers,
dotMetricsEnabled,
) => { ) => {
const queryKey = useMemo(() => { const queryKey = useMemo(() => {
if (options?.queryKey && Array.isArray(options.queryKey)) { if (options?.queryKey && Array.isArray(options.queryKey)) {
@ -41,7 +43,8 @@ export const useGetK8sVolumesList: UseGetK8sVolumesList = (
SuccessResponse<K8sVolumesListResponse> | ErrorResponse, SuccessResponse<K8sVolumesListResponse> | ErrorResponse,
Error Error
>({ >({
queryFn: ({ signal }) => getK8sVolumesList(requestData, signal, headers), queryFn: ({ signal }) =>
getK8sVolumesList(requestData, signal, headers, dotMetricsEnabled),
...options, ...options,
queryKey, queryKey,
}); });

View File

@ -27,6 +27,7 @@ export type WhereClauseConfig = {
export const useAutoComplete = ( export const useAutoComplete = (
query: IBuilderQuery, query: IBuilderQuery,
dotMetricsEnabled: boolean,
whereClauseConfig?: WhereClauseConfig, whereClauseConfig?: WhereClauseConfig,
shouldUseSuggestions?: boolean, shouldUseSuggestions?: boolean,
isInfraMonitoring?: boolean, isInfraMonitoring?: boolean,
@ -39,6 +40,7 @@ export const useAutoComplete = (
const { keys, results, isFetching, exampleQueries } = useFetchKeysAndValues( const { keys, results, isFetching, exampleQueries } = useFetchKeysAndValues(
searchValue, searchValue,
query, query,
dotMetricsEnabled,
searchKey, searchKey,
shouldUseSuggestions, shouldUseSuggestions,
isInfraMonitoring, isInfraMonitoring,

View File

@ -4,8 +4,8 @@ import { getAttributesValues } from 'api/queryBuilder/getAttributesValues';
import { DATA_TYPE_VS_ATTRIBUTE_VALUES_KEY } from 'constants/queryBuilder'; import { DATA_TYPE_VS_ATTRIBUTE_VALUES_KEY } from 'constants/queryBuilder';
import { DEBOUNCE_DELAY } from 'constants/queryBuilderFilterConfig'; import { DEBOUNCE_DELAY } from 'constants/queryBuilderFilterConfig';
import { import {
GetK8sEntityToAggregateAttribute,
K8sCategory, K8sCategory,
K8sEntityToAggregateAttributeMapping,
} from 'container/InfraMonitoringK8s/constants'; } from 'container/InfraMonitoringK8s/constants';
import { import {
getRemovePrefixFromKey, getRemovePrefixFromKey,
@ -50,6 +50,7 @@ type IuseFetchKeysAndValues = {
export const useFetchKeysAndValues = ( export const useFetchKeysAndValues = (
searchValue: string, searchValue: string,
query: IBuilderQuery, query: IBuilderQuery,
dotMetricsEnabled: boolean,
searchKey: string, searchKey: string,
shouldUseSuggestions?: boolean, shouldUseSuggestions?: boolean,
isInfraMonitoring?: boolean, isInfraMonitoring?: boolean,
@ -123,7 +124,7 @@ export const useFetchKeysAndValues = (
aggregateOperator: query.aggregateOperator, aggregateOperator: query.aggregateOperator,
aggregateAttribute: aggregateAttribute:
isInfraMonitoring && entity isInfraMonitoring && entity
? K8sEntityToAggregateAttributeMapping[entity] ? GetK8sEntityToAggregateAttribute(entity, dotMetricsEnabled)
: query.aggregateAttribute.key, : query.aggregateAttribute.key,
tagType: query.aggregateAttribute.type ?? null, tagType: query.aggregateAttribute.type ?? null,
}, },
@ -219,7 +220,7 @@ export const useFetchKeysAndValues = (
aggregateOperator: 'noop', aggregateOperator: 'noop',
dataSource: query.dataSource, dataSource: query.dataSource,
aggregateAttribute: aggregateAttribute:
K8sEntityToAggregateAttributeMapping[entity] || GetK8sEntityToAggregateAttribute(entity, dotMetricsEnabled) ||
query.aggregateAttribute.key, query.aggregateAttribute.key,
attributeKey: filterAttributeKey?.key ?? tagKey, attributeKey: filterAttributeKey?.key ?? tagKey,
filterAttributeKeyDataType: filterAttributeKeyDataType:

View File

@ -7,6 +7,8 @@ import { encode } from 'js-base64';
import { ReactNode, useCallback, useEffect, useMemo, useState } from 'react'; import { ReactNode, useCallback, useEffect, useMemo, useState } from 'react';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import { FeatureKeys } from '../../constants/features';
import { useAppContext } from '../../providers/App/App';
import { whilelistedKeys } from './config'; import { whilelistedKeys } from './config';
import { ResourceContext } from './context'; import { ResourceContext } from './context';
import { ResourceAttributesFilterMachine } from './machine'; import { ResourceAttributesFilterMachine } from './machine';
@ -18,6 +20,7 @@ import {
import { import {
createQuery, createQuery,
getResourceAttributeQueriesFromURL, getResourceAttributeQueriesFromURL,
getResourceDeploymentKeys,
GetTagKeys, GetTagKeys,
GetTagValues, GetTagValues,
mappingWithRoutesAndKeys, mappingWithRoutesAndKeys,
@ -53,6 +56,11 @@ function ResourceProvider({ children }: Props): JSX.Element {
} }
}; };
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const dispatchQueries = useCallback( const dispatchQueries = useCallback(
(queries: IResourceAttribute[]): void => { (queries: IResourceAttribute[]): void => {
urlQuery.set( urlQuery.set(
@ -70,7 +78,7 @@ function ResourceProvider({ children }: Props): JSX.Element {
actions: { actions: {
onSelectTagKey: () => { onSelectTagKey: () => {
handleLoading(true); handleLoading(true);
GetTagKeys() GetTagKeys(dotMetricsEnabled)
.then((tagKeys) => { .then((tagKeys) => {
const options = mappingWithRoutesAndKeys(pathname, tagKeys); const options = mappingWithRoutesAndKeys(pathname, tagKeys);
@ -141,10 +149,10 @@ function ResourceProvider({ children }: Props): JSX.Element {
const handleEnvironmentChange = useCallback( const handleEnvironmentChange = useCallback(
(environments: string[]): void => { (environments: string[]): void => {
const staging = ['resource_deployment_environment', 'IN']; const staging = [getResourceDeploymentKeys(dotMetricsEnabled), 'IN'];
const queriesCopy = queries.filter( const queriesCopy = queries.filter(
(query) => query.tagKey !== 'resource_deployment_environment', (query) => query.tagKey !== getResourceDeploymentKeys(dotMetricsEnabled),
); );
if (environments && Array.isArray(environments) && environments.length > 0) { if (environments && Array.isArray(environments) && environments.length > 0) {
@ -159,7 +167,7 @@ function ResourceProvider({ children }: Props): JSX.Element {
send('RESET'); send('RESET');
}, },
[dispatchQueries, queries, send], [dispatchQueries, dotMetricsEnabled, queries, send],
); );
const handleClose = useCallback( const handleClose = useCallback(

View File

@ -1,10 +1,14 @@
import { act, renderHook, waitFor } from '@testing-library/react'; import { act, renderHook, waitFor } from '@testing-library/react';
import { createMemoryHistory } from 'history'; import { createMemoryHistory } from 'history';
import { AppProvider } from 'providers/App/App';
import { QueryClient, QueryClientProvider } from 'react-query';
import { Router } from 'react-router-dom'; import { Router } from 'react-router-dom';
import ResourceProvider from '../ResourceProvider'; import ResourceProvider from '../ResourceProvider';
import useResourceAttribute from '../useResourceAttribute'; import useResourceAttribute from '../useResourceAttribute';
const queryClient = new QueryClient();
jest.mock('hooks/useSafeNavigate', () => ({ jest.mock('hooks/useSafeNavigate', () => ({
useSafeNavigate: (): any => ({ useSafeNavigate: (): any => ({
safeNavigate: jest.fn(), safeNavigate: jest.fn(),
@ -17,9 +21,13 @@ describe('useResourceAttribute component hook', () => {
initialEntries: ['/inital-url?tab=overview'], initialEntries: ['/inital-url?tab=overview'],
}); });
const wrapper = ({ children }: { children: any }): JSX.Element => ( const wrapper = ({ children }: { children: any }): JSX.Element => (
<Router history={history}> <QueryClientProvider client={queryClient}>
<ResourceProvider>{children}</ResourceProvider> <AppProvider>
</Router> <Router history={history}>
<ResourceProvider>{children}</ResourceProvider>
</Router>
</AppProvider>
</QueryClientProvider>
); );
const { result } = renderHook(() => useResourceAttribute(), { wrapper }); const { result } = renderHook(() => useResourceAttribute(), { wrapper });

View File

@ -146,7 +146,17 @@ export const OperatorSchema: IOption[] = OperatorConversions.map(
}), }),
); );
export const GetTagKeys = async (): Promise<IOption[]> => { export const getResourceDeploymentKeys = (
dotMetricsEnabled: boolean,
): string => {
if (dotMetricsEnabled) return 'resource_deployment.environment';
return 'resource_deployment_environment';
};
export const GetTagKeys = async (
dotMetricsEnabled: boolean,
): Promise<IOption[]> => {
const resourceDeploymentKey = getResourceDeploymentKeys(dotMetricsEnabled);
const { payload } = await getResourceAttributesTagKeys({ const { payload } = await getResourceAttributesTagKeys({
metricName: 'signoz_calls_total', metricName: 'signoz_calls_total',
match: 'resource_', match: 'resource_',
@ -159,17 +169,19 @@ export const GetTagKeys = async (): Promise<IOption[]> => {
payload.data.attributeKeys?.map((attributeKey) => attributeKey.key) || []; payload.data.attributeKeys?.map((attributeKey) => attributeKey.key) || [];
return keys return keys
.filter((tagKey: string) => tagKey !== 'resource_deployment_environment') .filter((tagKey: string) => tagKey !== resourceDeploymentKey)
.map((tagKey: string) => ({ .map((tagKey: string) => ({
label: convertMetricKeyToTrace(tagKey), label: convertMetricKeyToTrace(tagKey),
value: tagKey, value: tagKey,
})); }));
}; };
export const getEnvironmentTagKeys = async (): Promise<IOption[]> => { export const getEnvironmentTagKeys = async (
dotMetricsEnabled: boolean,
): Promise<IOption[]> => {
const { payload } = await getResourceAttributesTagKeys({ const { payload } = await getResourceAttributesTagKeys({
metricName: 'signoz_calls_total', metricName: 'signoz_calls_total',
match: 'resource_deployment_environment', match: getResourceDeploymentKeys(dotMetricsEnabled),
}); });
if (!payload || !payload?.data) { if (!payload || !payload?.data) {
return []; return [];
@ -182,9 +194,11 @@ export const getEnvironmentTagKeys = async (): Promise<IOption[]> => {
})); }));
}; };
export const getEnvironmentTagValues = async (): Promise<IOption[]> => { export const getEnvironmentTagValues = async (
dotMetricsEnabled: boolean,
): Promise<IOption[]> => {
const { payload } = await getResourceAttributesTagValues({ const { payload } = await getResourceAttributesTagValues({
tagKey: 'resource_deployment_environment', tagKey: getResourceDeploymentKeys(dotMetricsEnabled),
metricName: 'signoz_calls_total', metricName: 'signoz_calls_total',
}); });

View File

@ -4,22 +4,24 @@ import { useIsDarkMode } from 'hooks/useDarkMode';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Widgets } from 'types/api/dashboard/getAll'; import { Widgets } from 'types/api/dashboard/getAll';
import { FeatureKeys } from '../../../../constants/features';
import { useAppContext } from '../../../../providers/App/App';
import MetricPageGridGraph from './MetricPageGraph'; import MetricPageGridGraph from './MetricPageGraph';
import { import {
averageRequestLatencyWidgetData, getAverageRequestLatencyWidgetData,
brokerCountWidgetData, getBrokerCountWidgetData,
brokerNetworkThroughputWidgetData, getBrokerNetworkThroughputWidgetData,
bytesConsumedWidgetData, getBytesConsumedWidgetData,
consumerFetchRateWidgetData, getConsumerFetchRateWidgetData,
consumerGroupMemberWidgetData, getConsumerGroupMemberWidgetData,
consumerLagByGroupWidgetData, getConsumerLagByGroupWidgetData,
consumerOffsetWidgetData, getConsumerOffsetWidgetData,
ioWaitTimeWidgetData, getIoWaitTimeWidgetData,
kafkaProducerByteRateWidgetData, getKafkaProducerByteRateWidgetData,
messagesConsumedWidgetData, getMessagesConsumedWidgetData,
producerFetchRequestPurgatoryWidgetData, getProducerFetchRequestPurgatoryWidgetData,
requestResponseWidgetData, getRequestResponseWidgetData,
requestTimesWidgetData, getRequestTimesWidgetData,
} from './MetricPageUtil'; } from './MetricPageUtil';
interface MetricSectionProps { interface MetricSectionProps {
@ -71,15 +73,20 @@ function MetricColumnGraphs({
}): JSX.Element { }): JSX.Element {
const { t } = useTranslation('messagingQueues'); const { t } = useTranslation('messagingQueues');
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const metricsData = [ const metricsData = [
{ {
title: t('metricGraphCategory.brokerMetrics.title'), title: t('metricGraphCategory.brokerMetrics.title'),
description: t('metricGraphCategory.brokerMetrics.description'), description: t('metricGraphCategory.brokerMetrics.description'),
graphCount: [ graphCount: [
brokerCountWidgetData, getBrokerCountWidgetData(dotMetricsEnabled),
requestTimesWidgetData, getRequestTimesWidgetData(dotMetricsEnabled),
producerFetchRequestPurgatoryWidgetData, getProducerFetchRequestPurgatoryWidgetData(dotMetricsEnabled),
brokerNetworkThroughputWidgetData, getBrokerNetworkThroughputWidgetData(dotMetricsEnabled),
], ],
id: 'broker-metrics', id: 'broker-metrics',
}, },
@ -87,11 +94,11 @@ function MetricColumnGraphs({
title: t('metricGraphCategory.producerMetrics.title'), title: t('metricGraphCategory.producerMetrics.title'),
description: t('metricGraphCategory.producerMetrics.description'), description: t('metricGraphCategory.producerMetrics.description'),
graphCount: [ graphCount: [
ioWaitTimeWidgetData, getIoWaitTimeWidgetData(dotMetricsEnabled),
requestResponseWidgetData, getRequestResponseWidgetData(dotMetricsEnabled),
averageRequestLatencyWidgetData, getAverageRequestLatencyWidgetData(dotMetricsEnabled),
kafkaProducerByteRateWidgetData, getKafkaProducerByteRateWidgetData(dotMetricsEnabled),
bytesConsumedWidgetData, getBytesConsumedWidgetData(dotMetricsEnabled),
], ],
id: 'producer-metrics', id: 'producer-metrics',
}, },
@ -99,11 +106,11 @@ function MetricColumnGraphs({
title: t('metricGraphCategory.consumerMetrics.title'), title: t('metricGraphCategory.consumerMetrics.title'),
description: t('metricGraphCategory.consumerMetrics.description'), description: t('metricGraphCategory.consumerMetrics.description'),
graphCount: [ graphCount: [
consumerOffsetWidgetData, getConsumerOffsetWidgetData(dotMetricsEnabled),
consumerGroupMemberWidgetData, getConsumerGroupMemberWidgetData(dotMetricsEnabled),
consumerLagByGroupWidgetData, getConsumerLagByGroupWidgetData(dotMetricsEnabled),
consumerFetchRateWidgetData, getConsumerFetchRateWidgetData(dotMetricsEnabled),
messagesConsumedWidgetData, getMessagesConsumedWidgetData(dotMetricsEnabled),
], ],
id: 'consumer-metrics', id: 'consumer-metrics',
}, },

View File

@ -10,17 +10,19 @@ import { useRef, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Widgets } from 'types/api/dashboard/getAll'; import { Widgets } from 'types/api/dashboard/getAll';
import { FeatureKeys } from '../../../../constants/features';
import { useAppContext } from '../../../../providers/App/App';
import MetricColumnGraphs from './MetricColumnGraphs'; import MetricColumnGraphs from './MetricColumnGraphs';
import MetricPageGridGraph from './MetricPageGraph'; import MetricPageGridGraph from './MetricPageGraph';
import { import {
cpuRecentUtilizationWidgetData, getCpuRecentUtilizationWidgetData,
currentOffsetPartitionWidgetData, getCurrentOffsetPartitionWidgetData,
insyncReplicasWidgetData, getInsyncReplicasWidgetData,
jvmGcCollectionsElapsedWidgetData, getJvmGcCollectionsElapsedWidgetData,
jvmGCCountWidgetData, getJvmGCCountWidgetData,
jvmMemoryHeapWidgetData, getJvmMemoryHeapWidgetData,
oldestOffsetWidgetData, getOldestOffsetWidgetData,
partitionCountPerTopicWidgetData, getPartitionCountPerTopicWidgetData,
} from './MetricPageUtil'; } from './MetricPageUtil';
interface CollapsibleMetricSectionProps { interface CollapsibleMetricSectionProps {
@ -95,6 +97,11 @@ function MetricPage(): JSX.Element {
})); }));
}; };
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const { t } = useTranslation('messagingQueues'); const { t } = useTranslation('messagingQueues');
const metricSections = [ const metricSections = [
@ -103,10 +110,10 @@ function MetricPage(): JSX.Element {
title: t('metricGraphCategory.brokerJVMMetrics.title'), title: t('metricGraphCategory.brokerJVMMetrics.title'),
description: t('metricGraphCategory.brokerJVMMetrics.description'), description: t('metricGraphCategory.brokerJVMMetrics.description'),
graphCount: [ graphCount: [
jvmGCCountWidgetData, getJvmGCCountWidgetData(dotMetricsEnabled),
jvmGcCollectionsElapsedWidgetData, getJvmGcCollectionsElapsedWidgetData(dotMetricsEnabled),
cpuRecentUtilizationWidgetData, getCpuRecentUtilizationWidgetData(dotMetricsEnabled),
jvmMemoryHeapWidgetData, getJvmMemoryHeapWidgetData(dotMetricsEnabled),
], ],
}, },
{ {
@ -114,10 +121,10 @@ function MetricPage(): JSX.Element {
title: t('metricGraphCategory.partitionMetrics.title'), title: t('metricGraphCategory.partitionMetrics.title'),
description: t('metricGraphCategory.partitionMetrics.description'), description: t('metricGraphCategory.partitionMetrics.description'),
graphCount: [ graphCount: [
partitionCountPerTopicWidgetData, getPartitionCountPerTopicWidgetData(dotMetricsEnabled),
currentOffsetPartitionWidgetData, getCurrentOffsetPartitionWidgetData(dotMetricsEnabled),
oldestOffsetWidgetData, getOldestOffsetWidgetData(dotMetricsEnabled),
insyncReplicasWidgetData, getInsyncReplicasWidgetData(dotMetricsEnabled),
], ],
}, },
]; ];

View File

@ -13,6 +13,8 @@ import { useState } from 'react';
import { useHistory, useLocation } from 'react-router-dom'; import { useHistory, useLocation } from 'react-router-dom';
import { useCopyToClipboard } from 'react-use'; import { useCopyToClipboard } from 'react-use';
import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App';
import { useGetAllConfigOptions } from './useGetAllConfigOptions'; import { useGetAllConfigOptions } from './useGetAllConfigOptions';
type ConfigOptionType = 'group' | 'topic' | 'partition'; type ConfigOptionType = 'group' | 'topic' | 'partition';
@ -38,11 +40,19 @@ const useConfigOptions = (
isFetching: boolean; isFetching: boolean;
options: DefaultOptionType[]; options: DefaultOptionType[];
} => { } => {
const { featureFlags } = useAppContext();
const dotMetricsEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
?.active || false;
const [searchText, setSearchText] = useState<string>(''); const [searchText, setSearchText] = useState<string>('');
const { isFetching, options } = useGetAllConfigOptions({ const { isFetching, options } = useGetAllConfigOptions(
attributeKey: type, {
searchText, attributeKey: type,
}); searchText,
},
dotMetricsEnabled,
);
const handleDebouncedSearch = useDebouncedFn((searchText): void => { const handleDebouncedSearch = useDebouncedFn((searchText): void => {
setSearchText(searchText as string); setSearchText(searchText as string);
}, 500); }, 500);

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