Skip to content

Commit a7026d8

Browse files
committed
feat(releases): Refactor to support deep-linked Issues Chart
Part of #88560
1 parent 07a0fe1 commit a7026d8

File tree

4 files changed

+106
-23
lines changed

4 files changed

+106
-23
lines changed

static/app/components/charts/chartWidgetLoader.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {useQuery} from '@tanstack/react-query';
44
import Placeholder from 'sentry/components/placeholder';
55
import {t} from 'sentry/locale';
66
import type {LoadableChartWidgetProps} from 'sentry/views/insights/common/components/widgets/types';
7+
import {EVENT_GRAPH_WIDGET_ID} from 'sentry/views/issueDetails/streamline/eventGraphWidget';
78

89
interface Props extends LoadableChartWidgetProps {
910
/**
@@ -26,7 +27,13 @@ interface Props extends LoadableChartWidgetProps {
2627
export function ChartWidgetLoader(props: Props) {
2728
const query = useQuery<{default: React.FC<LoadableChartWidgetProps>}>({
2829
queryKey: [`widget-${props.id}`],
29-
queryFn: () => import(`sentry/views/insights/common/components/widgets/${props.id}`),
30+
queryFn: () => {
31+
if (props.id === EVENT_GRAPH_WIDGET_ID) {
32+
return import('sentry/views/issueDetails/streamline/eventGraphWidget');
33+
}
34+
35+
return import(`sentry/views/insights/common/components/widgets/${props.id}`);
36+
},
3037
});
3138

3239
if (query.isPending) {

static/app/views/issueDetails/streamline/eventGraph.tsx

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import type {ReactEchartsRef, SeriesDataUnit} from 'sentry/types/echarts';
2626
import type {Event} from 'sentry/types/event';
2727
import type {Group} from 'sentry/types/group';
2828
import type {EventsStats, MultiSeriesEventsStats} from 'sentry/types/organization';
29+
import type EventView from 'sentry/utils/discover/eventView';
2930
import {DiscoverDatasets} from 'sentry/utils/discover/types';
3031
import {formatAbbreviatedNumber} from 'sentry/utils/formatters';
3132
import {getConfigForIssueType} from 'sentry/utils/issueTypeConfig';
@@ -37,6 +38,7 @@ import useOrganization from 'sentry/utils/useOrganization';
3738
import {useReleaseStats} from 'sentry/utils/useReleaseStats';
3839
import {getBucketSize} from 'sentry/views/dashboards/utils/getBucketSize';
3940
import {useIssueDetails} from 'sentry/views/issueDetails/streamline/context';
41+
import {EVENT_GRAPH_WIDGET_ID} from 'sentry/views/issueDetails/streamline/eventGraphWidget';
4042
import useFlagSeries from 'sentry/views/issueDetails/streamline/hooks/featureFlags/useFlagSeries';
4143
import {useCurrentEventMarklineSeries} from 'sentry/views/issueDetails/streamline/hooks/useEventMarkLineSeries';
4244
import {
@@ -48,7 +50,7 @@ import {Tab} from 'sentry/views/issueDetails/types';
4850
import {useGroupDetailsRoute} from 'sentry/views/issueDetails/useGroupDetailsRoute';
4951
import {useReleaseBubbles} from 'sentry/views/releases/releaseBubbles/useReleaseBubbles';
5052

51-
const enum EventGraphSeries {
53+
enum EventGraphSeries {
5254
EVENT = 'event',
5355
USER = 'user',
5456
}
@@ -64,6 +66,7 @@ interface EventGraphProps {
6466
* chart).
6567
*/
6668
disableZoomNavigation?: boolean;
69+
eventView?: EventView;
6770
ref?: React.Ref<ReactEchartsRef>;
6871
/**
6972
* Configures showing releases on the chart as bubbles or lines. This is used
@@ -100,6 +103,7 @@ function createSeriesAndCount(stats: EventsStats) {
100103
export function EventGraph({
101104
group,
102105
event,
106+
eventView: eventViewProps,
103107
disableZoomNavigation = false,
104108
showReleasesAs,
105109
showSummary = true,
@@ -131,7 +135,8 @@ export function EventGraph({
131135
ref: chartContainerRef,
132136
onResize,
133137
});
134-
const eventView = useIssueDetailsEventView({group, isSmallContainer});
138+
const eventViewHook = useIssueDetailsEventView({group, isSmallContainer});
139+
const eventView = eventViewProps || eventViewHook;
135140

136141
const {
137142
data: groupStats = {},
@@ -447,18 +452,22 @@ export function EventGraph({
447452
if (isLoadingStats || isPendingUniqueUsersCount) {
448453
return (
449454
<GraphWrapper {...styleProps}>
450-
<SummaryContainer>
451-
<GraphButton
452-
isActive={visibleSeries === EventGraphSeries.EVENT}
453-
disabled
454-
label={t('Events')}
455-
/>
456-
<GraphButton
457-
isActive={visibleSeries === EventGraphSeries.USER}
458-
disabled
459-
label={t('Users')}
460-
/>
461-
</SummaryContainer>
455+
{showSummary ? (
456+
<SummaryContainer>
457+
<GraphButton
458+
isActive={visibleSeries === EventGraphSeries.EVENT}
459+
disabled
460+
label={t('Events')}
461+
/>
462+
<GraphButton
463+
isActive={visibleSeries === EventGraphSeries.USER}
464+
disabled
465+
label={t('Users')}
466+
/>
467+
</SummaryContainer>
468+
) : (
469+
<div />
470+
)}
462471
<LoadingChartContainer ref={chartContainerRef}>
463472
<Placeholder height="96px" testId="event-graph-loading" />
464473
</LoadingChartContainer>
@@ -561,7 +570,11 @@ function GraphButton({
561570
label,
562571
count,
563572
...props
564-
}: {isActive: boolean; label: string; count?: string} & Partial<ButtonProps>) {
573+
}: {
574+
isActive: boolean;
575+
label: string;
576+
count?: string;
577+
} & Partial<ButtonProps>) {
565578
return (
566579
<CalloutButton
567580
isActive={isActive}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import styled from '@emotion/styled';
2+
3+
import Placeholder from 'sentry/components/placeholder';
4+
import {t} from 'sentry/locale';
5+
import {useParams} from 'sentry/utils/useParams';
6+
import type {LoadableChartWidgetProps} from 'sentry/views/insights/common/components/widgets/types';
7+
import {EventGraph} from 'sentry/views/issueDetails/streamline/eventGraph';
8+
import {useIssueDetailsEventView} from 'sentry/views/issueDetails/streamline/hooks/useIssueDetailsDiscoverQuery';
9+
import {useGroup} from 'sentry/views/issueDetails/useGroup';
10+
11+
export default function EventGraphWidget({pageFilters}: LoadableChartWidgetProps) {
12+
const {groupId} = useParams();
13+
14+
const {
15+
data: groupData,
16+
isPending: loadingGroup,
17+
isError: isGroupError,
18+
} = useGroup({groupId: groupId!});
19+
20+
const eventView = useIssueDetailsEventView({
21+
group: groupData!,
22+
isSmallContainer: true,
23+
pageFilters,
24+
});
25+
26+
if (loadingGroup) {
27+
return (
28+
<Container>
29+
<Placeholder height="100%" />
30+
</Container>
31+
);
32+
}
33+
34+
if (isGroupError) {
35+
return (
36+
<Container>
37+
<Placeholder height="100%" error={t('Error loading chart')} />
38+
</Container>
39+
);
40+
}
41+
42+
return (
43+
<EventGraph
44+
event={undefined}
45+
eventView={eventView}
46+
group={groupData}
47+
showSummary={false}
48+
showReleasesAs="line"
49+
disableZoomNavigation
50+
/>
51+
);
52+
}
53+
54+
const Container = styled('div')`
55+
height: 100%;
56+
`;
57+
58+
export const EVENT_GRAPH_WIDGET_ID = 'event-graph-widget';

static/app/views/issueDetails/streamline/hooks/useIssueDetailsDiscoverQuery.tsx

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {getInterval} from 'sentry/components/charts/utils';
2+
import type {PageFilters} from 'sentry/types/core';
23
import type {Group} from 'sentry/types/group';
34
import type {NewQuery, SavedQuery} from 'sentry/types/organization';
45
import EventView from 'sentry/utils/discover/eventView';
@@ -16,11 +17,13 @@ import {useGroupDefaultStatsPeriod} from 'sentry/views/issueDetails/useGroupDefa
1617

1718
export function useIssueDetailsEventView({
1819
group,
20+
pageFilters,
1921
queryProps,
2022
isSmallContainer = false,
2123
}: {
2224
group: Group;
2325
isSmallContainer?: boolean;
26+
pageFilters?: PageFilters;
2427
queryProps?: Partial<SavedQuery>;
2528
}) {
2629
const searchQuery = useEventQuery({groupId: group.id});
@@ -29,13 +32,15 @@ export function useIssueDetailsEventView({
2932
const hasSetStatsPeriod =
3033
location.query.statsPeriod || location.query.start || location.query.end;
3134
const defaultStatsPeriod = useGroupDefaultStatsPeriod(group, group.project);
32-
const periodQuery = hasSetStatsPeriod
33-
? getPeriod({
34-
start: location.query.start as string,
35-
end: location.query.end as string,
36-
period: location.query.statsPeriod as string,
37-
})
38-
: defaultStatsPeriod;
35+
const periodQuery = pageFilters
36+
? getPeriod(pageFilters.datetime)
37+
: hasSetStatsPeriod
38+
? getPeriod({
39+
start: location.query.start as string,
40+
end: location.query.end as string,
41+
period: location.query.statsPeriod as string,
42+
})
43+
: defaultStatsPeriod;
3944

4045
const interval = getInterval(
4146
{

0 commit comments

Comments
 (0)