Skip to content

Commit aa331ca

Browse files
authored
feat(insights): update overview throughput/duration widgets to contain correct query (#97570)
Updates the frontend overview throughput and duration widgets (see screenshot) so that it contain the same query as the table itself. This query just tries to filter out non-frontend data. <img width="822" height="613" alt="image" src="https://github.com/user-attachments/assets/bee0e346-4365-4bb1-ad95-832e2baa8798" />
1 parent a7243f3 commit aa331ca

File tree

4 files changed

+89
-41
lines changed

4 files changed

+89
-41
lines changed

static/app/views/insights/common/components/widgets/overviewTransactionDurationChartWidget.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
import {t} from 'sentry/locale';
2-
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
32
import {InsightsLineChartWidget} from 'sentry/views/insights/common/components/insightsLineChartWidget';
43
import type {LoadableChartWidgetProps} from 'sentry/views/insights/common/components/widgets/types';
54
import {useSpanSeries} from 'sentry/views/insights/common/queries/useDiscoverSeries';
65
import {Referrer} from 'sentry/views/insights/pages/frontend/referrers';
7-
import {useTransactionNameQuery} from 'sentry/views/insights/pages/platform/shared/useTransactionNameQuery';
6+
import {useFrontendQuery} from 'sentry/views/insights/pages/frontend/useFrontendQuery';
87
import {SpanFields} from 'sentry/views/insights/types';
98

109
export default function OverviewTransactionDurationChartWidget(
1110
props: LoadableChartWidgetProps
1211
) {
13-
const {query} = useTransactionNameQuery();
14-
12+
const search = useFrontendQuery();
1513
const title = t('Duration');
16-
const search = new MutableSearch(`${SpanFields.IS_TRANSACTION}:true ${query}`);
14+
15+
search.addFilterValue(SpanFields.IS_TRANSACTION, 'true');
1716
const referrer = Referrer.TRANSACTION_DURATION_CHART;
1817

1918
const {data, isLoading, error} = useSpanSeries(

static/app/views/insights/common/components/widgets/overviewTransactionThroughputChartWidget.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
import {t} from 'sentry/locale';
2-
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
32
import {InsightsLineChartWidget} from 'sentry/views/insights/common/components/insightsLineChartWidget';
43
import type {LoadableChartWidgetProps} from 'sentry/views/insights/common/components/widgets/types';
54
import {useSpanSeries} from 'sentry/views/insights/common/queries/useDiscoverSeries';
65
import {Referrer} from 'sentry/views/insights/pages/frontend/referrers';
7-
import {useTransactionNameQuery} from 'sentry/views/insights/pages/platform/shared/useTransactionNameQuery';
6+
import {useFrontendQuery} from 'sentry/views/insights/pages/frontend/useFrontendQuery';
87
import {SpanFields, type SpanProperty} from 'sentry/views/insights/types';
98

109
export default function OverviewTransactionThroughputChartWidget(
1110
props: LoadableChartWidgetProps
1211
) {
13-
const {query} = useTransactionNameQuery();
14-
12+
const search = useFrontendQuery();
1513
const title = t('Throughput');
16-
const search = new MutableSearch(`${SpanFields.IS_TRANSACTION}:true ${query}`);
14+
15+
search.addFilterValue(SpanFields.IS_TRANSACTION, 'true');
1716
const yAxis: SpanProperty = 'epm()';
1817
const referrer = Referrer.TRANSACTION_THROUGHPUT_CHART;
1918

static/app/views/insights/pages/frontend/newFrontendOverviewPage.tsx

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ import {
3636
StackedWidgetWrapper,
3737
TripleRowWidgetWrapper,
3838
} from 'sentry/views/insights/pages/backend/backendOverviewPage';
39-
import {OVERVIEW_PAGE_ALLOWED_OPS as BACKEND_OVERVIEW_PAGE_ALLOWED_OPS} from 'sentry/views/insights/pages/backend/settings';
4039
import {
4140
FrontendOverviewTable,
4241
isAValidSort,
@@ -47,11 +46,11 @@ import type {PageSpanOps} from 'sentry/views/insights/pages/frontend/settings';
4746
import {
4847
DEFAULT_SORT,
4948
DEFAULT_SPAN_OP_SELECTION,
50-
EAP_OVERVIEW_PAGE_ALLOWED_OPS,
5149
FRONTEND_LANDING_TITLE,
5250
PAGE_SPAN_OPS,
5351
SPAN_OP_QUERY_PARAM,
5452
} from 'sentry/views/insights/pages/frontend/settings';
53+
import {useFrontendQuery} from 'sentry/views/insights/pages/frontend/useFrontendQuery';
5554
import {InsightsSpanTagProvider} from 'sentry/views/insights/pages/insightsSpanTagProvider';
5655
import {WebVitalsWidget} from 'sentry/views/insights/pages/platform/nextjs/webVitalsWidget';
5756
import {IssuesWidget} from 'sentry/views/insights/pages/platform/shared/issuesWidget';
@@ -69,6 +68,8 @@ export function NewFrontendOverviewPage() {
6968
const onboardingProject = useOnboardingProject();
7069
const navigate = useNavigate();
7170
const {selection} = usePageFilters();
71+
const search = useFrontendQuery();
72+
7273
const cursor = decodeScalar(location.query?.[QueryParameterNames.PAGES_CURSOR]);
7374
const spanOp: PageSpanOps = getSpanOpFromQuery(
7475
decodeScalar(location.query?.[SPAN_OP_QUERY_PARAM])
@@ -85,34 +86,6 @@ export function NewFrontendOverviewPage() {
8586
otherProjects: selectedOtherProjects,
8687
} = categorizeProjects(getSelectedProjectList(selection.projects, projects));
8788

88-
const existingQuery = new MutableSearch(searchBarQuery);
89-
90-
// TODO - this query is getting complicated, once were on EAP, we should consider moving this to the backend
91-
existingQuery.addOp('(');
92-
93-
if (spanOp === 'all') {
94-
const spanOps = [...EAP_OVERVIEW_PAGE_ALLOWED_OPS, 'pageload', 'navigation'];
95-
existingQuery.addFilterValue('span.op', `[${spanOps.join(',')}]`);
96-
// add disjunction filter creates a very long query as it seperates conditions with OR, project ids are numeric with no spaces, so we can use a comma seperated list
97-
if (selectedFrontendProjects.length > 0) {
98-
existingQuery.addOp('OR');
99-
existingQuery.addFilterValue(
100-
'project.id',
101-
`[${selectedFrontendProjects.map(({id}) => id).join(',')}]`
102-
);
103-
}
104-
} else if (spanOp === 'pageload') {
105-
const spanOps = [...EAP_OVERVIEW_PAGE_ALLOWED_OPS, 'pageload'];
106-
existingQuery.addFilterValue('span.op', `[${spanOps.join(',')}]`);
107-
} else if (spanOp === 'navigation') {
108-
// navigation span ops doesn't work for web vitals, so we do need to filter for web vital spans
109-
existingQuery.addFilterValue('span.op', 'navigation');
110-
}
111-
112-
existingQuery.addOp(')');
113-
114-
existingQuery.addFilterValues('!span.op', BACKEND_OVERVIEW_PAGE_ALLOWED_OPS);
115-
11689
const showOnboarding = onboardingProject !== undefined;
11790

11891
const getFreeTextFromQuery = (query: string) => {
@@ -155,7 +128,7 @@ export function NewFrontendOverviewPage() {
155128

156129
const response = useSpans(
157130
{
158-
search: existingQuery,
131+
search,
159132
sorts,
160133
cursor,
161134
useQueryOptions: {additonalQueryKey: STARRED_SEGMENT_TABLE_QUERY_KEY},
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import {getSelectedProjectList} from 'sentry/utils/project/useSelectedProjectsHaveField';
2+
import {decodeScalar} from 'sentry/utils/queryString';
3+
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
4+
import useLocationQuery from 'sentry/utils/url/useLocationQuery';
5+
import {useLocation} from 'sentry/utils/useLocation';
6+
import usePageFilters from 'sentry/utils/usePageFilters';
7+
import useProjects from 'sentry/utils/useProjects';
8+
import {OVERVIEW_PAGE_ALLOWED_OPS as BACKEND_OVERVIEW_PAGE_ALLOWED_OPS} from 'sentry/views/insights/pages/backend/settings';
9+
import {
10+
DEFAULT_SPAN_OP_SELECTION,
11+
EAP_OVERVIEW_PAGE_ALLOWED_OPS,
12+
PAGE_SPAN_OPS,
13+
type PageSpanOps,
14+
SPAN_OP_QUERY_PARAM,
15+
} from 'sentry/views/insights/pages/frontend/settings';
16+
import {categorizeProjects} from 'sentry/views/insights/pages/utils';
17+
18+
export function useFrontendQuery() {
19+
const {projects} = useProjects();
20+
const {selection} = usePageFilters();
21+
const location = useLocation();
22+
23+
const {query: searchBarQuery} = useLocationQuery({
24+
fields: {
25+
query: decodeScalar,
26+
},
27+
});
28+
29+
const spanOp: PageSpanOps = getSpanOpFromQuery(
30+
decodeScalar(location.query?.[SPAN_OP_QUERY_PARAM])
31+
);
32+
33+
const query = new MutableSearch(searchBarQuery);
34+
35+
const {frontendProjects} = categorizeProjects(
36+
getSelectedProjectList(selection.projects, projects)
37+
);
38+
39+
// TODO - this query is getting complicated, once were on EAP, we should consider moving this to the backend
40+
query.addOp('(');
41+
42+
if (spanOp === 'all') {
43+
const spanOps = [...EAP_OVERVIEW_PAGE_ALLOWED_OPS, 'pageload', 'navigation'];
44+
query.addFilterValue('span.op', `[${spanOps.join(',')}]`);
45+
// add disjunction filter creates a very long query as it seperates conditions with OR, project ids are numeric with no spaces, so we can use a comma seperated list
46+
if (frontendProjects.length > 0) {
47+
query.addOp('OR');
48+
query.addFilterValue(
49+
'project.id',
50+
`[${frontendProjects.map(({id}) => id).join(',')}]`
51+
);
52+
}
53+
} else if (spanOp === 'pageload') {
54+
const spanOps = [...EAP_OVERVIEW_PAGE_ALLOWED_OPS, 'pageload'];
55+
query.addFilterValue('span.op', `[${spanOps.join(',')}]`);
56+
} else if (spanOp === 'navigation') {
57+
// navigation span ops doesn't work for web vitals, so we do need to filter for web vital spans
58+
query.addFilterValue('span.op', 'navigation');
59+
}
60+
61+
query.addOp(')');
62+
63+
query.addFilterValues('!span.op', BACKEND_OVERVIEW_PAGE_ALLOWED_OPS);
64+
65+
return query;
66+
}
67+
68+
const isPageSpanOp = (op?: string): op is PageSpanOps => {
69+
return PAGE_SPAN_OPS.includes(op as PageSpanOps);
70+
};
71+
72+
const getSpanOpFromQuery = (op?: string): PageSpanOps => {
73+
if (isPageSpanOp(op)) {
74+
return op;
75+
}
76+
return DEFAULT_SPAN_OP_SELECTION;
77+
};

0 commit comments

Comments
 (0)