diff --git a/static/app/views/insights/browser/resources/components/charts/resourceLandingPageCharts.tsx b/static/app/views/insights/browser/resources/components/charts/resourceLandingPageCharts.tsx
index 437901eff9a0fc..cb186b085e06d2 100644
--- a/static/app/views/insights/browser/resources/components/charts/resourceLandingPageCharts.tsx
+++ b/static/app/views/insights/browser/resources/components/charts/resourceLandingPageCharts.tsx
@@ -1,83 +1,23 @@
import styled from '@emotion/styled';
import {space} from 'sentry/styles/space';
-import {EMPTY_OPTION_VALUE, MutableSearch} from 'sentry/utils/tokenizeSearch';
-import {InsightsLineChartWidget} from 'sentry/views/insights/common/components/insightsLineChartWidget';
-import {useSpanMetricsSeries} from 'sentry/views/insights/common/queries/useDiscoverSeries';
-import type {ModuleFilters} from 'sentry/views/insights/common/views/spans/types';
-import {
- getDurationChartTitle,
- getThroughputChartTitle,
-} from 'sentry/views/insights/common/views/spans/types';
-import {SpanMetricsField} from 'sentry/views/insights/types';
-
-const {SPAN_SELF_TIME, NORMALIZED_DESCRIPTION, SPAN_DOMAIN} = SpanMetricsField;
-
-type Props = {
- appliedFilters: ModuleFilters;
- extraQuery?: string[];
-};
-
-export function ResourceLandingPageCharts({appliedFilters, extraQuery}: Props) {
- let query: string = buildDiscoverQueryConditions(appliedFilters);
-
- if (extraQuery) {
- query += ` ${extraQuery.join(' ')}`;
- }
-
- const {data, isPending, error} = useSpanMetricsSeries(
- {
- search: new MutableSearch(query),
- yAxis: ['epm()', `avg(${SPAN_SELF_TIME})`],
- transformAliasToInputFormat: true,
- },
- 'api.starfish.span-time-charts'
- );
+import {ResourceLandingDurationChartWidget} from 'sentry/views/insights/common/components/widgets/resourceLandingDurationChartWidget';
+import {ResourceLandingThroughputChartWidget} from 'sentry/views/insights/common/components/widgets/resourceLandingThroughputChartWidget';
+export function ResourceLandingPageCharts() {
return (
-
+
-
+
);
}
-const SPAN_FILTER_KEYS = ['span_operation', SPAN_DOMAIN, 'action'];
-
-const buildDiscoverQueryConditions = (appliedFilters: ModuleFilters) => {
- const result = Object.keys(appliedFilters)
- .filter(key => SPAN_FILTER_KEYS.includes(key))
- // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
- .filter(key => Boolean(appliedFilters[key]))
- .map(key => {
- // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
- const value = appliedFilters[key];
- if (key === SPAN_DOMAIN && value === EMPTY_OPTION_VALUE) {
- return [`!has:${SPAN_DOMAIN}`];
- }
- return `${key}:${value}`;
- });
-
- result.push(`has:${NORMALIZED_DESCRIPTION}`);
-
- return result.join(' ');
-};
-
const ChartsContainer = styled('div')`
display: flex;
flex-direction: row;
diff --git a/static/app/views/insights/browser/resources/components/charts/resourceSummaryCharts.tsx b/static/app/views/insights/browser/resources/components/charts/resourceSummaryCharts.tsx
index 18726cb67f0db9..8ca6b7a8a04a7d 100644
--- a/static/app/views/insights/browser/resources/components/charts/resourceSummaryCharts.tsx
+++ b/static/app/views/insights/browser/resources/components/charts/resourceSummaryCharts.tsx
@@ -1,105 +1,23 @@
import {Fragment} from 'react';
-import {t} from 'sentry/locale';
-import {MutableSearch} from 'sentry/utils/tokenizeSearch';
-import {Referrer} from 'sentry/views/insights/browser/resources/referrer';
-import {DATA_TYPE, FIELD_ALIASES} from 'sentry/views/insights/browser/resources/settings';
-import {useResourceModuleFilters} from 'sentry/views/insights/browser/resources/utils/useResourceFilters';
-import {InsightsLineChartWidget} from 'sentry/views/insights/common/components/insightsLineChartWidget';
import * as ModuleLayout from 'sentry/views/insights/common/components/moduleLayout';
-import {useSpanMetricsSeries} from 'sentry/views/insights/common/queries/useDiscoverSeries';
-import {
- getDurationChartTitle,
- getThroughputChartTitle,
-} from 'sentry/views/insights/common/views/spans/types';
-import {SpanMetricsField} from 'sentry/views/insights/types';
-
-const {
- SPAN_SELF_TIME,
- HTTP_RESPONSE_CONTENT_LENGTH,
- HTTP_DECODED_RESPONSE_CONTENT_LENGTH,
- HTTP_RESPONSE_TRANSFER_SIZE,
- RESOURCE_RENDER_BLOCKING_STATUS,
-} = SpanMetricsField;
-
-function ResourceSummaryCharts(props: {groupId: string}) {
- const filters = useResourceModuleFilters();
-
- const mutableSearch = MutableSearch.fromQueryObject({
- 'span.group': props.groupId,
- ...(filters[RESOURCE_RENDER_BLOCKING_STATUS]
- ? {
- [RESOURCE_RENDER_BLOCKING_STATUS]: filters[RESOURCE_RENDER_BLOCKING_STATUS],
- }
- : {}),
- ...(filters[SpanMetricsField.USER_GEO_SUBREGION]
- ? {
- [SpanMetricsField.USER_GEO_SUBREGION]: `[${filters[SpanMetricsField.USER_GEO_SUBREGION].join(',')}]`,
- }
- : {}),
- });
-
- const {
- data: spanMetricsSeriesData,
- isPending: areSpanMetricsSeriesLoading,
- error: spanMetricsSeriesError,
- } = useSpanMetricsSeries(
- {
- search: mutableSearch,
- yAxis: [
- `epm()`,
- `avg(${SPAN_SELF_TIME})`,
- `avg(${HTTP_RESPONSE_CONTENT_LENGTH})`,
- `avg(${HTTP_DECODED_RESPONSE_CONTENT_LENGTH})`,
- `avg(${HTTP_RESPONSE_TRANSFER_SIZE})`,
- ],
- enabled: Boolean(props.groupId),
- transformAliasToInputFormat: true,
- },
- Referrer.RESOURCE_SUMMARY_CHARTS
- );
-
- if (spanMetricsSeriesData) {
- spanMetricsSeriesData[`avg(${HTTP_RESPONSE_TRANSFER_SIZE})`].lineStyle = {
- type: 'dashed',
- };
- spanMetricsSeriesData[`avg(${HTTP_DECODED_RESPONSE_CONTENT_LENGTH})`].lineStyle = {
- type: 'dashed',
- };
- }
+import {ResourceSummaryAverageSizeChartWidget} from 'sentry/views/insights/common/components/widgets/resourceSummaryAverageSizeChartWidget';
+import {ResourceSummaryDurationChartWidget} from 'sentry/views/insights/common/components/widgets/resourceSummaryDurationChartWidget';
+import {ResourceSummaryThroughputChartWidget} from 'sentry/views/insights/common/components/widgets/resourceSummaryThroughputChartWidget';
+function ResourceSummaryCharts() {
return (
-
+
-
+
-
+
);
diff --git a/static/app/views/insights/browser/resources/components/resourceView.tsx b/static/app/views/insights/browser/resources/components/resourceView.tsx
index ddec211538d010..0abf456916a7bc 100644
--- a/static/app/views/insights/browser/resources/components/resourceView.tsx
+++ b/static/app/views/insights/browser/resources/components/resourceView.tsx
@@ -8,7 +8,6 @@ import {trackAnalytics} from 'sentry/utils/analytics';
import {useLocation} from 'sentry/utils/useLocation';
import {useNavigate} from 'sentry/utils/useNavigate';
import useOrganization from 'sentry/utils/useOrganization';
-import {getResourceTypeFilter} from 'sentry/views/insights/browser/common/queries/useResourcesQuery';
import RenderBlockingSelector from 'sentry/views/insights/browser/resources/components/renderBlockingSelector';
import ResourceTable from 'sentry/views/insights/browser/resources/components/tables/resourceTable';
import {
@@ -24,16 +23,13 @@ import {
import {useResourceSort} from 'sentry/views/insights/browser/resources/utils/useResourceSort';
import {QueryParameterNames} from 'sentry/views/insights/common/views/queryParameters';
import {TransactionSelector} from 'sentry/views/insights/common/views/spans/selectors/transactionSelector';
-import type {ModuleFilters} from 'sentry/views/insights/common/views/spans/types';
import {ResourceLandingPageCharts} from './charts/resourceLandingPageCharts';
const {
SPAN_OP: RESOURCE_TYPE,
- SPAN_DOMAIN,
TRANSACTION,
RESOURCE_RENDER_BLOCKING_STATUS,
- USER_GEO_SUBREGION,
} = BrowserStarfishFields;
type Option = {
@@ -45,25 +41,10 @@ function ResourceView() {
const filters = useResourceModuleFilters();
const sort = useResourceSort();
- const spanTimeChartsFilters: ModuleFilters = {
- 'span.op': `[${DEFAULT_RESOURCE_TYPES.join(',')}]`,
- ...(filters[SPAN_DOMAIN] ? {[SPAN_DOMAIN]: filters[SPAN_DOMAIN]} : {}),
- };
-
- const extraQuery = [
- ...getResourceTypeFilter(undefined, DEFAULT_RESOURCE_TYPES),
- ...(filters[USER_GEO_SUBREGION]
- ? [`user.geo.subregion:[${filters[USER_GEO_SUBREGION].join(',')}]`]
- : []),
- ];
-
return (
-
+
diff --git a/static/app/views/insights/browser/resources/views/resourceSummaryPage.tsx b/static/app/views/insights/browser/resources/views/resourceSummaryPage.tsx
index 921d252fb2cf42..d8390dc864510e 100644
--- a/static/app/views/insights/browser/resources/views/resourceSummaryPage.tsx
+++ b/static/app/views/insights/browser/resources/views/resourceSummaryPage.tsx
@@ -155,7 +155,7 @@ function ResourceSummary() {
)}
-
+
diff --git a/static/app/views/insights/common/components/widgets/hooks/useResourceLandingSeries.tsx b/static/app/views/insights/common/components/widgets/hooks/useResourceLandingSeries.tsx
new file mode 100644
index 00000000000000..7392b688d115a5
--- /dev/null
+++ b/static/app/views/insights/common/components/widgets/hooks/useResourceLandingSeries.tsx
@@ -0,0 +1,68 @@
+import type {PageFilters} from 'sentry/types/core';
+import {EMPTY_OPTION_VALUE, MutableSearch} from 'sentry/utils/tokenizeSearch';
+import {getResourceTypeFilter} from 'sentry/views/insights/browser/common/queries/useResourcesQuery';
+import {DEFAULT_RESOURCE_TYPES} from 'sentry/views/insights/browser/resources/settings';
+import {useResourceModuleFilters} from 'sentry/views/insights/browser/resources/utils/useResourceFilters';
+import {useSpanMetricsSeries} from 'sentry/views/insights/common/queries/useDiscoverSeries';
+import type {ModuleFilters} from 'sentry/views/insights/common/views/spans/types';
+import {SpanMetricsField} from 'sentry/views/insights/types';
+
+const {NORMALIZED_DESCRIPTION, SPAN_DOMAIN, SPAN_SELF_TIME, USER_GEO_SUBREGION} =
+ SpanMetricsField;
+
+const SPAN_FILTER_KEYS = ['span_operation', SPAN_DOMAIN, 'action'];
+
+const buildDiscoverQueryConditions = (appliedFilters: ModuleFilters) => {
+ const result = Object.keys(appliedFilters)
+ .filter(key => SPAN_FILTER_KEYS.includes(key))
+ // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
+ .filter(key => Boolean(appliedFilters[key]))
+ .map(key => {
+ // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
+ const value = appliedFilters[key];
+ if (key === SPAN_DOMAIN && value === EMPTY_OPTION_VALUE) {
+ return [`!has:${SPAN_DOMAIN}`];
+ }
+ return `${key}:${value}`;
+ });
+
+ result.push(`has:${NORMALIZED_DESCRIPTION}`);
+
+ return result.join(' ');
+};
+
+interface Props {
+ pageFilters?: PageFilters;
+}
+
+export function useResourceLandingSeries(props: Props = {}) {
+ const filters = useResourceModuleFilters();
+
+ const spanTimeChartsFilters: ModuleFilters = {
+ 'span.op': `[${DEFAULT_RESOURCE_TYPES.join(',')}]`,
+ ...(filters[SPAN_DOMAIN] ? {[SPAN_DOMAIN]: filters[SPAN_DOMAIN]} : {}),
+ };
+
+ const extraQuery = [
+ ...getResourceTypeFilter(undefined, DEFAULT_RESOURCE_TYPES),
+ ...(filters[USER_GEO_SUBREGION]
+ ? [`user.geo.subregion:[${filters[USER_GEO_SUBREGION].join(',')}]`]
+ : []),
+ ];
+
+ let query: string = buildDiscoverQueryConditions(spanTimeChartsFilters);
+
+ if (extraQuery.length) {
+ query += ` ${extraQuery.join(' ')}`;
+ }
+
+ return useSpanMetricsSeries(
+ {
+ search: new MutableSearch(query),
+ yAxis: ['epm()', `avg(${SPAN_SELF_TIME})`],
+ transformAliasToInputFormat: true,
+ },
+ 'api.starfish.span-time-charts',
+ props.pageFilters
+ );
+}
diff --git a/static/app/views/insights/common/components/widgets/hooks/useResourceSummarySeries.tsx b/static/app/views/insights/common/components/widgets/hooks/useResourceSummarySeries.tsx
new file mode 100644
index 00000000000000..f8ad5a17334e6f
--- /dev/null
+++ b/static/app/views/insights/common/components/widgets/hooks/useResourceSummarySeries.tsx
@@ -0,0 +1,54 @@
+import type {PageFilters} from 'sentry/types/core';
+import {MutableSearch} from 'sentry/utils/tokenizeSearch';
+import {Referrer} from 'sentry/views/insights/browser/resources/referrer';
+import {useResourceModuleFilters} from 'sentry/views/insights/browser/resources/utils/useResourceFilters';
+import {useSpanMetricsSeries} from 'sentry/views/insights/common/queries/useDiscoverSeries';
+import {SpanMetricsField} from 'sentry/views/insights/types';
+
+const {
+ SPAN_SELF_TIME,
+ HTTP_RESPONSE_CONTENT_LENGTH,
+ HTTP_DECODED_RESPONSE_CONTENT_LENGTH,
+ HTTP_RESPONSE_TRANSFER_SIZE,
+ RESOURCE_RENDER_BLOCKING_STATUS,
+} = SpanMetricsField;
+
+interface Props {
+ groupId?: string;
+ pageFilters?: PageFilters;
+}
+
+export function useResourceSummarySeries({pageFilters, groupId}: Props = {}) {
+ const filters = useResourceModuleFilters();
+
+ const mutableSearch = MutableSearch.fromQueryObject({
+ 'span.group': groupId,
+ ...(filters[RESOURCE_RENDER_BLOCKING_STATUS]
+ ? {
+ [RESOURCE_RENDER_BLOCKING_STATUS]: filters[RESOURCE_RENDER_BLOCKING_STATUS],
+ }
+ : {}),
+ ...(filters[SpanMetricsField.USER_GEO_SUBREGION]
+ ? {
+ [SpanMetricsField.USER_GEO_SUBREGION]: `[${filters[SpanMetricsField.USER_GEO_SUBREGION].join(',')}]`,
+ }
+ : {}),
+ });
+
+ return useSpanMetricsSeries(
+ {
+ search: mutableSearch,
+ yAxis: [
+ `epm()`,
+ `avg(${SPAN_SELF_TIME})`,
+ `avg(${HTTP_RESPONSE_CONTENT_LENGTH})`,
+ `avg(${HTTP_DECODED_RESPONSE_CONTENT_LENGTH})`,
+ `avg(${HTTP_RESPONSE_TRANSFER_SIZE})`,
+ ],
+ enabled: Boolean(groupId),
+ transformAliasToInputFormat: true,
+ },
+ Referrer.RESOURCE_SUMMARY_CHARTS,
+ pageFilters
+ );
+}
diff --git a/static/app/views/insights/common/components/widgets/resourceLandingDurationChartWidget.tsx b/static/app/views/insights/common/components/widgets/resourceLandingDurationChartWidget.tsx
new file mode 100644
index 00000000000000..9435c251386350
--- /dev/null
+++ b/static/app/views/insights/common/components/widgets/resourceLandingDurationChartWidget.tsx
@@ -0,0 +1,24 @@
+import {InsightsLineChartWidget} from 'sentry/views/insights/common/components/insightsLineChartWidget';
+import {useResourceLandingSeries} from 'sentry/views/insights/common/components/widgets/hooks/useResourceLandingSeries';
+import type {LoadableChartWidgetProps} from 'sentry/views/insights/common/components/widgets/types';
+import {getDurationChartTitle} from 'sentry/views/insights/common/views/spans/types';
+import {SpanMetricsField} from 'sentry/views/insights/types';
+
+const {SPAN_SELF_TIME} = SpanMetricsField;
+
+export function ResourceLandingDurationChartWidget(props: LoadableChartWidgetProps) {
+ const {data, isPending, error} = useResourceLandingSeries({
+ pageFilters: props.pageFilters,
+ });
+
+ return (
+
+ );
+}
diff --git a/static/app/views/insights/common/components/widgets/resourceLandingThroughputChartWidget.tsx b/static/app/views/insights/common/components/widgets/resourceLandingThroughputChartWidget.tsx
new file mode 100644
index 00000000000000..861a0e906820a2
--- /dev/null
+++ b/static/app/views/insights/common/components/widgets/resourceLandingThroughputChartWidget.tsx
@@ -0,0 +1,21 @@
+import {InsightsLineChartWidget} from 'sentry/views/insights/common/components/insightsLineChartWidget';
+import {useResourceLandingSeries} from 'sentry/views/insights/common/components/widgets/hooks/useResourceLandingSeries';
+import type {LoadableChartWidgetProps} from 'sentry/views/insights/common/components/widgets/types';
+import {getThroughputChartTitle} from 'sentry/views/insights/common/views/spans/types';
+
+export function ResourceLandingThroughputChartWidget(props: LoadableChartWidgetProps) {
+ const {data, isPending, error} = useResourceLandingSeries({
+ pageFilters: props.pageFilters,
+ });
+
+ return (
+
+ );
+}
diff --git a/static/app/views/insights/common/components/widgets/resourceSummaryAverageSizeChartWidget.tsx b/static/app/views/insights/common/components/widgets/resourceSummaryAverageSizeChartWidget.tsx
new file mode 100644
index 00000000000000..4162e78f081da3
--- /dev/null
+++ b/static/app/views/insights/common/components/widgets/resourceSummaryAverageSizeChartWidget.tsx
@@ -0,0 +1,46 @@
+import {t} from 'sentry/locale';
+import {useParams} from 'sentry/utils/useParams';
+import {DATA_TYPE, FIELD_ALIASES} from 'sentry/views/insights/browser/resources/settings';
+import {InsightsLineChartWidget} from 'sentry/views/insights/common/components/insightsLineChartWidget';
+import {useResourceSummarySeries} from 'sentry/views/insights/common/components/widgets/hooks/useResourceSummarySeries';
+import type {LoadableChartWidgetProps} from 'sentry/views/insights/common/components/widgets/types';
+import {SpanMetricsField} from 'sentry/views/insights/types';
+
+const {
+ HTTP_RESPONSE_CONTENT_LENGTH,
+ HTTP_DECODED_RESPONSE_CONTENT_LENGTH,
+ HTTP_RESPONSE_TRANSFER_SIZE,
+} = SpanMetricsField;
+
+export function ResourceSummaryAverageSizeChartWidget(props: LoadableChartWidgetProps) {
+ const {groupId} = useParams();
+
+ const {data, isPending, error} = useResourceSummarySeries({
+ groupId,
+ pageFilters: props.pageFilters,
+ });
+
+ if (data) {
+ data[`avg(${HTTP_RESPONSE_TRANSFER_SIZE})`].lineStyle = {
+ type: 'dashed',
+ };
+ data[`avg(${HTTP_DECODED_RESPONSE_CONTENT_LENGTH})`].lineStyle = {
+ type: 'dashed',
+ };
+ }
+ return (
+
+ );
+}
diff --git a/static/app/views/insights/common/components/widgets/resourceSummaryDurationChartWidget.tsx b/static/app/views/insights/common/components/widgets/resourceSummaryDurationChartWidget.tsx
new file mode 100644
index 00000000000000..ade1896b5ac4d5
--- /dev/null
+++ b/static/app/views/insights/common/components/widgets/resourceSummaryDurationChartWidget.tsx
@@ -0,0 +1,28 @@
+import {useParams} from 'sentry/utils/useParams';
+import {InsightsLineChartWidget} from 'sentry/views/insights/common/components/insightsLineChartWidget';
+import {useResourceSummarySeries} from 'sentry/views/insights/common/components/widgets/hooks/useResourceSummarySeries';
+import type {LoadableChartWidgetProps} from 'sentry/views/insights/common/components/widgets/types';
+import {getDurationChartTitle} from 'sentry/views/insights/common/views/spans/types';
+import {SpanMetricsField} from 'sentry/views/insights/types';
+
+const {SPAN_SELF_TIME} = SpanMetricsField;
+
+export function ResourceSummaryDurationChartWidget(props: LoadableChartWidgetProps) {
+ const {groupId} = useParams();
+
+ const {data, isPending, error} = useResourceSummarySeries({
+ groupId,
+ pageFilters: props.pageFilters,
+ });
+
+ return (
+
+ );
+}
diff --git a/static/app/views/insights/common/components/widgets/resourceSummaryThroughputChartWidget.tsx b/static/app/views/insights/common/components/widgets/resourceSummaryThroughputChartWidget.tsx
new file mode 100644
index 00000000000000..ab49e3723eeca7
--- /dev/null
+++ b/static/app/views/insights/common/components/widgets/resourceSummaryThroughputChartWidget.tsx
@@ -0,0 +1,25 @@
+import {useParams} from 'sentry/utils/useParams';
+import {InsightsLineChartWidget} from 'sentry/views/insights/common/components/insightsLineChartWidget';
+import {useResourceSummarySeries} from 'sentry/views/insights/common/components/widgets/hooks/useResourceSummarySeries';
+import type {LoadableChartWidgetProps} from 'sentry/views/insights/common/components/widgets/types';
+import {getThroughputChartTitle} from 'sentry/views/insights/common/views/spans/types';
+
+export function ResourceSummaryThroughputChartWidget(props: LoadableChartWidgetProps) {
+ const {groupId} = useParams();
+
+ const {data, isPending, error} = useResourceSummarySeries({
+ groupId,
+ pageFilters: props.pageFilters,
+ });
+
+ return (
+
+ );
+}