Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ import {GroupActivityType} from 'sentry/types/group';
interface IconWithDefaultProps {
Component: React.ComponentType<SVGIconProps> | null;
defaultProps: {locked?: boolean; type?: string};
componentFunction?: (props: {
propsFunction?: (data: GroupActivity['data']) => Record<string, unknown>;
renderIcon?: (props: {
data: GroupActivity['data'];
sentry_app: GroupActivity['sentry_app'];
user: GroupActivity['user'];
}) => React.ComponentType<SVGIconProps>;
propsFunction?: (data: GroupActivity['data']) => Record<string, unknown>;
}) => React.ReactNode;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Missed icon mapping consumer update

High Severity

componentFunction was renamed to renderIcon and now returns a React.ReactNode instead of a component type, but progressActivityTooltip.tsx still reads componentFunction and treats the result as a component. That shared consumer needs the same ReactNode-based update as index.tsx, or typecheck fails and a naive rename would render a node as a component.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit fe6c622. Configure here.

}

export const groupActivityTypeIconMapping: Record<
Expand All @@ -59,13 +59,11 @@ export const groupActivityTypeIconMapping: Record<
[GroupActivityType.NOTE]: {
Component: IconChat,
defaultProps: {},
componentFunction: ({user, sentry_app}) => {
renderIcon: ({user, sentry_app}) => {
if (sentry_app) {
return function () {
return <SentryAppAvatar sentryApp={sentry_app} />;
};
return <SentryAppAvatar sentryApp={sentry_app} />;
}
return user ? () => <StyledUserAvatar user={user} /> : IconChat;
return user ? <StyledUserAvatar user={user} /> : <IconChat size="xs" />;
},
},
[GroupActivityType.SET_RESOLVED]: {Component: IconCheckmark, defaultProps: {}},
Comment on lines 59 to 69

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Bug: The progress tooltip was not updated to use the new renderIcon property, causing CREATE_ISSUE activities to display a generic icon instead of a provider-specific one.
Severity: LOW

Suggested Fix

Update progressActivityTooltip.tsx to use the new renderIcon property from the icon mapping to render the icon, similar to the implementation in index.tsx. This will ensure that provider-specific icons are correctly displayed for CREATE_ISSUE activities.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: static/app/views/issueDetails/activitySection/groupActivityIcons.tsx#L59-L69

Potential issue: In `progressActivityTooltip.tsx`, the `ProgressActivityItem` component
attempts to render an icon for a `CREATE_ISSUE` activity. It references the
`componentFunction` property on the icon mapping, which no longer exists after a
refactor and was replaced by `renderIcon`. Because `componentFunction` is `undefined`,
the code falls back to rendering the generic `IconAdd` component. This happens when a
`CREATE_ISSUE` activity appears in the progress tooltip, which can occur if a group has
no other progress-specific activities. The result is that a generic 'add' icon is
displayed instead of the correct provider-specific icon (e.g., GitHub, Jira).

Did we get this right? 👍 / 👎 to inform future reviews.

Expand Down Expand Up @@ -109,21 +107,21 @@ export const groupActivityTypeIconMapping: Record<
[GroupActivityType.SET_REGRESSION]: {Component: IconFire, defaultProps: {}},
[GroupActivityType.CREATE_ISSUE]: {
Component: IconAdd,
componentFunction: ({data}) => {
renderIcon: ({data}) => {
const provider = (data as GroupActivityCreateIssue['data']).provider;
switch (provider) {
case 'GitHub':
return IconGithub;
return <IconGithub size="xs" />;
case 'GitLab':
return IconGitlab;
return <IconGitlab size="xs" />;
case 'Bitbucket':
return IconBitbucket;
return <IconBitbucket size="xs" />;
case 'Jira':
return IconJira;
return <IconJira size="xs" />;
case 'Asana':
return IconAsana;
return <IconAsana size="xs" />;
default:
return IconAdd;
return <IconAdd size="xs" />;
}
},
defaultProps: {},
Expand Down
24 changes: 11 additions & 13 deletions static/app/views/issueDetails/activitySection/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,14 +134,20 @@ function LegacyTimelineItem({
);

const iconMapping = groupActivityTypeIconMapping[item.type];
const componentFunction = iconMapping?.componentFunction;
const Icon = componentFunction
? componentFunction({
const Icon = iconMapping?.Component ?? null;
const iconNode = iconMapping?.renderIcon
? iconMapping.renderIcon({
data: item.data,
user: item.user,
sentry_app: item.sentry_app,
})
: (iconMapping?.Component ?? null);
: Icon && (
<Icon
{...iconMapping.defaultProps}
{...iconMapping.propsFunction?.(item.data)}
size="xs"
/>
);

return (
<ActivityTimelineItem
Expand All @@ -160,15 +166,7 @@ function LegacyTimelineItem({
</TitleRow>
}
timestamp={<Timestamp date={item.dateCreated} unitStyle={timestampUnitStyle} />}
icon={
Icon && (
<Icon
{...iconMapping.defaultProps}
{...iconMapping.propsFunction?.(item.data)}
size="xs"
/>
)
}
icon={iconNode}
>
{item.type === GroupActivityType.NOTE && editing ? (
<ActivityNoteInput
Expand Down
Loading