Skip to content

Commit 69f0b48

Browse files
authored
design: Make service map drill-down links more obvious (#1738)
# Summary The buttons within the service map tooltips were hard to recognize as buttons/links. I've added an icon and give them a hover state. ## Before <img width="277" height="124" alt="Screenshot 2026-02-13 at 2 28 14 PM" src="https://github.com/user-attachments/assets/256b0b7d-b6eb-44e6-8a69-c0bf2b15db17" /> ## After <img width="202" height="197" alt="Screenshot 2026-02-13 at 2 27 26 PM" src="https://github.com/user-attachments/assets/27e26ff9-b644-4d14-8217-cf4e7fd53d84" />
1 parent 35494dc commit 69f0b48

File tree

3 files changed

+62
-50
lines changed

3 files changed

+62
-50
lines changed

.changeset/kind-peas-kneel.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@hyperdx/app": patch
3+
---
4+
5+
design: Make service map drill-down links more obvious

packages/app/src/components/ServiceMap/ServiceMap.module.scss

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,10 @@
66
}
77

88
.toolbar {
9-
padding: 4px 8px;
9+
padding: 4px;
1010
border-radius: 4px;
11-
background-color: #f0f0f0;
12-
border: 1px solid #ccc;
13-
color: #111;
14-
15-
.linkButton {
16-
font-size: small;
17-
}
11+
background-color: var(--color-bg-header);
12+
border: 1px solid var(--color-border);
1813
}
1914

2015
.serviceNode {
Lines changed: 54 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import { useCallback } from 'react';
12
import SqlString from 'sqlstring';
23
import { TSource } from '@hyperdx/common-utils/dist/types';
3-
import { UnstyledButton } from '@mantine/core';
4+
import { Button, Group, Stack, UnstyledButton } from '@mantine/core';
5+
import { IconSearch } from '@tabler/icons-react';
46

57
import { formatApproximateNumber, navigateToTraceSearch } from './utils';
68

@@ -21,53 +23,63 @@ export default function ServiceMapTooltip({
2123
serviceName: string;
2224
isSingleTrace?: boolean;
2325
}) {
26+
const requestText = `${isSingleTrace ? totalRequests : formatApproximateNumber(totalRequests)} request${
27+
totalRequests !== 1 ? 's' : ''
28+
}`;
29+
const errorsText = `${errorPercentage.toFixed(2)}% errors`;
30+
31+
const handleRequestsClick = useCallback(() => {
32+
navigateToTraceSearch({
33+
dateRange,
34+
source,
35+
where: SqlString.format("? = ? AND ? IN ('Server', 'Consumer')", [
36+
SqlString.raw(source.serviceNameExpression ?? 'ServiceName'),
37+
serviceName,
38+
SqlString.raw(source.spanKindExpression ?? 'SpanKind'),
39+
]),
40+
});
41+
}, [dateRange, source, serviceName]);
42+
43+
const handleErrorsClick = useCallback(() => {
44+
navigateToTraceSearch({
45+
dateRange,
46+
source,
47+
where: SqlString.format(
48+
"? = ? AND ? IN ('Server', 'Consumer') AND ? = 'Error'",
49+
[
50+
SqlString.raw(source.serviceNameExpression ?? 'ServiceName'),
51+
serviceName,
52+
SqlString.raw(source.spanKindExpression ?? 'SpanKind'),
53+
SqlString.raw(source.statusCodeExpression ?? 'StatusCode'),
54+
],
55+
),
56+
});
57+
}, [dateRange, source, serviceName]);
58+
2459
return (
25-
<div className={styles.toolbar}>
26-
<UnstyledButton
27-
onClick={() =>
28-
navigateToTraceSearch({
29-
dateRange,
30-
source,
31-
where: SqlString.format("? = ? AND ? IN ('Server', 'Consumer')", [
32-
SqlString.raw(source.serviceNameExpression ?? 'ServiceName'),
33-
serviceName,
34-
SqlString.raw(source.spanKindExpression ?? 'SpanKind'),
35-
]),
36-
})
37-
}
38-
className={styles.linkButton}
60+
<Stack className={styles.toolbar} gap={0}>
61+
<Button
62+
onClick={handleRequestsClick}
63+
variant="subtle"
64+
size="xs"
65+
color="var(--color-text)"
66+
rightSection={<IconSearch size={16} />}
3967
>
40-
{isSingleTrace ? totalRequests : formatApproximateNumber(totalRequests)}{' '}
41-
request
42-
{totalRequests !== 1 ? 's' : ''}
43-
</UnstyledButton>
68+
{requestText}
69+
</Button>
4470
{errorPercentage > 0 ? (
4571
<>
46-
{', '}
47-
<UnstyledButton
48-
onClick={() =>
49-
navigateToTraceSearch({
50-
dateRange,
51-
source,
52-
where: SqlString.format(
53-
"? = ? AND ? IN ('Server', 'Consumer') AND ? = 'Error'",
54-
[
55-
SqlString.raw(
56-
source.serviceNameExpression ?? 'ServiceName',
57-
),
58-
serviceName,
59-
SqlString.raw(source.spanKindExpression ?? 'SpanKind'),
60-
SqlString.raw(source.statusCodeExpression ?? 'StatusCode'),
61-
],
62-
),
63-
})
64-
}
65-
className={styles.linkButton}
72+
<Button
73+
onClick={handleErrorsClick}
74+
variant="subtle"
75+
size="xs"
76+
color="var(--color-text-danger)"
77+
rightSection={<IconSearch size={16} />}
6678
>
67-
{errorPercentage.toFixed(2)}% error
68-
</UnstyledButton>
79+
{errorsText}
80+
</Button>
6981
</>
7082
) : null}
71-
</div>
83+
</Stack>
7284
);
7385
}

0 commit comments

Comments
 (0)