Skip to content
Open
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
182 changes: 63 additions & 119 deletions static/app/components/events/autofix/v2/explorerSeerDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import {useCallback, useMemo} from 'react';
import styled from '@emotion/styled';
import {AnimatePresence} from 'framer-motion';

import {Flex} from '@sentry/scraps/layout';
import {Flex, Stack} from '@sentry/scraps/layout';
import {Heading, Text} from '@sentry/scraps/text';

import Feature from 'sentry/components/acl/feature';
import {Breadcrumbs as NavigationBreadcrumbs} from 'sentry/components/breadcrumbs';
import {Breadcrumbs} from 'sentry/components/breadcrumbs';
import {ProjectAvatar} from 'sentry/components/core/avatar/projectAvatar';
import {Button, ButtonBar} from 'sentry/components/core/button';
import {Button} from 'sentry/components/core/button';
import {LinkButton} from 'sentry/components/core/button/linkButton';
import AutofixFeedback from 'sentry/components/events/autofix/autofixFeedback';
import {
Expand All @@ -33,7 +34,7 @@ import {ExplorerNextSteps} from 'sentry/components/events/autofix/v2/nextSteps';
import {formatArtifactsToMarkdown} from 'sentry/components/events/autofix/v2/utils';
import {DrawerBody, DrawerHeader} from 'sentry/components/globalDrawer/components';
import Placeholder from 'sentry/components/placeholder';
import {IconAdd, IconCopy, IconSeer, IconSettings} from 'sentry/icons';
import {IconCopy, IconRefresh, IconSeer, IconSettings} from 'sentry/icons';
import {t} from 'sentry/locale';
import type {Event} from 'sentry/types/event';
import type {Group} from 'sentry/types/group';
Expand All @@ -42,7 +43,6 @@ import type {Project} from 'sentry/types/project';
import {getShortEventId} from 'sentry/utils/events';
import useCopyToClipboard from 'sentry/utils/useCopyToClipboard';
import useOrganization from 'sentry/utils/useOrganization';
import {MIN_NAV_HEIGHT} from 'sentry/views/issueDetails/streamline/eventTitle';
import type {useAiConfig} from 'sentry/views/issueDetails/streamline/hooks/useAiConfig';
import {SeerNotices} from 'sentry/views/issueDetails/streamline/sidebar/seerNotices';
import {openSeerExplorer} from 'sentry/views/seerExplorer/openSeerExplorer';
Expand All @@ -60,45 +60,59 @@ interface ExplorerSeerDrawerProps {
const drawerBreadcrumbs = (group: Group, event: Event, project: Project) => [
{
label: (
<CrumbContainer>
<Flex gap="md" align="center">
<ProjectAvatar project={project} />
<ShortId>{group.shortId}</ShortId>
</CrumbContainer>
<Text variant="muted">{group.shortId}</Text>
</Flex>
),
},
{label: getShortEventId(event.id)},
{label: t('Seer')},
];

interface DrawerNavigatorProps {
iconAnimation: 'loading' | 'waiting';
interface SeerDrawerHeaderProps {
event: Event;
group: Group;
project: Project;
}

function SeerDrawerHeader({event, group, project}: SeerDrawerHeaderProps) {
const breadcrumbs = useMemo(
() => drawerBreadcrumbs(group, event, project),
[group, event, project]
);
return (
<DrawerHeader>
<NavigationBreadcrumbs crumbs={breadcrumbs} />
</DrawerHeader>
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Drawer header missing position and border style overrides

Medium Severity

The new SeerDrawerHeader function component wraps DrawerHeader without the style overrides that were present in the original styled component. The old version set position: unset, box-shadow: none, max-height, and border-bottom. Without these overrides, the header will now have sticky positioning (causing it to stick when scrolling), display an unwanted box-shadow, lack the intended border-bottom, and have no height constraint.

Fix in Cursor Fix in Web


interface SeerDrawerNavigatorProps {
organization: Organization;
project: Project;
copyButtonDisabled?: boolean;
loading?: boolean;
onCopyMarkdown?: () => void;
onReset?: () => void;
}

/**
* Common navigator section with header and buttons.
*/
function DrawerNavigator({
iconAnimation,
function SeerDrawerNavigator({
loading,
organization,
project,
copyButtonDisabled = false,
onCopyMarkdown,
onReset,
}: DrawerNavigatorProps) {
}: SeerDrawerNavigatorProps) {
return (
<SeerDrawerNavigator>
<HeaderContainer>
<Header>{t('Seer')}</Header>
<IconSeer animation={iconAnimation} size="md" />
</HeaderContainer>
<ButtonWrapper>
<SeerDrawerNavigatorContainer justify="between" padding="sm 2xl">
Copy link
Contributor

Choose a reason for hiding this comment

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

Navigator missing vertical alignment and background styling

Medium Severity

The SeerDrawerNavigatorContainer is missing align="center" and background="primary" props that were present in the original styled component. Without align="center", the header text/icon and button groups won't be vertically centered. Without background="primary", the navigator section will lack its intended background color and may appear transparent or blend incorrectly with surrounding content.

Additional Locations (1)

Fix in Cursor Fix in Web

<Flex align="center" gap="sm">
<Heading as="h3" size="xl">
{t('Seer')}
</Heading>
<IconSeer animation={loading ? 'loading' : 'waiting'} size="md" />
</Flex>
<Flex gap="md">
<AutofixFeedback iconOnly />

<Feature features={['organizations:autofix-seer-preferences']}>
<LinkButton
external
Expand All @@ -115,18 +129,18 @@ function DrawerNavigator({
title={t('Copy analysis as Markdown / LLM prompt')}
aria-label={t('Copy analysis as Markdown')}
icon={<IconCopy />}
disabled={copyButtonDisabled}
disabled={!onCopyMarkdown}
/>
<Button
size="xs"
onClick={onReset}
icon={<IconAdd />}
icon={<IconRefresh />}
aria-label={t('Start a new analysis from scratch')}
title={t('Start a new analysis from scratch')}
disabled={!onReset}
/>
</ButtonWrapper>
</SeerDrawerNavigator>
</Flex>
</SeerDrawerNavigatorContainer>
);
}

Expand Down Expand Up @@ -219,11 +233,6 @@ export function ExplorerSeerDrawer({
copy(markdownText, {successMessage: t('Analysis copied to clipboard.')});
}, [artifacts, group, event, copy]);

const breadcrumbs = useMemo(
() => drawerBreadcrumbs(group, event, project),
[group, event, project]
);

const hasArtifacts =
!!artifacts.root_cause?.data ||
!!artifacts.solution?.data ||
Expand All @@ -234,21 +243,18 @@ export function ExplorerSeerDrawer({
if (isLoading) {
return (
<DrawerContainer>
<SeerDrawerHeader>
<NavigationCrumbs crumbs={breadcrumbs} />
</SeerDrawerHeader>
<DrawerNavigator
iconAnimation="loading"
copyButtonDisabled={!hasArtifacts}
onCopyMarkdown={handleCopyMarkdown}
<SeerDrawerHeader event={event} group={group} project={project} />
<SeerDrawerNavigator
loading
onCopyMarkdown={hasArtifacts ? handleCopyMarkdown : undefined}
onReset={undefined}
organization={organization}
project={project}
/>
<PlaceholderStack>
<Stack gap="xl" padding="xl">
<Placeholder height="10rem" />
<Placeholder height="15rem" />
</PlaceholderStack>
</Stack>
Copy link
Contributor

Choose a reason for hiding this comment

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

Loading state Stack missing top margin spacing

Low Severity

The Stack component used in the loading state is missing marginTop="xl" that was present in the original PlaceholderStack styled component. This will cause the placeholder content to appear closer to the navigator section above, reducing the visual spacing during the loading state.

Fix in Cursor Fix in Web

</DrawerContainer>
);
}
Expand All @@ -257,13 +263,9 @@ export function ExplorerSeerDrawer({
if (!runState && aiConfig.hasAutofix) {
return (
<DrawerContainer>
<SeerDrawerHeader>
<NavigationCrumbs crumbs={breadcrumbs} />
</SeerDrawerHeader>
<DrawerNavigator
iconAnimation="waiting"
copyButtonDisabled={!hasArtifacts}
onCopyMarkdown={handleCopyMarkdown}
<SeerDrawerHeader event={event} group={group} project={project} />
<SeerDrawerNavigator
onCopyMarkdown={hasArtifacts ? handleCopyMarkdown : undefined}
onReset={undefined}
organization={organization}
project={project}
Expand All @@ -284,13 +286,9 @@ export function ExplorerSeerDrawer({
if (!runState) {
return (
<DrawerContainer>
<SeerDrawerHeader>
<NavigationCrumbs crumbs={breadcrumbs} />
</SeerDrawerHeader>
<DrawerNavigator
iconAnimation="waiting"
copyButtonDisabled={!hasArtifacts}
onCopyMarkdown={handleCopyMarkdown}
<SeerDrawerHeader event={event} group={group} project={project} />
<SeerDrawerNavigator
onCopyMarkdown={hasArtifacts ? handleCopyMarkdown : undefined}
onReset={undefined}
organization={organization}
project={project}
Expand All @@ -309,16 +307,11 @@ export function ExplorerSeerDrawer({
// Has run - show artifacts and status
return (
<DrawerContainer>
<SeerDrawerHeader>
<NavigationCrumbs crumbs={breadcrumbs} />
</SeerDrawerHeader>
<DrawerNavigator
iconAnimation={
runState.status === 'processing' && isPolling ? 'loading' : 'waiting'
}
copyButtonDisabled={!hasArtifacts}
onCopyMarkdown={handleCopyMarkdown}
onReset={() => reset()}
<SeerDrawerHeader event={event} group={group} project={project} />
<SeerDrawerNavigator
loading={runState.status === 'processing' && isPolling}
onCopyMarkdown={hasArtifacts ? handleCopyMarkdown : undefined}
onReset={reset}
organization={organization}
project={project}
/>
Expand Down Expand Up @@ -425,23 +418,6 @@ const DrawerContainer = styled('div')`
background: ${p => p.theme.tokens.background.secondary};
`;

const SeerDrawerHeader = styled(DrawerHeader)`
position: unset;
max-height: ${MIN_NAV_HEIGHT}px;
box-shadow: none;
border-bottom: 1px solid ${p => p.theme.tokens.border.primary};
`;

const SeerDrawerNavigator = styled('div')`
display: flex;
align-items: center;
padding: ${p => p.theme.space.sm} ${p => p.theme.space['2xl']};
background: ${p => p.theme.tokens.background.primary};
z-index: 1;
min-height: ${MIN_NAV_HEIGHT}px;
box-shadow: ${p => p.theme.tokens.border.transparent.neutral.muted} 0 1px;
`;

const SeerDrawerBody = styled(DrawerBody)`
overflow: auto;
overscroll-behavior: contain;
Expand All @@ -453,43 +429,11 @@ const SeerDrawerBody = styled(DrawerBody)`
}
`;

const HeaderContainer = styled('div')`
display: flex;
align-items: center;
gap: ${p => p.theme.space.sm};
`;

const Header = styled('h3')`
font-size: ${p => p.theme.fontSize.xl};
font-weight: ${p => p.theme.fontWeight.bold};
margin: 0;
`;

const NavigationCrumbs = styled(NavigationBreadcrumbs)`
const NavigationBreadcrumbs = styled(Breadcrumbs)`
margin: 0;
padding: 0;
`;

const CrumbContainer = styled('div')`
display: flex;
gap: ${p => p.theme.space.md};
align-items: center;
`;

const ShortId = styled('div')`
font-family: ${p => p.theme.text.family};
font-size: ${p => p.theme.fontSize.md};
line-height: 1;
`;

const ButtonWrapper = styled(ButtonBar)`
margin-left: auto;
`;

const PlaceholderStack = styled('div')`
display: flex;
flex-direction: column;
gap: ${p => p.theme.space.xl};
margin-top: ${p => p.theme.space.xl};
padding: ${p => p.theme.space.xl};
const SeerDrawerNavigatorContainer = styled(Flex)`
box-shadow: ${p => p.theme.tokens.border.transparent.neutral.muted} 0 1px;
`;
Loading