Skip to content

Commit a237bff

Browse files
billyvgandrewshie-sentry
authored andcommitted
ref(insights): Combine data loading + widget rendering for Insights -> Http pages (#89325)
As part of an effort to be able to [deeplink to charts via the Releases Drawer](#88560), we need to move data fetching + chart rendering into a self-contained component (with a unique id). This refactors the widgets on `httpLandingPage` and `httpDomainSummaryPage` so that we get an idea of what this will look like before continuing on to do others.
1 parent 0751ccf commit a237bff

13 files changed

+278
-180
lines changed

static/app/views/insights/common/components/insightsTimeSeriesWidget.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export interface InsightsTimeSeriesWidgetProps extends WidgetTitleProps {
4040
aliases?: Record<string, string>;
4141
description?: React.ReactNode;
4242
height?: string | number;
43+
id?: string;
4344
interactiveTitle?: () => React.ReactNode;
4445
legendSelection?: LegendSelection | undefined;
4546
onLegendSelectionChange?: ((selection: LegendSelection) => void) | undefined;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import {decodeList, decodeScalar} from 'sentry/utils/queryString';
2+
import {EMPTY_OPTION_VALUE, escapeFilterValue} from 'sentry/utils/tokenizeSearch';
3+
import useLocationQuery from 'sentry/utils/url/useLocationQuery';
4+
import {BASE_FILTERS} from 'sentry/views/insights/http/settings';
5+
import {SpanMetricsField} from 'sentry/views/insights/types';
6+
7+
export function useHttpDomainSummaryChartFilter() {
8+
const {domain, [SpanMetricsField.USER_GEO_SUBREGION]: subregions} = useLocationQuery({
9+
fields: {
10+
domain: decodeScalar,
11+
[SpanMetricsField.USER_GEO_SUBREGION]: decodeList,
12+
},
13+
});
14+
return {
15+
...BASE_FILTERS,
16+
'span.domain': domain === '' ? EMPTY_OPTION_VALUE : escapeFilterValue(domain),
17+
...(subregions.length > 0
18+
? {
19+
[SpanMetricsField.USER_GEO_SUBREGION]: `[${subregions.join(',')}]`,
20+
}
21+
: {}),
22+
};
23+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import {decodeList, decodeScalar} from 'sentry/utils/queryString';
2+
import useLocationQuery from 'sentry/utils/url/useLocationQuery';
3+
import {BASE_FILTERS} from 'sentry/views/insights/http/settings';
4+
import {SpanMetricsField} from 'sentry/views/insights/types';
5+
6+
export function useHttpLandingChartFilter() {
7+
const query = useLocationQuery({
8+
fields: {
9+
'span.domain': decodeScalar,
10+
[SpanMetricsField.USER_GEO_SUBREGION]: decodeList,
11+
},
12+
});
13+
14+
return {
15+
...BASE_FILTERS,
16+
...(query[SpanMetricsField.USER_GEO_SUBREGION].length > 0
17+
? {
18+
[SpanMetricsField.USER_GEO_SUBREGION]: `[${query[SpanMetricsField.USER_GEO_SUBREGION].join(',')}]`,
19+
}
20+
: {}),
21+
};
22+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
2+
import {InsightsLineChartWidget} from 'sentry/views/insights/common/components/insightsLineChartWidget';
3+
import {useHttpDomainSummaryChartFilter} from 'sentry/views/insights/common/components/widgets/hooks/useHttpDomainSummaryChartFilter';
4+
import {useSpanMetricsSeries} from 'sentry/views/insights/common/queries/useDiscoverSeries';
5+
import {getDurationChartTitle} from 'sentry/views/insights/common/views/spans/types';
6+
import {Referrer} from 'sentry/views/insights/http/referrers';
7+
import {SpanMetricsField} from 'sentry/views/insights/types';
8+
9+
export default function HttpDomainSummaryDurationChartWidget() {
10+
const chartFilters = useHttpDomainSummaryChartFilter();
11+
const {
12+
isPending: isDurationDataLoading,
13+
data: durationData,
14+
error: durationError,
15+
} = useSpanMetricsSeries(
16+
{
17+
search: MutableSearch.fromQueryObject(chartFilters),
18+
yAxis: [`avg(${SpanMetricsField.SPAN_SELF_TIME})`],
19+
transformAliasToInputFormat: true,
20+
},
21+
Referrer.DOMAIN_SUMMARY_DURATION_CHART
22+
);
23+
24+
return (
25+
<InsightsLineChartWidget
26+
id="httpDomainSummaryDurationChartWidget"
27+
title={getDurationChartTitle('http')}
28+
series={[durationData[`avg(${SpanMetricsField.SPAN_SELF_TIME})`]]}
29+
isLoading={isDurationDataLoading}
30+
error={durationError}
31+
/>
32+
);
33+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
2+
import {InsightsLineChartWidget} from 'sentry/views/insights/common/components/insightsLineChartWidget';
3+
import {useHttpDomainSummaryChartFilter} from 'sentry/views/insights/common/components/widgets/hooks/useHttpDomainSummaryChartFilter';
4+
import {useSpanMetricsSeries} from 'sentry/views/insights/common/queries/useDiscoverSeries';
5+
import {DataTitles} from 'sentry/views/insights/common/views/spans/types';
6+
import {Referrer} from 'sentry/views/insights/http/referrers';
7+
import {FIELD_ALIASES} from 'sentry/views/insights/http/settings';
8+
9+
export default function HttpDomainSummaryResponseCodesWidget() {
10+
const chartFilters = useHttpDomainSummaryChartFilter();
11+
const {
12+
isPending: isResponseCodeDataLoading,
13+
data: responseCodeData,
14+
error: responseCodeError,
15+
} = useSpanMetricsSeries(
16+
{
17+
search: MutableSearch.fromQueryObject(chartFilters),
18+
yAxis: ['http_response_rate(3)', 'http_response_rate(4)', 'http_response_rate(5)'],
19+
transformAliasToInputFormat: true,
20+
},
21+
Referrer.DOMAIN_SUMMARY_RESPONSE_CODE_CHART
22+
);
23+
24+
return (
25+
<InsightsLineChartWidget
26+
id="httpDomainSummaryResponseCodesWidget"
27+
title={DataTitles.unsuccessfulHTTPCodes}
28+
series={[
29+
responseCodeData[`http_response_rate(3)`],
30+
responseCodeData[`http_response_rate(4)`],
31+
responseCodeData[`http_response_rate(5)`],
32+
]}
33+
aliases={FIELD_ALIASES}
34+
isLoading={isResponseCodeDataLoading}
35+
error={responseCodeError}
36+
/>
37+
);
38+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
2+
import {InsightsLineChartWidget} from 'sentry/views/insights/common/components/insightsLineChartWidget';
3+
import {useHttpDomainSummaryChartFilter} from 'sentry/views/insights/common/components/widgets/hooks/useHttpDomainSummaryChartFilter';
4+
import {useSpanMetricsSeries} from 'sentry/views/insights/common/queries/useDiscoverSeries';
5+
import {getThroughputChartTitle} from 'sentry/views/insights/common/views/spans/types';
6+
import {Referrer} from 'sentry/views/insights/http/referrers';
7+
8+
export default function HttpDomainSummaryThroughputChartWidget() {
9+
const chartFilters = useHttpDomainSummaryChartFilter();
10+
const {
11+
isPending: isThroughputDataLoading,
12+
data: throughputData,
13+
error: throughputError,
14+
} = useSpanMetricsSeries(
15+
{
16+
search: MutableSearch.fromQueryObject(chartFilters),
17+
yAxis: ['epm()'],
18+
transformAliasToInputFormat: true,
19+
},
20+
Referrer.DOMAIN_SUMMARY_THROUGHPUT_CHART
21+
);
22+
23+
return (
24+
<InsightsLineChartWidget
25+
id="httpDomainSummaryThroughputChartWidget"
26+
title={getThroughputChartTitle('http')}
27+
series={[throughputData['epm()']]}
28+
isLoading={isThroughputDataLoading}
29+
error={throughputError}
30+
/>
31+
);
32+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
2+
import {InsightsLineChartWidget} from 'sentry/views/insights/common/components/insightsLineChartWidget';
3+
import {useHttpLandingChartFilter} from 'sentry/views/insights/common/components/widgets/hooks/useHttpLandingChartFilter';
4+
import {useSpanMetricsSeries} from 'sentry/views/insights/common/queries/useDiscoverSeries';
5+
import {getDurationChartTitle} from 'sentry/views/insights/common/views/spans/types';
6+
import {Referrer} from 'sentry/views/insights/http/referrers';
7+
8+
export default function HttpDurationChartWidget() {
9+
const chartFilters = useHttpLandingChartFilter();
10+
const {
11+
isPending: isDurationDataLoading,
12+
data: durationData,
13+
error: durationError,
14+
} = useSpanMetricsSeries(
15+
{
16+
search: MutableSearch.fromQueryObject(chartFilters),
17+
yAxis: ['avg(span.self_time)'],
18+
transformAliasToInputFormat: true,
19+
},
20+
Referrer.LANDING_DURATION_CHART
21+
);
22+
23+
return (
24+
<InsightsLineChartWidget
25+
id="httpDurationChartWidget"
26+
title={getDurationChartTitle('http')}
27+
series={[durationData['avg(span.self_time)']]}
28+
isLoading={isDurationDataLoading}
29+
error={durationError}
30+
/>
31+
);
32+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
2+
import {InsightsLineChartWidget} from 'sentry/views/insights/common/components/insightsLineChartWidget';
3+
import {useHttpLandingChartFilter} from 'sentry/views/insights/common/components/widgets/hooks/useHttpLandingChartFilter';
4+
import {useSpanMetricsSeries} from 'sentry/views/insights/common/queries/useDiscoverSeries';
5+
import {DataTitles} from 'sentry/views/insights/common/views/spans/types';
6+
import {Referrer} from 'sentry/views/insights/http/referrers';
7+
import {FIELD_ALIASES} from 'sentry/views/insights/http/settings';
8+
9+
export default function HttpResponseCodesChartWidget() {
10+
const chartFilters = useHttpLandingChartFilter();
11+
const {
12+
isPending: isResponseCodeDataLoading,
13+
data: responseCodeData,
14+
error: responseCodeError,
15+
} = useSpanMetricsSeries(
16+
{
17+
search: MutableSearch.fromQueryObject(chartFilters),
18+
yAxis: ['http_response_rate(3)', 'http_response_rate(4)', 'http_response_rate(5)'],
19+
transformAliasToInputFormat: true,
20+
},
21+
Referrer.LANDING_RESPONSE_CODE_CHART
22+
);
23+
24+
return (
25+
<InsightsLineChartWidget
26+
id="httpResponseCodesChartWidget"
27+
title={DataTitles.unsuccessfulHTTPCodes}
28+
series={[
29+
responseCodeData[`http_response_rate(3)`],
30+
responseCodeData[`http_response_rate(4)`],
31+
responseCodeData[`http_response_rate(5)`],
32+
]}
33+
aliases={FIELD_ALIASES}
34+
isLoading={isResponseCodeDataLoading}
35+
error={responseCodeError}
36+
/>
37+
);
38+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
2+
import {InsightsLineChartWidget} from 'sentry/views/insights/common/components/insightsLineChartWidget';
3+
import {useHttpLandingChartFilter} from 'sentry/views/insights/common/components/widgets/hooks/useHttpLandingChartFilter';
4+
import {useSpanMetricsSeries} from 'sentry/views/insights/common/queries/useDiscoverSeries';
5+
import {getThroughputChartTitle} from 'sentry/views/insights/common/views/spans/types';
6+
import {Referrer} from 'sentry/views/insights/http/referrers';
7+
8+
export default function HttpThroughputChartWidget() {
9+
const chartFilters = useHttpLandingChartFilter();
10+
const {
11+
isPending: isThroughputDataLoading,
12+
data: throughputData,
13+
error: throughputError,
14+
} = useSpanMetricsSeries(
15+
{
16+
search: MutableSearch.fromQueryObject(chartFilters),
17+
yAxis: ['epm()'],
18+
transformAliasToInputFormat: true,
19+
},
20+
Referrer.LANDING_THROUGHPUT_CHART
21+
);
22+
23+
return (
24+
<InsightsLineChartWidget
25+
id="httpThroughputChartWidget"
26+
title={getThroughputChartTitle('http')}
27+
series={[throughputData['epm()']]}
28+
isLoading={isThroughputDataLoading}
29+
error={throughputError}
30+
/>
31+
);
32+
}

static/app/views/insights/http/views/httpDomainSummaryPage.spec.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {useReleaseStats} from 'sentry/utils/useReleaseStats';
1717

1818
jest.mock('sentry/utils/useReleaseStats');
1919

20-
describe('HTTPSummaryPage', function () {
20+
describe('HTTPDomainSummaryPage', function () {
2121
const organization = OrganizationFixture({features: ['insights-initial-modules']});
2222

2323
let throughputRequestMock!: jest.Mock;

0 commit comments

Comments
 (0)