Skip to content

Commit

Permalink
feat(issue-details): Add streamlined sidebar and activity (#78043)
Browse files Browse the repository at this point in the history
new version of #77958 , which
was reverted because the condition for not using a grid layout was being
read as false (undefined) on non-issues pages. this pr updates it to
only change the layout of the issue details container so it won't affect
any other page.
  • Loading branch information
roggenkemper authored and 0Calories committed Sep 25, 2024
1 parent 1eead49 commit 1d65341
Show file tree
Hide file tree
Showing 6 changed files with 932 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ import {getConfigForIssueType} from 'sentry/utils/issueTypeConfig';
import {VisuallyCompleteWithData} from 'sentry/utils/performanceForSentry';
import normalizeUrl from 'sentry/utils/url/normalizeUrl';
import usePrevious from 'sentry/utils/usePrevious';
import {useSyncedLocalStorageState} from 'sentry/utils/useSyncedLocalStorageState';
import GroupEventDetailsContent from 'sentry/views/issueDetails/groupEventDetails/groupEventDetailsContent';
import GroupEventHeader from 'sentry/views/issueDetails/groupEventHeader';
import GroupSidebar from 'sentry/views/issueDetails/groupSidebar';
import StreamlinedSidebar from 'sentry/views/issueDetails/streamline/sidebar';

import ReprocessingProgress from '../reprocessingProgress';
import {
Expand Down Expand Up @@ -72,6 +74,8 @@ function GroupEventDetails(props: GroupEventDetailsProps) {
const prevEvent = usePrevious(event);
const hasStreamlinedUI = useHasStreamlinedUI();

const [sidebarOpen, _] = useSyncedLocalStorageState('issue-details-sidebar-open', true);

// load the data
useSentryAppComponentsData({projectId});

Expand Down Expand Up @@ -172,6 +176,7 @@ function GroupEventDetails(props: GroupEventDetailsProps) {
<StyledLayoutBody
data-test-id="group-event-details"
hasStreamlinedUi={hasStreamlinedUI}
sidebarOpen={sidebarOpen}
>
{groupReprocessingStatus === ReprocessingStatus.REPROCESSING ? (
<ReprocessingProgress
Expand All @@ -197,15 +202,23 @@ function GroupEventDetails(props: GroupEventDetailsProps) {
)}
{renderContent()}
</MainLayoutComponent>
<StyledLayoutSide hasStreamlinedUi={hasStreamlinedUI}>
<GroupSidebar
organization={organization}
project={project}
group={group}
event={eventWithMeta}
environments={environments}
/>
</StyledLayoutSide>
{hasStreamlinedUI ? (
sidebarOpen ? (
<StyledLayoutSide hasStreamlinedUi={hasStreamlinedUI}>
<StreamlinedSidebar group={group} event={event} project={project} />
</StyledLayoutSide>
) : null
) : (
<StyledLayoutSide hasStreamlinedUi={hasStreamlinedUI}>
<GroupSidebar
organization={organization}
project={project}
group={group}
event={eventWithMeta}
environments={environments}
/>
</StyledLayoutSide>
)}
</Fragment>
)}
</StyledLayoutBody>
Expand All @@ -214,7 +227,10 @@ function GroupEventDetails(props: GroupEventDetailsProps) {
);
}

const StyledLayoutBody = styled(Layout.Body)<{hasStreamlinedUi: boolean}>`
const StyledLayoutBody = styled(Layout.Body)<{
hasStreamlinedUi: boolean;
sidebarOpen: boolean;
}>`
/* Makes the borders align correctly */
padding: 0 !important;
@media (min-width: ${p => p.theme.breakpoints.large}) {
Expand All @@ -226,6 +242,7 @@ const StyledLayoutBody = styled(Layout.Body)<{hasStreamlinedUi: boolean}>`
css`
@media (min-width: ${p.theme.breakpoints.large}) {
gap: ${space(2)};
display: ${p.sidebarOpen ? 'grid' : 'block'};
}
`}
`;
Expand Down
50 changes: 50 additions & 0 deletions static/app/views/issueDetails/streamline/activitySection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {Fragment} from 'react';
import styled from '@emotion/styled';

import Timeline from 'sentry/components/timeline';
import TimeSince from 'sentry/components/timeSince';
import type {Group} from 'sentry/types/group';
import useOrganization from 'sentry/utils/useOrganization';
import {groupActivityTypeIconMapping} from 'sentry/views/issueDetails/streamline/groupActivityIcons';
import getGroupActivityItem from 'sentry/views/issueDetails/streamline/groupActivityItem';

function StreamlinedActivitySection({group}: {group: Group}) {
const organization = useOrganization();

return (
<Fragment>
<Timeline.Container>
{group.activity.map(item => {
const authorName = item.user ? item.user.name : 'Sentry';
const {title, message} = getGroupActivityItem(
item,
organization,
group.project.id,
<Author>{authorName}</Author>
);

const Icon = groupActivityTypeIconMapping[item.type]?.Component ?? null;

return (
<Timeline.Item
title={title}
timestamp={<TimeSince date={item.dateCreated} />}
icon={
Icon && <Icon {...groupActivityTypeIconMapping[item.type].defaultProps} />
}
key={item.id}
>
{message}
</Timeline.Item>
);
})}
</Timeline.Container>
</Fragment>
);
}

const Author = styled('span')`
font-weight: ${p => p.theme.fontWeightBold};
`;

export default StreamlinedActivitySection;
67 changes: 67 additions & 0 deletions static/app/views/issueDetails/streamline/groupActivityIcons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import {
IconAdd,
IconCheckmark,
IconClose,
IconDelete,
IconEdit,
IconFile,
IconFire,
IconFlag,
IconGraph,
IconLock,
IconMute,
IconNext,
IconPlay,
IconPrevious,
IconRefresh,
IconUnsubscribed,
IconUser,
} from 'sentry/icons';
import {GroupActivityType} from 'sentry/types/group';

interface IconWithDefaultProps {
Component: React.ComponentType<any> | null;
defaultProps: {locked?: boolean; type?: string};
}

export const groupActivityTypeIconMapping: Record<
GroupActivityType,
IconWithDefaultProps
> = {
[GroupActivityType.NOTE]: {Component: IconFile, defaultProps: {}},
[GroupActivityType.SET_RESOLVED]: {Component: IconCheckmark, defaultProps: {}},
[GroupActivityType.SET_RESOLVED_BY_AGE]: {Component: IconCheckmark, defaultProps: {}},
[GroupActivityType.SET_RESOLVED_IN_RELEASE]: {
Component: IconCheckmark,
defaultProps: {},
},
[GroupActivityType.SET_RESOLVED_IN_COMMIT]: {
Component: IconCheckmark,
defaultProps: {},
},
[GroupActivityType.SET_RESOLVED_IN_PULL_REQUEST]: {
Component: IconCheckmark,
defaultProps: {},
},
[GroupActivityType.SET_UNRESOLVED]: {Component: IconClose, defaultProps: {}},
[GroupActivityType.SET_IGNORED]: {Component: IconMute, defaultProps: {}},
[GroupActivityType.SET_PUBLIC]: {Component: IconLock, defaultProps: {}},
[GroupActivityType.SET_PRIVATE]: {Component: IconLock, defaultProps: {locked: true}},
[GroupActivityType.SET_REGRESSION]: {Component: IconFire, defaultProps: {}},
[GroupActivityType.CREATE_ISSUE]: {Component: IconAdd, defaultProps: {}},
[GroupActivityType.UNMERGE_SOURCE]: {Component: IconPrevious, defaultProps: {}},
[GroupActivityType.UNMERGE_DESTINATION]: {Component: IconPrevious, defaultProps: {}},
[GroupActivityType.FIRST_SEEN]: {Component: IconFlag, defaultProps: {}},
[GroupActivityType.ASSIGNED]: {Component: IconUser, defaultProps: {}},
[GroupActivityType.UNASSIGNED]: {Component: IconUnsubscribed, defaultProps: {}},
[GroupActivityType.MERGE]: {Component: IconNext, defaultProps: {}},
[GroupActivityType.REPROCESS]: {Component: IconRefresh, defaultProps: {}},
[GroupActivityType.MARK_REVIEWED]: {Component: IconCheckmark, defaultProps: {}},
[GroupActivityType.AUTO_SET_ONGOING]: {Component: IconPlay, defaultProps: {}},
[GroupActivityType.SET_ESCALATING]: {
Component: IconGraph,
defaultProps: {type: 'area'},
},
[GroupActivityType.SET_PRIORITY]: {Component: IconEdit, defaultProps: {}},
[GroupActivityType.DELETED_ATTACHMENT]: {Component: IconDelete, defaultProps: {}},
};
Loading

0 comments on commit 1d65341

Please sign in to comment.