Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ref(issue-details): Allows replays section to reflect filters #81128

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from
22 changes: 14 additions & 8 deletions static/app/views/issueDetails/groupReplays/groupReplays.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import {trackAnalytics} from 'sentry/utils/analytics';
import {browserHistory} from 'sentry/utils/browserHistory';
import type EventView from 'sentry/utils/discover/eventView';
import useReplayCountForIssues from 'sentry/utils/replayCount/useReplayCountForIssues';
import useReplayList from 'sentry/utils/replays/hooks/useReplayList';
import useReplayReader from 'sentry/utils/replays/hooks/useReplayReader';
import {useLocation} from 'sentry/utils/useLocation';
Expand All @@ -29,6 +28,11 @@

import {ReplayClipPreviewWrapper} from './replayClipPreviewWrapper';
import useReplaysFromIssue from './useReplaysFromIssue';
import {
type ReplayCount,
useIssueDetailsReplayCount,
} from 'sentry/views/issueDetails/streamline/useIssueDetailsReplayCount';
import {useIssueDetailsEventCount} from 'sentry/views/issueDetails/streamline/useIssueDetailsEventCount';

type Props = {
group: Group;
Expand Down Expand Up @@ -177,9 +181,6 @@
}) {
const location = useLocation();
const urlParams = useUrlParams();
const {getReplayCountForIssue} = useReplayCountForIssues({
statsPeriod: '90d',
});
const hasStreamlinedUI = useHasStreamlinedUI();

const replayListData = useReplayList({
Expand All @@ -206,10 +207,13 @@
},
[location]
);
const eventCount = useIssueDetailsEventCount({group});

const selectedReplay = replays?.[selectedReplayIndex];
const {data: replayData} = useIssueDetailsReplayCount<ReplayCount>({group});

const replayCount = replayData?.[group.id] ?? 0;

const replayCount = getReplayCountForIssue(group.id, group.issueCategory);
const nextReplay = replays?.[selectedReplayIndex + 1];
const nextReplayText = nextReplay?.id
? `${nextReplay.user.display_name || t('Anonymous User')}`
Expand Down Expand Up @@ -267,20 +271,22 @@
replayTable
);

console.log({replayCount});

Check failure on line 274 in static/app/views/issueDetails/groupReplays/groupReplays.tsx

View workflow job for this annotation

GitHub Actions / pre-commit lint

Unexpected console statement

