feat: misc improvements (#824)

- add top level attributes to overview panel: HDX-1715
- add connection name to sources list
- introduce additional default aliases for otel (service, level, duration)
- fix bug with being unable to save source after deselecting correlated log source
- copy improvements
- `dev:down` npm command to tear down dev docker compose
This commit is contained in:
Mike Shi 2025-05-17 13:02:09 -07:00 committed by GitHub
parent a36c2290df
commit 5ce694401b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 71 additions and 13 deletions

View file

@ -32,6 +32,7 @@
"app:dev": "npx concurrently -k -n 'API,APP,ALERTS-TASK,COMMON-UTILS' -c 'green.bold,blue.bold,yellow.bold,magenta' 'nx run @hyperdx/api:dev' 'nx run @hyperdx/app:dev' 'nx run @hyperdx/api:dev-task check-alerts' 'nx run @hyperdx/common-utils:dev'",
"app:lint": "nx run @hyperdx/app:ci:lint",
"dev": "docker compose -f docker-compose.dev.yml up -d && yarn app:dev && docker compose -f docker-compose.dev.yml down",
"dev:down": "docker compose -f docker-compose.dev.yml down",
"lint": "npx nx run-many -t ci:lint",
"version": "make version",
"release": "npx nx run-many --target=build --projects=@hyperdx/common-utils && npx changeset tag && npx changeset publish"

View file

@ -779,7 +779,7 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
pathname.startsWith('/clickhouse'),
})}
>
Clickhouse
ClickHouse
</Link>
<Link
href={`/services`}

View file

@ -201,7 +201,11 @@ export default function AuthPage({ action }: { action: 'register' | 'login' }) {
loading={isSubmitting}
data-test-id="submit"
>
{isRegister ? 'Register' : 'Login'}
{config.IS_OSS && isRegister
? 'Create'
: isRegister
? 'Register'
: 'Login'}
</Button>
</Stack>
</Paper>

View file

@ -12,7 +12,7 @@ import { SubmitHandler, useForm } from 'react-hook-form';
import { json, jsonParseLinter } from '@codemirror/lang-json';
import { linter } from '@codemirror/lint';
import { EditorView, ViewUpdate } from '@codemirror/view';
import { WebhookService } from '@hyperdx/common-utils/dist/types';
import { SourceKind, WebhookService } from '@hyperdx/common-utils/dist/types';
import {
Alert,
Badge,
@ -198,6 +198,7 @@ function ConnectionsSection() {
}
function SourcesSection() {
const { data: connections } = useConnections();
const { data: sources } = useSources();
const [editedSourceId, setEditedSourceId] = useState<string | null>(null);
@ -216,13 +217,22 @@ function SourcesSection() {
<Flex key={s.id} justify="space-between" align="center">
<div>
<Text>{s.name}</Text>
<Text size="xxs" c="dimmed">
<Text size="xxs" c="dimmed" mt="xs">
{capitalizeFirstLetter(s.kind)}
<Text px="md" span>
<span className="bi-hdd-stack me-1" />
{connections?.find(c => c.id === s.connection)?.name}
</Text>
{s.from && (
<>
{' '}
&middot; <span className="bi-database me-1" />
{s.from.databaseName}.{s.from.tableName}
<span className="bi-database me-1" />
{s.from.databaseName}
{
s.kind === SourceKind.Metric
? ''
: '.' /** Metrics dont have table names */
}
{s.from.tableName}
</>
)}
</Text>

View file

@ -1,5 +1,6 @@
import { useCallback, useContext, useMemo } from 'react';
import { isString, pickBy } from 'lodash';
import isString from 'lodash/isString';
import pickBy from 'lodash/pickBy';
import { SourceKind, TSource } from '@hyperdx/common-utils/dist/types';
import { Accordion, Box, Divider, Flex, Text } from '@mantine/core';
@ -37,6 +38,32 @@ export function RowOverviewPanel({
return firstRow;
}, [data]);
// TODO: Use source config to select these in SQL, but we'll just
// assume OTel column names for now
const topLevelAttributeKeys = [
'ServiceName',
'SpanName',
'Duration',
'SeverityText',
'StatusCode',
'StatusMessage',
'SpanKind',
'TraceId',
'SpanId',
'ParentSpanId',
'ScopeName',
'ScopeVersion',
];
const topLevelAttributes = pickBy(firstRow, (value, key) => {
if (value === '') {
return false;
}
if (topLevelAttributeKeys.includes(key)) {
return true;
}
return false;
});
const resourceAttributes = firstRow?.__hdx_resource_attributes ?? EMPTY_OBJ;
const eventAttributes = firstRow?.__hdx_event_attributes ?? EMPTY_OBJ;
const dataAttributes =
@ -138,6 +165,7 @@ export function RowOverviewPanel({
'network',
'resourceAttributes',
'eventAttributes',
'topLevelAttributes',
]}
multiple
>
@ -181,6 +209,21 @@ export function RowOverviewPanel({
</Accordion.Item>
)}
{Object.keys(topLevelAttributes).length > 0 && (
<Accordion.Item value="topLevelAttributes">
<Accordion.Control>
<Text size="sm" c="gray.2" ps="md">
Top Level Attributes
</Text>
</Accordion.Control>
<Accordion.Panel>
<Box px="md">
<DBRowJsonViewer data={topLevelAttributes} />
</Box>
</Accordion.Panel>
</Accordion.Item>
)}
<Accordion.Item value="eventAttributes">
<Accordion.Control>
<Text size="sm" c="gray.2" ps="md">

View file

@ -35,8 +35,8 @@ export default function DBTracePanel({
focusDate,
parentSourceId,
}: {
parentSourceId?: string;
childSourceId?: string;
parentSourceId?: string | null;
childSourceId?: string | null;
traceId: string;
dateRange: [Date, Date];
focusDate: Date;

View file

@ -268,7 +268,7 @@ export async function inferTableSourceConfig({
...(isOtelLogSchema
? {
defaultTableSelectExpression:
'Timestamp, ServiceName, SeverityText, Body',
'Timestamp, ServiceName as service, SeverityText as level, Body',
serviceNameExpression: 'ServiceName',
bodyExpression: 'Body',
@ -288,7 +288,7 @@ export async function inferTableSourceConfig({
implicitColumnExpression: 'SpanName',
bodyExpression: 'SpanName',
defaultTableSelectExpression:
'Timestamp, ServiceName, StatusCode, round(Duration / 1e6), SpanName',
'Timestamp, ServiceName as service, StatusCode as level, round(Duration / 1e6) as duration, SpanName',
eventAttributesExpression: 'SpanAttributes',
serviceNameExpression: 'ServiceName',
resourceAttributesExpression: 'ResourceAttributes',

View file

@ -516,7 +516,7 @@ export const SourceSchema = z.object({
spanKindExpression: z.string().optional(),
statusCodeExpression: z.string().optional(),
statusMessageExpression: z.string().optional(),
logSourceId: z.string().optional(),
logSourceId: z.string().optional().nullable(),
// OTEL Metrics
metricTables: MetricTableSchema.optional(),