Skip to content

Commit ee95b68

Browse files
authored
fix: Protect against feedbacks ingested without project association (#74218)
Fixes some feedback types to make them align with reality a little more. This comment is still true: ``` // Typescript is a lie. `project` might be missing if feedback didn't go // through the new ingest pipeline. This can happen in new self-hosted upgrades. ``` So what I did is bake that into the feedback item type, and fix any downstream callsites, so that the feedback item page can render in this case. I also wrapped the FeedbackItem component in an ErrorBoundary, so if there are problems the rest of the page should appear. Fixes #67412 Fixes #70136
1 parent 6bfcabd commit ee95b68

21 files changed

+165
-120
lines changed

static/app/components/deprecatedAssigneeSelectorDropdown.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ export class DeprecatedAssigneeSelectorDropdown extends Component<
223223
return [];
224224
}
225225

226-
const teams = ProjectsStore.getBySlug(group.project.slug)?.teams ?? [];
226+
const teams = ProjectsStore.getBySlug(group.project?.slug)?.teams ?? [];
227227
return teams
228228
.sort((a, b) => a.slug.localeCompare(b.slug))
229229
.map(team => ({

static/app/components/devtoolbar/components/feedback/feedbackPanel.tsx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -143,13 +143,15 @@ function FeedbackListItem({item}: {item: FeedbackIssueListItem}) {
143143
</div>
144144

145145
<div css={[badgeWithLabelCss, xSmallCss]} style={{gridArea: 'owner'}}>
146-
<ProjectBadge
147-
css={css({'&& img': {boxShadow: 'none'}})}
148-
project={item.project}
149-
avatarSize={16}
150-
hideName
151-
avatarProps={{hasTooltip: false}}
152-
/>
146+
{item.project ? (
147+
<ProjectBadge
148+
css={css({'&& img': {boxShadow: 'none'}})}
149+
project={item.project}
150+
avatarSize={16}
151+
hideName
152+
avatarProps={{hasTooltip: false}}
153+
/>
154+
) : null}
153155
<TextOverflow>{item.shortId}</TextOverflow>
154156
</div>
155157

static/app/components/feedback/feedbackItem/feedbackActions.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {IconEllipsis} from 'sentry/icons';
1111
import {t} from 'sentry/locale';
1212
import {space} from 'sentry/styles/space';
1313
import type {Event} from 'sentry/types/event';
14+
import type {Group} from 'sentry/types/group';
1415
import {defined} from 'sentry/utils';
1516
import type {FeedbackIssue} from 'sentry/utils/feedback/types';
1617

@@ -33,7 +34,7 @@ export default function FeedbackActions({
3334
<Flex gap={space(1)} align="center" className={className} style={style}>
3435
<ErrorBoundary mini>
3536
<FeedbackAssignedTo
36-
feedbackIssue={feedbackItem}
37+
feedbackIssue={feedbackItem as any as Group}
3738
feedbackEvent={eventData}
3839
showActorName={['medium', 'large'].includes(size)}
3940
/>

static/app/components/feedback/feedbackItem/feedbackActivitySection.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,20 @@ import {addErrorMessage, addSuccessMessage} from 'sentry/actionCreators/indicato
44
import useFeedbackCache from 'sentry/components/feedback/useFeedbackCache';
55
import useMutateActivity from 'sentry/components/feedback/useMutateActivity';
66
import {t} from 'sentry/locale';
7-
import type {Group, GroupActivity, GroupActivityNote, User} from 'sentry/types';
87
import type {NoteType} from 'sentry/types/alerts';
9-
import {GroupActivityType} from 'sentry/types/group';
10-
import type {FeedbackIssue} from 'sentry/utils/feedback/types';
8+
import {
9+
type Group,
10+
type GroupActivity,
11+
type GroupActivityNote,
12+
GroupActivityType,
13+
} from 'sentry/types/group';
14+
import type {User} from 'sentry/types/user';
1115
import {uniqueId} from 'sentry/utils/guid';
1216
import useOrganization from 'sentry/utils/useOrganization';
1317
import ActivitySection from 'sentry/views/issueDetails/activitySection';
1418

1519
type Props = {
16-
feedbackItem: FeedbackIssue;
20+
feedbackItem: Group;
1721
};
1822

1923
function FeedbackActivitySection(props: Props) {
@@ -30,7 +34,7 @@ function FeedbackActivitySection(props: Props) {
3034
invalidateCached([feedbackItem.id]);
3135
},
3236
organization,
33-
group: feedbackItem as unknown as Group,
37+
group: feedbackItem,
3438
});
3539

3640
const deleteOptions = useMemo(() => {

static/app/components/feedback/feedbackItem/feedbackAssignedTo.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@ import {getAssignedToDisplayName, getOwnerList} from 'sentry/components/group/as
1111
import {IconChevron, IconUser} from 'sentry/icons';
1212
import {t} from 'sentry/locale';
1313
import {space} from 'sentry/styles/space';
14-
import type {FeedbackEvent, FeedbackIssue} from 'sentry/utils/feedback/types';
14+
import type {Group} from 'sentry/types/group';
15+
import type {FeedbackEvent} from 'sentry/utils/feedback/types';
1516
import {useApiQuery} from 'sentry/utils/queryClient';
1617
import useApi from 'sentry/utils/useApi';
1718
import useOrganization from 'sentry/utils/useOrganization';
1819

1920
interface Props {
2021
feedbackEvent: FeedbackEvent | undefined;
21-
feedbackIssue: FeedbackIssue;
22+
feedbackIssue: Group;
2223
showActorName: boolean;
2324
}
2425

static/app/components/feedback/feedbackItem/feedbackItem.tsx

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {IconChat, IconFire, IconLink, IconTag} from 'sentry/icons';
1818
import {t} from 'sentry/locale';
1919
import {space} from 'sentry/styles/space';
2020
import type {Event} from 'sentry/types/event';
21+
import type {Group} from 'sentry/types/group';
2122
import type {FeedbackIssue} from 'sentry/utils/feedback/types';
2223
import useOrganization from 'sentry/utils/useOrganization';
2324

@@ -76,7 +77,7 @@ export default function FeedbackItem({feedbackItem, eventData, tags}: Props) {
7677
</Section>
7778
) : null}
7879

79-
{crashReportId && (
80+
{crashReportId && feedbackItem.project ? (
8081
<Section icon={<IconFire size="xs" />} title={t('Linked Error')}>
8182
<ErrorBoundary mini>
8283
<CrashReportSection
@@ -86,7 +87,7 @@ export default function FeedbackItem({feedbackItem, eventData, tags}: Props) {
8687
/>
8788
</ErrorBoundary>
8889
</Section>
89-
)}
90+
) : null}
9091

9192
<FeedbackReplay
9293
eventData={eventData}
@@ -98,22 +99,24 @@ export default function FeedbackItem({feedbackItem, eventData, tags}: Props) {
9899
<TagsSection tags={tags} />
99100
</Section>
100101

101-
<Section
102-
icon={<IconChat size="xs" />}
103-
title={
104-
<Fragment>
105-
{t('Internal Activity')}
106-
<QuestionTooltip
107-
size="xs"
108-
title={t(
109-
'Use this section to post comments that are visible only to your organization. It will also automatically update when someone resolves or assigns the feedback.'
110-
)}
111-
/>
112-
</Fragment>
113-
}
114-
>
115-
<FeedbackActivitySection feedbackItem={feedbackItem} />
116-
</Section>
102+
{feedbackItem.project ? (
103+
<Section
104+
icon={<IconChat size="xs" />}
105+
title={
106+
<Fragment>
107+
{t('Internal Activity')}
108+
<QuestionTooltip
109+
size="xs"
110+
title={t(
111+
'Use this section to post comments that are visible only to your organization. It will also automatically update when someone resolves or assigns the feedback.'
112+
)}
113+
/>
114+
</Fragment>
115+
}
116+
>
117+
<FeedbackActivitySection feedbackItem={feedbackItem as unknown as Group} />
118+
</Section>
119+
) : null}
117120
</OverflowPanelItem>
118121
</Fragment>
119122
);

static/app/components/feedback/feedbackItem/feedbackItemHeader.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export default function FeedbackItemHeader({eventData, feedbackItem}: Props) {
5151
/>
5252
</Flex>
5353

54-
{eventData && (
54+
{eventData && feedbackItem.project ? (
5555
<Flex wrap="wrap" justify="flex-start" css={fixIssueLinkSpacing}>
5656
<ErrorBoundary mini>
5757
<IssueTrackingSection
@@ -61,7 +61,7 @@ export default function FeedbackItemHeader({eventData, feedbackItem}: Props) {
6161
/>
6262
</ErrorBoundary>
6363
</Flex>
64-
)}
64+
) : null}
6565
</VerticalSpacing>
6666
);
6767
}

static/app/components/feedback/feedbackItem/feedbackItemLoader.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {useEffect} from 'react';
22

3+
import ErrorBoundary from 'sentry/components/errorBoundary';
34
import FeedbackEmptyDetails from 'sentry/components/feedback/details/feedbackEmptyDetails';
45
import FeedbackErrorDetails from 'sentry/components/feedback/details/feedbackErrorDetails';
56
import FeedbackItem from 'sentry/components/feedback/feedbackItem/feedbackItem';
@@ -37,9 +38,13 @@ export default function FeedbackItemLoader() {
3738
<Placeholder height="100%" />
3839
) : issueResult.isError ? (
3940
<FeedbackErrorDetails error={t('Unable to load feedback')} />
40-
) : !issueData ? (
41-
<FeedbackEmptyDetails />
41+
) : issueData ? (
42+
<ErrorBoundary
43+
customComponent={<FeedbackErrorDetails error={t('Unable to load feedback')} />}
44+
>
45+
<FeedbackItem eventData={eventData} feedbackItem={issueData} tags={tags} />
46+
</ErrorBoundary>
4247
) : (
43-
<FeedbackItem eventData={eventData} feedbackItem={issueData} tags={tags} />
48+
<FeedbackEmptyDetails />
4449
);
4550
}

static/app/components/feedback/feedbackItem/feedbackReplay.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export default function FeedbackReplay({eventData, feedbackItem, organization}:
2929
const {hasSentOneReplay, fetching: isFetchingSentOneReplay} =
3030
useHaveSelectedProjectsSentAnyReplayEvents();
3131
const platformSupported = replayPlatforms.includes(
32-
feedbackItem.project.platform as PlatformKey
32+
feedbackItem.project?.platform as PlatformKey
3333
);
3434

3535
if (replayId && hasReplayId) {

static/app/components/feedback/feedbackItem/feedbackShortId.tsx

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import styled from '@emotion/styled';
44

55
import {Flex} from 'sentry/components/container/flex';
66
import {DropdownMenu} from 'sentry/components/dropdownMenu';
7+
import useCurrentFeedbackProject from 'sentry/components/feedback/useCurrentFeedbackProject';
78
import ProjectBadge from 'sentry/components/idBadge/projectBadge';
89
import TextOverflow from 'sentry/components/textOverflow';
910
import {IconChevron} from 'sentry/icons';
@@ -36,12 +37,17 @@ const hideDropdown = css`
3637

3738
export default function FeedbackShortId({className, feedbackItem, style}: Props) {
3839
const organization = useOrganization();
40+
const projectSlug = useCurrentFeedbackProject();
3941

4042
const feedbackUrl =
4143
window.location.origin +
42-
normalizeUrl(
43-
`/organizations/${organization.slug}/feedback/?feedbackSlug=${feedbackItem.project.slug}:${feedbackItem.id}&project=${feedbackItem.project.id}`
44-
);
44+
normalizeUrl({
45+
pathname: `/organizations/${organization.slug}/feedback/`,
46+
query: {
47+
feedbackSlug: `${projectSlug}:${feedbackItem.id}`,
48+
project: feedbackItem.project?.id,
49+
},
50+
});
4551

4652
const {onClick: handleCopyUrl} = useCopyToClipboard({
4753
successMessage: t('Copied Feedback URL to clipboard'),
@@ -62,12 +68,14 @@ export default function FeedbackShortId({className, feedbackItem, style}: Props)
6268
css={hideDropdown}
6369
>
6470
<Flex gap={space(0.75)} align="center">
65-
<ProjectBadge
66-
project={feedbackItem.project}
67-
avatarSize={16}
68-
hideName
69-
avatarProps={{hasTooltip: true, tooltip: feedbackItem.project.slug}}
70-
/>
71+
{feedbackItem.project ? (
72+
<ProjectBadge
73+
project={feedbackItem.project}
74+
avatarSize={16}
75+
hideName
76+
avatarProps={{hasTooltip: true, tooltip: feedbackItem.project.slug}}
77+
/>
78+
) : null}
7179
<ShortId>{feedbackItem.shortId}</ShortId>
7280
</Flex>
7381
<DropdownMenu

0 commit comments

Comments
 (0)