return (
<StyledLayoutPage withPadding hasStreamlinedUI={hasStreamlinedUI}>
<ReplayCountHeader>
<IconUser size="sm" />
{replayCount ?? 0 > 50
{(replayCount ?? 0) > 50
? tn(
'There are 50+ replays for this issue across %s event',
'There are 50+ replays for this issue across %s events',
group.count
eventCount
)
: t(
'There %s for this issue across %s.',
tn('is %s replay', 'are %s replays', replayCount ?? 0),
tn('%s event', '%s events', group.count)
tn('%s event', '%s events', eventCount)
)}
</ReplayCountHeader>
{inner}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import {decodeScalar} from 'sentry/utils/queryString';
import {DEFAULT_SORT} from 'sentry/utils/replays/fetchReplayList';
import useApi from 'sentry/utils/useApi';
import useCleanQueryParamsOnRouteLeave from 'sentry/utils/useCleanQueryParamsOnRouteLeave';
import {useEventQuery} from 'sentry/views/issueDetails/streamline/eventSearch';
import {useIssueDetailsEventView} from 'sentry/views/issueDetails/streamline/useIssueDetailsDiscoverQuery';
import {useHasStreamlinedUI} from 'sentry/views/issueDetails/utils';
import {REPLAY_LIST_FIELDS} from 'sentry/views/replays/types';

export default function useReplaysFromIssue({
Expand All @@ -22,6 +25,7 @@ export default function useReplaysFromIssue({
organization: Organization;
}) {
const api = useApi();
const hasStreamlinedUI = useHasStreamlinedUI();

const [replayIds, setReplayIds] = useState<string[]>();

Expand Down Expand Up @@ -53,6 +57,19 @@ export default function useReplaysFromIssue({
}
}, [api, organization.slug, group.id, dataSource, location.query.environment]);

const searchQuery = useEventQuery({group});
const replayQuery = replayIds?.length ? `id:[${String(replayIds)}]` : '';
const combinedQuery = [searchQuery, replayQuery].join(' ').trim();
const issueDetailsEventView = useIssueDetailsEventView({
group,
queryProps: {
version: 2,
fields: REPLAY_LIST_FIELDS,
orderby: decodeScalar(location.query.sort, DEFAULT_SORT),
},
});
issueDetailsEventView.query = combinedQuery;

const eventView = useMemo(() => {
if (!replayIds || !replayIds.length) {
return null;
Expand All @@ -78,7 +95,7 @@ export default function useReplaysFromIssue({
}, [fetchReplayIds]);

return {
eventView,
eventView: hasStreamlinedUI ? issueDetailsEventView : eventView,
fetchError,
isFetching: replayIds === undefined,
pageLinks: null,
Expand Down
15 changes: 9 additions & 6 deletions static/app/views/issueDetails/streamline/eventNavigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {SavedQueryDatasets} from 'sentry/utils/discover/types';
import {getConfigForIssueType} from 'sentry/utils/issueTypeConfig';
import parseLinkHeader from 'sentry/utils/parseLinkHeader';
import {keepPreviousData, useApiQuery} from 'sentry/utils/queryClient';
import useReplayCountForIssues from 'sentry/utils/replayCount/useReplayCountForIssues';
import normalizeUrl from 'sentry/utils/url/normalizeUrl';
import {useLocation} from 'sentry/utils/useLocation';
import useMedia from 'sentry/utils/useMedia';
Expand All @@ -29,13 +28,18 @@ import {useParams} from 'sentry/utils/useParams';
import {hasDatasetSelector} from 'sentry/views/dashboards/utils';
import {useGroupEventAttachments} from 'sentry/views/issueDetails/groupEventAttachments/useGroupEventAttachments';
import {useIssueDetailsEventView} from 'sentry/views/issueDetails/streamline/useIssueDetailsDiscoverQuery';
import {
type ReplayCount,
useIssueDetailsReplayCount,
} from 'sentry/views/issueDetails/streamline/useIssueDetailsReplayCount';
import {Tab, TabPaths} from 'sentry/views/issueDetails/types';
import {useGroupDetailsRoute} from 'sentry/views/issueDetails/useGroupDetailsRoute';
import {
getGroupEventQueryKey,
useDefaultIssueEvent,
useEnvironmentsFromUrl,
} from 'sentry/views/issueDetails/utils';
import {useIssueDetailsEventCount} from 'sentry/views/issueDetails/streamline/useIssueDetailsEventCount';

const enum EventNavOptions {
RECOMMENDED = 'recommended',
Expand Down Expand Up @@ -136,11 +140,10 @@ export function IssueEventNavigation({event, group, query}: IssueEventNavigation
notifyOnChangeProps: [],
}
);
const eventCount = useIssueDetailsEventCount({group});

const {getReplayCountForIssue} = useReplayCountForIssues({
statsPeriod: '90d',
});
const replaysCount = getReplayCountForIssue(group.id, group.issueCategory) ?? 0;
const {data: replayData} = useIssueDetailsReplayCount<ReplayCount>({group});
const replaysCount = replayData?.[group.id] ?? 0;

const attachments = useGroupEventAttachments({
groupId: group.id,
Expand Down Expand Up @@ -201,7 +204,7 @@ export function IssueEventNavigation({event, group, query}: IssueEventNavigation
key: Tab.DETAILS,
label: (
<DropdownCountWrapper isCurrentTab={currentTab === Tab.DETAILS}>
{TabName[Tab.DETAILS]} <ItemCount value={group.count} />
{TabName[Tab.DETAILS]} <ItemCount value={eventCount} />
</DropdownCountWrapper>
),
textValue: TabName[Tab.DETAILS],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {type Group} from 'sentry/types/group';
import {
useIssueDetailsDiscoverQuery,
useIssueDetailsEventView,
} from 'sentry/views/issueDetails/streamline/useIssueDetailsDiscoverQuery';
import {MultiSeriesEventsStats} from 'sentry/types/organization';
import {useMemo} from 'react';

export function useIssueDetailsEventCount({group}: {group: Group}) {
const eventView = useIssueDetailsEventView({group});
const {data: groupStats} = useIssueDetailsDiscoverQuery<MultiSeriesEventsStats>({
params: {
route: 'events-stats',
eventView,
referrer: 'issue_details.streamline_graph',
},
});
const eventCount = useMemo(() => {
if (!groupStats?.['count()']) {
return 0;
}
return groupStats['count()']?.data?.reduce((count, [_timestamp, countData]) => {
return count + (countData?.[0]?.count ?? 0);
}, 0);
}, [groupStats]);
return eventCount;
}
Comment on lines +10 to +28
Copy link
Member Author

@leeandher leeandher Nov 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This kinda sucks it's the entire query for a timeseries that I iterate over to create a count.

There is definitely an easier way, but I couldn't figure out the discover syntax to get there.

Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import {type Group, IssueCategory} from 'sentry/types/group';
import {
type ApiQueryKey,
useApiQuery,
type UseApiQueryOptions,
} from 'sentry/utils/queryClient';
import useOrganization from 'sentry/utils/useOrganization';
import {useEventQuery} from 'sentry/views/issueDetails/streamline/eventSearch';
import {useIssueDetailsEventView} from 'sentry/views/issueDetails/streamline/useIssueDetailsDiscoverQuery';

interface ReplayIdsParameters {
orgSlug: string;
query: {
data_source: 'discover' | 'search_issues';
query: string;
statsPeriod: string;
environment?: string[];
returnIds?: boolean;
};
}

export type ReplayCount = Record<string, number>;
export type ReplayIds = Record<string, string[]>;

function makeReplayCountQueryKey({orgSlug, query}: ReplayIdsParameters): ApiQueryKey {
return [`/organizations/${orgSlug}/replay-count/`, {query}];
}

function useReplayCount<T>(
params: ReplayIdsParameters,
options: Partial<UseApiQueryOptions<T>> = {}
) {
return useApiQuery<T>(makeReplayCountQueryKey(params), {
staleTime: Infinity,
retry: false,
...options,
});
}

export function useIssueDetailsReplayCount<T extends ReplayCount | ReplayIds>({
group,
}: {
group: Group;
}) {
const organization = useOrganization();
const searchQuery = useEventQuery({group});
const eventView = useIssueDetailsEventView({group});
return useReplayCount<T>({
orgSlug: organization.slug,
query: {
data_source:
group.issueCategory === IssueCategory.ERROR ? 'discover' : 'search_issues',
statsPeriod: eventView.statsPeriod ?? '90d',
environment: [...eventView.environment],
query: `issue.id:[${group.id}] ${searchQuery}`,
},
});
}
Loading