Skip to content

Commit 17d074d

Browse files
authored
ref(insights): Refactor Resource Summary + Landing charts into separate modules (#89612)
Part of #88560
1 parent afa1a33 commit 17d074d

11 files changed

+280
-175
lines changed

static/app/views/insights/browser/resources/components/charts/resourceLandingPageCharts.tsx

Lines changed: 5 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,23 @@
11
import styled from '@emotion/styled';
22

33
import {space} from 'sentry/styles/space';
4-
import {EMPTY_OPTION_VALUE, MutableSearch} from 'sentry/utils/tokenizeSearch';
5-
import {InsightsLineChartWidget} from 'sentry/views/insights/common/components/insightsLineChartWidget';
6-
import {useSpanMetricsSeries} from 'sentry/views/insights/common/queries/useDiscoverSeries';
7-
import type {ModuleFilters} from 'sentry/views/insights/common/views/spans/types';
8-
import {
9-
getDurationChartTitle,
10-
getThroughputChartTitle,
11-
} from 'sentry/views/insights/common/views/spans/types';
12-
import {SpanMetricsField} from 'sentry/views/insights/types';
13-
14-
const {SPAN_SELF_TIME, NORMALIZED_DESCRIPTION, SPAN_DOMAIN} = SpanMetricsField;
15-
16-
type Props = {
17-
appliedFilters: ModuleFilters;
18-
extraQuery?: string[];
19-
};
20-
21-
export function ResourceLandingPageCharts({appliedFilters, extraQuery}: Props) {
22-
let query: string = buildDiscoverQueryConditions(appliedFilters);
23-
24-
if (extraQuery) {
25-
query += ` ${extraQuery.join(' ')}`;
26-
}
27-
28-
const {data, isPending, error} = useSpanMetricsSeries(
29-
{
30-
search: new MutableSearch(query),
31-
yAxis: ['epm()', `avg(${SPAN_SELF_TIME})`],
32-
transformAliasToInputFormat: true,
33-
},
34-
'api.starfish.span-time-charts'
35-
);
4+
import {ResourceLandingDurationChartWidget} from 'sentry/views/insights/common/components/widgets/resourceLandingDurationChartWidget';
5+
import {ResourceLandingThroughputChartWidget} from 'sentry/views/insights/common/components/widgets/resourceLandingThroughputChartWidget';
366

7+
export function ResourceLandingPageCharts() {
378
return (
389
<ChartsContainer>
3910
<ChartsContainerItem>
40-
<InsightsLineChartWidget
41-
title={getThroughputChartTitle('resource')}
42-
series={[data['epm()']]}
43-
isLoading={isPending}
44-
error={error}
45-
/>
11+
<ResourceLandingThroughputChartWidget />
4612
</ChartsContainerItem>
4713

4814
<ChartsContainerItem>
49-
<InsightsLineChartWidget
50-
title={getDurationChartTitle('resource')}
51-
series={[data[`avg(${SPAN_SELF_TIME})`]]}
52-
isLoading={isPending}
53-
error={error}
54-
/>
15+
<ResourceLandingDurationChartWidget />
5516
</ChartsContainerItem>
5617
</ChartsContainer>
5718
);
5819
}
5920

60-
const SPAN_FILTER_KEYS = ['span_operation', SPAN_DOMAIN, 'action'];
61-
62-
const buildDiscoverQueryConditions = (appliedFilters: ModuleFilters) => {
63-
const result = Object.keys(appliedFilters)
64-
.filter(key => SPAN_FILTER_KEYS.includes(key))
65-
// @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
66-
.filter(key => Boolean(appliedFilters[key]))
67-
.map(key => {
68-
// @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
69-
const value = appliedFilters[key];
70-
if (key === SPAN_DOMAIN && value === EMPTY_OPTION_VALUE) {
71-
return [`!has:${SPAN_DOMAIN}`];
72-
}
73-
return `${key}:${value}`;
74-
});
75-
76-
result.push(`has:${NORMALIZED_DESCRIPTION}`);
77-
78-
return result.join(' ');
79-
};
80-
8121
const ChartsContainer = styled('div')`
8222
display: flex;
8323
flex-direction: row;

static/app/views/insights/browser/resources/components/charts/resourceSummaryCharts.tsx

Lines changed: 7 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,23 @@
11
import {Fragment} from 'react';
22

3-
import {t} from 'sentry/locale';
4-
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
5-
import {Referrer} from 'sentry/views/insights/browser/resources/referrer';
6-
import {DATA_TYPE, FIELD_ALIASES} from 'sentry/views/insights/browser/resources/settings';
7-
import {useResourceModuleFilters} from 'sentry/views/insights/browser/resources/utils/useResourceFilters';
8-
import {InsightsLineChartWidget} from 'sentry/views/insights/common/components/insightsLineChartWidget';
93
import * as ModuleLayout from 'sentry/views/insights/common/components/moduleLayout';
10-
import {useSpanMetricsSeries} from 'sentry/views/insights/common/queries/useDiscoverSeries';
11-
import {
12-
getDurationChartTitle,
13-
getThroughputChartTitle,
14-
} from 'sentry/views/insights/common/views/spans/types';
15-
import {SpanMetricsField} from 'sentry/views/insights/types';
16-
17-
const {
18-
SPAN_SELF_TIME,
19-
HTTP_RESPONSE_CONTENT_LENGTH,
20-
HTTP_DECODED_RESPONSE_CONTENT_LENGTH,
21-
HTTP_RESPONSE_TRANSFER_SIZE,
22-
RESOURCE_RENDER_BLOCKING_STATUS,
23-
} = SpanMetricsField;
24-
25-
function ResourceSummaryCharts(props: {groupId: string}) {
26-
const filters = useResourceModuleFilters();
27-
28-
const mutableSearch = MutableSearch.fromQueryObject({
29-
'span.group': props.groupId,
30-
...(filters[RESOURCE_RENDER_BLOCKING_STATUS]
31-
? {
32-
[RESOURCE_RENDER_BLOCKING_STATUS]: filters[RESOURCE_RENDER_BLOCKING_STATUS],
33-
}
34-
: {}),
35-
...(filters[SpanMetricsField.USER_GEO_SUBREGION]
36-
? {
37-
[SpanMetricsField.USER_GEO_SUBREGION]: `[${filters[SpanMetricsField.USER_GEO_SUBREGION].join(',')}]`,
38-
}
39-
: {}),
40-
});
41-
42-
const {
43-
data: spanMetricsSeriesData,
44-
isPending: areSpanMetricsSeriesLoading,
45-
error: spanMetricsSeriesError,
46-
} = useSpanMetricsSeries(
47-
{
48-
search: mutableSearch,
49-
yAxis: [
50-
`epm()`,
51-
`avg(${SPAN_SELF_TIME})`,
52-
`avg(${HTTP_RESPONSE_CONTENT_LENGTH})`,
53-
`avg(${HTTP_DECODED_RESPONSE_CONTENT_LENGTH})`,
54-
`avg(${HTTP_RESPONSE_TRANSFER_SIZE})`,
55-
],
56-
enabled: Boolean(props.groupId),
57-
transformAliasToInputFormat: true,
58-
},
59-
Referrer.RESOURCE_SUMMARY_CHARTS
60-
);
61-
62-
if (spanMetricsSeriesData) {
63-
spanMetricsSeriesData[`avg(${HTTP_RESPONSE_TRANSFER_SIZE})`].lineStyle = {
64-
type: 'dashed',
65-
};
66-
spanMetricsSeriesData[`avg(${HTTP_DECODED_RESPONSE_CONTENT_LENGTH})`].lineStyle = {
67-
type: 'dashed',
68-
};
69-
}
4+
import {ResourceSummaryAverageSizeChartWidget} from 'sentry/views/insights/common/components/widgets/resourceSummaryAverageSizeChartWidget';
5+
import {ResourceSummaryDurationChartWidget} from 'sentry/views/insights/common/components/widgets/resourceSummaryDurationChartWidget';
6+
import {ResourceSummaryThroughputChartWidget} from 'sentry/views/insights/common/components/widgets/resourceSummaryThroughputChartWidget';
707

8+
function ResourceSummaryCharts() {
719
return (
7210
<Fragment>
7311
<ModuleLayout.Third>
74-
<InsightsLineChartWidget
75-
title={getThroughputChartTitle('resource')}
76-
series={[spanMetricsSeriesData?.[`epm()`]]}
77-
isLoading={areSpanMetricsSeriesLoading}
78-
error={spanMetricsSeriesError}
79-
/>
12+
<ResourceSummaryThroughputChartWidget />
8013
</ModuleLayout.Third>
8114

8215
<ModuleLayout.Third>
83-
<InsightsLineChartWidget
84-
title={getDurationChartTitle('resource')}
85-
series={[spanMetricsSeriesData?.[`avg(${SPAN_SELF_TIME})`]]}
86-
isLoading={areSpanMetricsSeriesLoading}
87-
error={spanMetricsSeriesError}
88-
/>
16+
<ResourceSummaryDurationChartWidget />
8917
</ModuleLayout.Third>
9018

9119
<ModuleLayout.Third>
92-
<InsightsLineChartWidget
93-
title={t('Average %s Size', DATA_TYPE)}
94-
series={[
95-
spanMetricsSeriesData?.[`avg(${HTTP_DECODED_RESPONSE_CONTENT_LENGTH})`],
96-
spanMetricsSeriesData?.[`avg(${HTTP_RESPONSE_TRANSFER_SIZE})`],
97-
spanMetricsSeriesData?.[`avg(${HTTP_RESPONSE_CONTENT_LENGTH})`],
98-
]}
99-
aliases={FIELD_ALIASES}
100-
isLoading={areSpanMetricsSeriesLoading}
101-
error={spanMetricsSeriesError}
102-
/>
20+
<ResourceSummaryAverageSizeChartWidget />
10321
</ModuleLayout.Third>
10422
</Fragment>
10523
);

static/app/views/insights/browser/resources/components/resourceView.tsx

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import {trackAnalytics} from 'sentry/utils/analytics';
88
import {useLocation} from 'sentry/utils/useLocation';
99
import {useNavigate} from 'sentry/utils/useNavigate';
1010
import useOrganization from 'sentry/utils/useOrganization';
11-
import {getResourceTypeFilter} from 'sentry/views/insights/browser/common/queries/useResourcesQuery';
1211
import RenderBlockingSelector from 'sentry/views/insights/browser/resources/components/renderBlockingSelector';
1312
import ResourceTable from 'sentry/views/insights/browser/resources/components/tables/resourceTable';
1413
import {
@@ -24,16 +23,13 @@ import {
2423
import {useResourceSort} from 'sentry/views/insights/browser/resources/utils/useResourceSort';
2524
import {QueryParameterNames} from 'sentry/views/insights/common/views/queryParameters';
2625
import {TransactionSelector} from 'sentry/views/insights/common/views/spans/selectors/transactionSelector';
27-
import type {ModuleFilters} from 'sentry/views/insights/common/views/spans/types';
2826

2927
import {ResourceLandingPageCharts} from './charts/resourceLandingPageCharts';
3028

3129
const {
3230
SPAN_OP: RESOURCE_TYPE,
33-
SPAN_DOMAIN,
3431
TRANSACTION,
3532
RESOURCE_RENDER_BLOCKING_STATUS,
36-
USER_GEO_SUBREGION,
3733
} = BrowserStarfishFields;
3834

3935
type Option = {
@@ -45,25 +41,10 @@ function ResourceView() {
4541
const filters = useResourceModuleFilters();
4642
const sort = useResourceSort();
4743

48-
const spanTimeChartsFilters: ModuleFilters = {
49-
'span.op': `[${DEFAULT_RESOURCE_TYPES.join(',')}]`,
50-
...(filters[SPAN_DOMAIN] ? {[SPAN_DOMAIN]: filters[SPAN_DOMAIN]} : {}),
51-
};
52-
53-
const extraQuery = [
54-
...getResourceTypeFilter(undefined, DEFAULT_RESOURCE_TYPES),
55-
...(filters[USER_GEO_SUBREGION]
56-
? [`user.geo.subregion:[${filters[USER_GEO_SUBREGION].join(',')}]`]
57-
: []),
58-
];
59-
6044
return (
6145
<Fragment>
6246
<SpanTimeChartsContainer>
63-
<ResourceLandingPageCharts
64-
appliedFilters={spanTimeChartsFilters}
65-
extraQuery={extraQuery}
66-
/>
47+
<ResourceLandingPageCharts />
6748
</SpanTimeChartsContainer>
6849

6950
<DropdownContainer>

static/app/views/insights/browser/resources/views/resourceSummaryPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ function ResourceSummary() {
155155
</ModuleLayout.Full>
156156
)}
157157

158-
<ResourceSummaryCharts groupId={groupId!} />
158+
<ResourceSummaryCharts />
159159

160160
<ModuleLayout.Full>
161161
<ResourceSummaryTable />
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import type {PageFilters} from 'sentry/types/core';
2+
import {EMPTY_OPTION_VALUE, MutableSearch} from 'sentry/utils/tokenizeSearch';
3+
import {getResourceTypeFilter} from 'sentry/views/insights/browser/common/queries/useResourcesQuery';
4+
import {DEFAULT_RESOURCE_TYPES} from 'sentry/views/insights/browser/resources/settings';
5+
import {useResourceModuleFilters} from 'sentry/views/insights/browser/resources/utils/useResourceFilters';
6+
import {useSpanMetricsSeries} from 'sentry/views/insights/common/queries/useDiscoverSeries';
7+
import type {ModuleFilters} from 'sentry/views/insights/common/views/spans/types';
8+
import {SpanMetricsField} from 'sentry/views/insights/types';
9+
10+
const {NORMALIZED_DESCRIPTION, SPAN_DOMAIN, SPAN_SELF_TIME, USER_GEO_SUBREGION} =
11+
SpanMetricsField;
12+
13+
const SPAN_FILTER_KEYS = ['span_operation', SPAN_DOMAIN, 'action'];
14+
15+
const buildDiscoverQueryConditions = (appliedFilters: ModuleFilters) => {
16+
const result = Object.keys(appliedFilters)
17+
.filter(key => SPAN_FILTER_KEYS.includes(key))
18+
// @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
19+
.filter(key => Boolean(appliedFilters[key]))
20+
.map(key => {
21+
// @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
22+
const value = appliedFilters[key];
23+
if (key === SPAN_DOMAIN && value === EMPTY_OPTION_VALUE) {
24+
return [`!has:${SPAN_DOMAIN}`];
25+
}
26+
return `${key}:${value}`;
27+
});
28+
29+
result.push(`has:${NORMALIZED_DESCRIPTION}`);
30+
31+
return result.join(' ');
32+
};
33+
34+
interface Props {
35+
pageFilters?: PageFilters;
36+
}
37+
38+
export function useResourceLandingSeries(props: Props = {}) {
39+
const filters = useResourceModuleFilters();
40+
41+
const spanTimeChartsFilters: ModuleFilters = {
42+
'span.op': `[${DEFAULT_RESOURCE_TYPES.join(',')}]`,
43+
...(filters[SPAN_DOMAIN] ? {[SPAN_DOMAIN]: filters[SPAN_DOMAIN]} : {}),
44+
};
45+
46+
const extraQuery = [
47+
...getResourceTypeFilter(undefined, DEFAULT_RESOURCE_TYPES),
48+
...(filters[USER_GEO_SUBREGION]
49+
? [`user.geo.subregion:[${filters[USER_GEO_SUBREGION].join(',')}]`]
50+
: []),
51+
];
52+
53+
let query: string = buildDiscoverQueryConditions(spanTimeChartsFilters);
54+
55+
if (extraQuery.length) {
56+
query += ` ${extraQuery.join(' ')}`;
57+
}
58+
59+
return useSpanMetricsSeries(
60+
{
61+
search: new MutableSearch(query),
62+
yAxis: ['epm()', `avg(${SPAN_SELF_TIME})`],
63+
transformAliasToInputFormat: true,
64+
},
65+
'api.starfish.span-time-charts',
66+
props.pageFilters
67+
);
68+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import type {PageFilters} from 'sentry/types/core';
2+
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
3+
import {Referrer} from 'sentry/views/insights/browser/resources/referrer';
4+
import {useResourceModuleFilters} from 'sentry/views/insights/browser/resources/utils/useResourceFilters';
5+
import {useSpanMetricsSeries} from 'sentry/views/insights/common/queries/useDiscoverSeries';
6+
import {SpanMetricsField} from 'sentry/views/insights/types';
7+
8+
const {
9+
SPAN_SELF_TIME,
10+
HTTP_RESPONSE_CONTENT_LENGTH,
11+
HTTP_DECODED_RESPONSE_CONTENT_LENGTH,
12+
HTTP_RESPONSE_TRANSFER_SIZE,
13+
RESOURCE_RENDER_BLOCKING_STATUS,
14+
} = SpanMetricsField;
15+
16+
interface Props {
17+
groupId?: string;
18+
pageFilters?: PageFilters;
19+
}
20+
21+
export function useResourceSummarySeries({pageFilters, groupId}: Props = {}) {
22+
const filters = useResourceModuleFilters();
23+
24+
const mutableSearch = MutableSearch.fromQueryObject({
25+
'span.group': groupId,
26+
...(filters[RESOURCE_RENDER_BLOCKING_STATUS]
27+
? {
28+
[RESOURCE_RENDER_BLOCKING_STATUS]: filters[RESOURCE_RENDER_BLOCKING_STATUS],
29+
}
30+
: {}),
31+
...(filters[SpanMetricsField.USER_GEO_SUBREGION]
32+
? {
33+
[SpanMetricsField.USER_GEO_SUBREGION]: `[${filters[SpanMetricsField.USER_GEO_SUBREGION].join(',')}]`,
34+
}
35+
: {}),
36+
});
37+
38+
return useSpanMetricsSeries(
39+
{
40+
search: mutableSearch,
41+
yAxis: [
42+
`epm()`,
43+
`avg(${SPAN_SELF_TIME})`,
44+
`avg(${HTTP_RESPONSE_CONTENT_LENGTH})`,
45+
`avg(${HTTP_DECODED_RESPONSE_CONTENT_LENGTH})`,
46+
`avg(${HTTP_RESPONSE_TRANSFER_SIZE})`,
47+
],
48+
enabled: Boolean(groupId),
49+
transformAliasToInputFormat: true,
50+
},
51+
Referrer.RESOURCE_SUMMARY_CHARTS,
52+
pageFilters
53+
);
54+
}

0 commit comments

Comments
 (0)