diff --git a/.changeset/perfect-toys-draw.md b/.changeset/perfect-toys-draw.md new file mode 100644 index 00000000..0a2e845b --- /dev/null +++ b/.changeset/perfect-toys-draw.md @@ -0,0 +1,5 @@ +--- +"@hyperdx/app": patch +--- + +fix: Show error on DBInfraPanel when correlated metric source is missing diff --git a/packages/app/src/components/DBInfraPanel.tsx b/packages/app/src/components/DBInfraPanel.tsx index 3f049d90..be434f6f 100644 --- a/packages/app/src/components/DBInfraPanel.tsx +++ b/packages/app/src/components/DBInfraPanel.tsx @@ -1,4 +1,5 @@ import { useMemo, useState } from 'react'; +import Link from 'next/link'; import { add, min, sub } from 'date-fns'; import { convertDateRangeToGranularityString, @@ -12,16 +13,23 @@ import { TSource, } from '@hyperdx/common-utils/dist/types'; import { + Alert, + Anchor, Box, Card, Group, + Modal, ScrollArea, SegmentedControl, SimpleGrid, Stack, + Text, } from '@mantine/core'; +import { useDisclosure } from '@mantine/hooks'; import { convertV1ChartConfigToV2 } from '@/ChartUtils'; +import { TableSourceForm } from '@/components/Sources/SourceForm'; +import { IS_LOCAL_MODE } from '@/config'; import { useSource } from '@/source'; import { @@ -211,11 +219,14 @@ export default ({ rowId: string | undefined | null; source: TSource; }) => { + const [editModalOpened, { open: openEditModal, close: closeEditModal }] = + useDisclosure(false); + const metricSourceId = isLogSource(source) || isTraceSource(source) ? source.metricSourceId : undefined; - const { data: metricSource } = useSource({ + const { data: metricSource, isLoading: isLoadingMetricSource } = useSource({ id: metricSourceId, kinds: [SourceKind.Metric], }); @@ -227,6 +238,39 @@ export default ({ return ( + {!metricSource && !isLoadingMetricSource && ( + <> + + + {metricSourceId + ? `The correlated metric source for "${source.name}" could not be found.` + : `Source "${source.name}" does not have a correlated metric source.`}{' '} + Infrastructure metrics can be displayed when a metric source is + configured in{' '} + {IS_LOCAL_MODE ? ( + + Source Settings + + ) : ( + + Team Settings + + )} + . + + + {IS_LOCAL_MODE && ( + + + + )} + + )} {podUid && (
{metricSource && ( diff --git a/packages/app/tests/e2e/features/correlated-metric-source.spec.ts b/packages/app/tests/e2e/features/correlated-metric-source.spec.ts new file mode 100644 index 00000000..96143c20 --- /dev/null +++ b/packages/app/tests/e2e/features/correlated-metric-source.spec.ts @@ -0,0 +1,35 @@ +import { SearchPage } from '../page-objects/SearchPage'; +import { expect, test } from '../utils/base-test'; + +test.describe('Correlated Metric Source', { tag: ['@full-stack'] }, () => { + let searchPage: SearchPage; + + test.beforeEach(async ({ page }) => { + searchPage = new SearchPage(page); + }); + + test('should show alert when no correlated metric source is configured', async ({ + page, + }) => { + // Navigate to search page + await searchPage.goto(); + + // Select the source without metricSourceId + await searchPage.selectSource('E2E K8s Logs No Metrics'); + + // Search for K8s events that have k8s.pod.uid resource attribute + await searchPage.performSearch('ResourceAttributes.k8s.pod.uid:*'); + + // Click on first row to open side panel + await searchPage.table.clickFirstRow(); + + // Click the Infrastructure tab + await searchPage.sidePanel.clickTab('infrastructure'); + + // Assert the "No correlated metric source" alert is visible + await expect(page.getByText('No correlated metric source')).toBeVisible(); + await expect( + page.getByText('does not have a correlated metric source'), + ).toBeVisible(); + }); +}); diff --git a/packages/app/tests/e2e/fixtures/e2e-fixtures.json b/packages/app/tests/e2e/fixtures/e2e-fixtures.json index 7ee876e5..d4e3f31b 100644 --- a/packages/app/tests/e2e/fixtures/e2e-fixtures.json +++ b/packages/app/tests/e2e/fixtures/e2e-fixtures.json @@ -92,6 +92,23 @@ "traceIdExpression": "TraceId", "spanIdExpression": "SpanId", "implicitColumnExpression": "Body" + }, + { + "id": "E2E K8s Logs No Metrics", + "kind": "log", + "name": "E2E K8s Logs No Metrics", + "connection": "local", + "from": { "databaseName": "default", "tableName": "e2e_otel_logs" }, + "timestampValueExpression": "TimestampTime", + "defaultTableSelectExpression": "Timestamp, ServiceName, SeverityText, Body", + "serviceNameExpression": "ServiceName", + "severityTextExpression": "SeverityText", + "eventAttributesExpression": "LogAttributes", + "resourceAttributesExpression": "ResourceAttributes", + "traceIdExpression": "TraceId", + "spanIdExpression": "SpanId", + "implicitColumnExpression": "Body", + "displayedTimestampValueExpression": "Timestamp" } ] }