Skip to content

Commit 7bb7a87

Browse files
authored
feat: Add filter for root spans (#1341)
Closes HDX-2772 This PR adds a filter that allows for quickly viewing just root spans from a Trace source. Notes: - The state of this filter is persisted in the URL Query Params - This filter is not persisted in a saved search to match the behavior of other filters, which are not persisted in saved searches. <img width="1237" height="833" alt="Screenshot 2025-11-12 at 3 56 18 PM" src="https://github.com/user-attachments/assets/9e6b461d-f201-4521-b546-15f986c7ec5b" /> <img width="1252" height="693" alt="Screenshot 2025-11-12 at 3 56 32 PM" src="https://github.com/user-attachments/assets/0aa02818-93ba-4f57-96fd-58c46aac3d9d" />
1 parent a75ce3b commit 7bb7a87

File tree

2 files changed

+57
-2
lines changed

2 files changed

+57
-2
lines changed

.changeset/silent-ducks-crash.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+
feat: Add filter for root spans

packages/app/src/components/DBSearchPageFilters.tsx

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ import {
1313
tcFromChartConfig,
1414
tcFromSource,
1515
} from '@hyperdx/common-utils/dist/core/metadata';
16-
import { ChartConfigWithDateRange } from '@hyperdx/common-utils/dist/types';
16+
import {
17+
ChartConfigWithDateRange,
18+
SourceKind,
19+
} from '@hyperdx/common-utils/dist/types';
1720
import {
1821
Accordion,
1922
ActionIcon,
@@ -186,7 +189,7 @@ export const FilterCheckbox = ({
186189
flex={1}
187190
title={label}
188191
>
189-
{label}
192+
{label || <span className="fst-italic">(empty)</span>}
190193
</Text>
191194
{percentage != null && (
192195
<FilterPercentage
@@ -907,6 +910,30 @@ const DBSearchPageFiltersComponent = ({
907910
[filterState],
908911
);
909912

913+
const setRootSpansOnly = useCallback(
914+
(rootSpansOnly: boolean) => {
915+
if (!source?.parentSpanIdExpression) return;
916+
917+
if (rootSpansOnly) {
918+
setFilterValue(source.parentSpanIdExpression, '', 'only');
919+
} else {
920+
clearFilter(source.parentSpanIdExpression);
921+
}
922+
},
923+
[setFilterValue, clearFilter, source],
924+
);
925+
926+
const isRootSpansOnly = useMemo(() => {
927+
if (!source?.parentSpanIdExpression || source.kind !== SourceKind.Trace)
928+
return false;
929+
930+
const parentSpanIdFilter = filterState?.[source?.parentSpanIdExpression];
931+
return (
932+
parentSpanIdFilter?.included.size === 1 &&
933+
parentSpanIdFilter?.included.has('')
934+
);
935+
}, [filterState, source]);
936+
910937
return (
911938
<Box className={classes.filtersPanel} style={{ width: `${size}%` }}>
912939
<div className={resizeStyles.resizeHandle} onMouseDown={startResize} />
@@ -996,6 +1023,29 @@ const DBSearchPageFiltersComponent = ({
9961023
/>
9971024
)}
9981025

1026+
{source?.kind === SourceKind.Trace &&
1027+
source.parentSpanIdExpression && (
1028+
<Checkbox
1029+
size={13 as any}
1030+
checked={isRootSpansOnly}
1031+
ms="6px"
1032+
label={
1033+
<Tooltip
1034+
openDelay={200}
1035+
color="gray"
1036+
position="right"
1037+
withArrow
1038+
label="Only show root spans (spans with no parent span)."
1039+
>
1040+
<Text size="xs" c="gray.3" mt="-1px">
1041+
<i className="bi bi-diagram-3"></i> Root Spans Only
1042+
</Text>
1043+
</Tooltip>
1044+
}
1045+
onChange={event => setRootSpansOnly(event.target.checked)}
1046+
/>
1047+
)}
1048+
9991049
{isLoading || isFacetsLoading ? (
10001050
<Flex align="center" justify="center">
10011051
<Loader size="xs" color="gray" />

0 commit comments

Comments
 (0)