Skip to content

Commit

Permalink
feat(issues): Add thread navigators, compact dropdown (#80969)
Browse files Browse the repository at this point in the history
  • Loading branch information
scttcper authored and andrewshie-sentry committed Dec 2, 2024
1 parent 783ef19 commit 1366cda
Show file tree
Hide file tree
Showing 9 changed files with 226 additions and 271 deletions.
12 changes: 12 additions & 0 deletions static/app/components/events/interfaces/threads.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1267,6 +1267,18 @@ describe('Threads', function () {
within(threadSelector).getByText('ViewController.causeCrash');
});

it('can navigate to next/previous thread', async function () {
render(<Threads {...props} />, {organization});
const threadSelector = await screen.findByTestId('thread-selector');
expect(threadSelector).toHaveTextContent('Thread #0');
await userEvent.click(await screen.findByRole('button', {name: 'Next Thread'}));
expect(threadSelector).toHaveTextContent('Thread #1');
await userEvent.click(
await screen.findByRole('button', {name: 'Previous Thread'})
);
expect(threadSelector).toHaveTextContent('Thread #0');
});

it('renders raw stack trace', async function () {
MockApiClient.addMockResponse({
url: `/projects/${organization.slug}/${project.slug}/events/${event.id}/apple-crash-report?minified=false`,
Expand Down
60 changes: 56 additions & 4 deletions static/app/components/events/interfaces/threads.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {Fragment, useEffect, useState} from 'react';
import {Fragment, useEffect, useMemo, useState} from 'react';
import styled from '@emotion/styled';

import {Button} from 'sentry/components/button';
import ButtonBar from 'sentry/components/buttonBar';
import {CommitRow} from 'sentry/components/commitRow';
import {Flex} from 'sentry/components/container/flex';
import ErrorBoundary from 'sentry/components/errorBoundary';
Expand All @@ -15,7 +17,14 @@ import Pill from 'sentry/components/pill';
import Pills from 'sentry/components/pills';
import QuestionTooltip from 'sentry/components/questionTooltip';
import TextOverflow from 'sentry/components/textOverflow';
import {IconClock, IconInfo, IconLock, IconPlay, IconTimer} from 'sentry/icons';
import {
IconChevron,
IconClock,
IconInfo,
IconLock,
IconPlay,
IconTimer,
} from 'sentry/icons';
import {t, tn} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import type {Event, Thread} from 'sentry/types/event';
Expand Down Expand Up @@ -101,15 +110,22 @@ const useActiveThreadState = (
};

export function Threads({data, event, projectSlug, groupingCurrentLevel, group}: Props) {
const threads = data.values ?? [];
// Sort threads by crashed first
const threads = useMemo(
() => (data.values ?? []).toSorted((a, b) => Number(b.crashed) - Number(a.crashed)),
[data.values]
);
const hasStreamlinedUI = useHasStreamlinedUI();
const [activeThread, setActiveThread] = useActiveThreadState(event, threads);

const stackTraceNotFound = !threads.length;

const hasMoreThanOneThread = threads.length > 1;

const exception = getThreadException(event, activeThread);
const exception = useMemo(
() => getThreadException(event, activeThread),
[event, activeThread]
);

const entryIndex = exception
? event.entries.findIndex(entry => entry.type === EntryType.EXCEPTION)
Expand Down Expand Up @@ -226,6 +242,18 @@ export function Threads({data, event, projectSlug, groupingCurrentLevel, group}:
const {id: activeThreadId, name: activeThreadName} = activeThread ?? {};
const hideThreadTags = activeThreadId === undefined || !activeThreadName;

function handleChangeThread(direction: 'previous' | 'next') {
const currentIndex = threads.findIndex(thread => thread.id === activeThreadId);
let nextIndex = direction === 'previous' ? currentIndex - 1 : currentIndex + 1;
if (nextIndex < 0) {
nextIndex = threads.length - 1;
} else if (nextIndex >= threads.length) {
nextIndex = 0;
}

setActiveThread(threads[nextIndex]);
}

const threadComponent = (
<Fragment>
{hasMoreThanOneThread && (
Expand All @@ -235,6 +263,28 @@ export function Threads({data, event, projectSlug, groupingCurrentLevel, group}:
<ThreadHeading>{t('Threads')}</ThreadHeading>
{activeThread && (
<Wrapper>
<ButtonBar merged>
<Button
title={t('Previous Thread')}
tooltipProps={{delay: 1000}}
icon={<IconChevron direction="left" />}
aria-label={t('Previous Thread')}
size="xs"
onClick={() => {
handleChangeThread('previous');
}}
/>
<Button
title={t('Next Thread')}
tooltipProps={{delay: 1000}}
icon={<IconChevron direction="right" />}
aria-label={t('Next Thread')}
size="xs"
onClick={() => {
handleChangeThread('next');
}}
/>
</ButtonBar>
<ThreadSelector
threads={threads}
activeThread={activeThread}
Expand Down Expand Up @@ -398,6 +448,8 @@ const LockReason = styled(TextOverflow)`
`;

const Wrapper = styled('div')`
display: flex;
gap: ${space(1)};
align-items: center;
flex-wrap: wrap;
flex-grow: 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import type {StacktraceType} from 'sentry/types/stacktrace';
import getRelevantFrame from './getRelevantFrame';
import getThreadException from './getThreadException';
import getThreadStacktrace from './getThreadStacktrace';
import trimFilename from './trimFilename';

type ThreadInfo = {
crashedInfo?: EntryData;
Expand All @@ -17,6 +16,11 @@ type ThreadInfo = {
state?: ThreadStates;
};

function trimFilename(filename: string) {
const pieces = filename.split(/\//g);
return pieces[pieces.length - 1];
}

function filterThreadInfo(
event: Event,
thread: Thread,
Expand Down

This file was deleted.

Loading

0 comments on commit 1366cda

Please sign in to comment.