From b66af786e6e5434e0219cccfc0e83518b411529d Mon Sep 17 00:00:00 2001
From: Amlan Kumar Nandy <45410599+amlannandy@users.noreply.github.com>
Date: Mon, 5 May 2025 12:58:56 +0700
Subject: [PATCH] fix: description tooltip coming up twice in metrics list
table (#7823)
---
.../Summary/__tests__/utils.test.tsx | 188 ++++++++++++++++++
.../MetricsExplorer/Summary/utils.tsx | 8 +-
2 files changed, 192 insertions(+), 4 deletions(-)
create mode 100644 frontend/src/container/MetricsExplorer/Summary/__tests__/utils.test.tsx
diff --git a/frontend/src/container/MetricsExplorer/Summary/__tests__/utils.test.tsx b/frontend/src/container/MetricsExplorer/Summary/__tests__/utils.test.tsx
new file mode 100644
index 0000000000..da63bd44a6
--- /dev/null
+++ b/frontend/src/container/MetricsExplorer/Summary/__tests__/utils.test.tsx
@@ -0,0 +1,188 @@
+import { Color } from '@signozhq/design-tokens';
+import { render } from '@testing-library/react';
+import { MetricType } from 'api/metricsExplorer/getMetricsList';
+
+import { TreemapViewType } from '../types';
+import {
+ formatDataForMetricsTable,
+ metricsTableColumns,
+ MetricTypeRenderer,
+} from '../utils';
+
+describe('metricsTableColumns', () => {
+ it('should have correct column definitions', () => {
+ expect(metricsTableColumns).toHaveLength(6);
+
+ // Metric Name column
+ expect(metricsTableColumns[0].dataIndex).toBe('metric_name');
+ expect(metricsTableColumns[0].width).toBe(400);
+ expect(metricsTableColumns[0].sorter).toBe(false);
+
+ // Description column
+ expect(metricsTableColumns[1].dataIndex).toBe('description');
+ expect(metricsTableColumns[1].width).toBe(400);
+
+ // Type column
+ expect(metricsTableColumns[2].dataIndex).toBe('metric_type');
+ expect(metricsTableColumns[2].width).toBe(150);
+ expect(metricsTableColumns[2].sorter).toBe(false);
+
+ // Unit column
+ expect(metricsTableColumns[3].dataIndex).toBe('unit');
+ expect(metricsTableColumns[3].width).toBe(150);
+
+ // Samples column
+ expect(metricsTableColumns[4].dataIndex).toBe(TreemapViewType.SAMPLES);
+ expect(metricsTableColumns[4].width).toBe(150);
+ expect(metricsTableColumns[4].sorter).toBe(true);
+
+ // Time Series column
+ expect(metricsTableColumns[5].dataIndex).toBe(TreemapViewType.TIMESERIES);
+ expect(metricsTableColumns[5].width).toBe(150);
+ expect(metricsTableColumns[5].sorter).toBe(true);
+ });
+
+ describe('MetricTypeRenderer', () => {
+ it('should render correct icon and color for each metric type', () => {
+ const types = [
+ {
+ type: MetricType.SUM,
+ color: Color.BG_ROBIN_500,
+ },
+ {
+ type: MetricType.GAUGE,
+ color: Color.BG_SAKURA_500,
+ },
+ {
+ type: MetricType.HISTOGRAM,
+ color: Color.BG_SIENNA_500,
+ },
+ {
+ type: MetricType.SUMMARY,
+ color: Color.BG_FOREST_500,
+ },
+ {
+ type: MetricType.EXPONENTIAL_HISTOGRAM,
+ color: Color.BG_AQUA_500,
+ },
+ ];
+
+ types.forEach(({ type, color }) => {
+ const { container } = render();
+ const rendererDiv = container.firstChild as HTMLElement;
+
+ expect(rendererDiv).toHaveStyle({
+ backgroundColor: `${color}33`,
+ border: `1px solid ${color}`,
+ color,
+ });
+ });
+ });
+
+ it('should return empty icon and color for unknown metric type', () => {
+ const { container } = render(
+ ,
+ );
+ const rendererDiv = container.firstChild as HTMLElement;
+
+ expect(rendererDiv.querySelector('svg')).toBeNull();
+ });
+ });
+});
+
+describe('formatDataForMetricsTable', () => {
+ it('should format metrics data correctly', () => {
+ const mockData = [
+ {
+ metric_name: 'test_metric',
+ description: 'Test description',
+ type: MetricType.GAUGE,
+ unit: 'bytes',
+ [TreemapViewType.SAMPLES]: 1000,
+ [TreemapViewType.TIMESERIES]: 2000,
+ lastReceived: '2023-01-01T00:00:00Z',
+ },
+ ];
+
+ const result = formatDataForMetricsTable(mockData);
+
+ expect(result).toHaveLength(1);
+ expect(result[0].key).toBe('test_metric');
+
+ // Verify metric name rendering
+ const metricNameElement = result[0].metric_name as JSX.Element;
+ const { container: metricNameWrapper } = render(metricNameElement);
+ expect(metricNameWrapper.textContent).toBe('test_metric');
+
+ // Verify description rendering
+ const descriptionElement = result[0].description as JSX.Element;
+ const { container: descriptionWrapper } = render(descriptionElement);
+ expect(descriptionWrapper.textContent).toBe('Test description');
+ expect(descriptionWrapper.querySelector('.description-tooltip')).toBeTruthy();
+
+ // Verify metric type rendering
+ const metricTypeElement = result[0].metric_type as JSX.Element;
+ const { container: metricTypeWrapper } = render(metricTypeElement);
+ expect(metricTypeWrapper.querySelector('.metric-type-renderer')).toBeTruthy();
+
+ // Verify unit rendering
+ const unitElement = result[0].unit as JSX.Element;
+ const { container: unitWrapper } = render(unitElement);
+ expect(unitWrapper.textContent).toBe('bytes');
+
+ // Verify samples rendering
+ const samplesElement = result[0][TreemapViewType.SAMPLES] as JSX.Element;
+ const { container: samplesWrapper } = render(samplesElement);
+ expect(samplesWrapper.textContent).toBe('1K+');
+
+ // Verify timeseries rendering
+ const timeseriesElement = result[0][
+ TreemapViewType.TIMESERIES
+ ] as JSX.Element;
+ const { container: timeseriesWrapper } = render(timeseriesElement);
+ expect(timeseriesWrapper.textContent).toBe('2K+');
+ });
+
+ it('should handle empty/null values', () => {
+ const mockData = [
+ {
+ metric_name: 'test-metric',
+ description: 'test-description',
+ type: MetricType.GAUGE,
+ unit: 'ms',
+ [TreemapViewType.SAMPLES]: 0,
+ [TreemapViewType.TIMESERIES]: 0,
+ lastReceived: '2023-01-01T00:00:00Z',
+ },
+ ];
+
+ const result = formatDataForMetricsTable(mockData);
+
+ // Verify empty metric name rendering
+ const metricNameElement = result[0].metric_name as JSX.Element;
+ const { container: metricNameWrapper } = render(metricNameElement);
+ expect(metricNameWrapper.textContent).toBe('test-metric');
+
+ // Verify null description rendering
+ const descriptionElement = result[0].description as JSX.Element;
+ const { container: descriptionWrapper } = render(descriptionElement);
+ expect(descriptionWrapper.textContent).toBe('test-description');
+
+ // Verify null unit rendering
+ const unitElement = result[0].unit as JSX.Element;
+ const { container: unitWrapper } = render(unitElement);
+ expect(unitWrapper.textContent).toBe('ms');
+
+ // Verify zero samples rendering
+ const samplesElement = result[0][TreemapViewType.SAMPLES] as JSX.Element;
+ const { container: samplesWrapper } = render(samplesElement);
+ expect(samplesWrapper.textContent).toBe('-');
+
+ // Verify zero timeseries rendering
+ const timeseriesElement = result[0][
+ TreemapViewType.TIMESERIES
+ ] as JSX.Element;
+ const { container: timeseriesWrapper } = render(timeseriesElement);
+ expect(timeseriesWrapper.textContent).toBe('-');
+ });
+});
diff --git a/frontend/src/container/MetricsExplorer/Summary/utils.tsx b/frontend/src/container/MetricsExplorer/Summary/utils.tsx
index 5e56291e57..f558bd535e 100644
--- a/frontend/src/container/MetricsExplorer/Summary/utils.tsx
+++ b/frontend/src/container/MetricsExplorer/Summary/utils.tsx
@@ -44,9 +44,7 @@ export const metricsTableColumns: ColumnType[] = [
dataIndex: 'description',
width: 400,
render: (value: string): React.ReactNode => (
-
- {value}
-
+ {value}
),
},
{
@@ -186,7 +184,9 @@ export const formatDataForMetricsTable = (
),
description: (
- {metric.description}
+
+ {metric.description}
+
),
metric_type: ,