|
@@ -1,24 +1,22 @@
|
|
|
import {Fragment, useCallback} from 'react';
|
|
|
import styled from '@emotion/styled';
|
|
|
|
|
|
-import Type from 'sentry/components/events/interfaces/breadcrumbs/breadcrumb/type';
|
|
|
import {
|
|
|
Panel as BasePanel,
|
|
|
PanelBody as BasePanelBody,
|
|
|
PanelHeader as BasePanelHeader,
|
|
|
- PanelItem,
|
|
|
} from 'sentry/components/panels';
|
|
|
import Placeholder from 'sentry/components/placeholder';
|
|
|
-import ActionCategory from 'sentry/components/replays/actionCategory';
|
|
|
-import PlayerRelativeTime from 'sentry/components/replays/playerRelativeTime';
|
|
|
import {useReplayContext} from 'sentry/components/replays/replayContext';
|
|
|
import {relativeTimeInMs} from 'sentry/components/replays/utils';
|
|
|
import {t} from 'sentry/locale';
|
|
|
import space from 'sentry/styles/space';
|
|
|
-import {BreadcrumbType, Crumb} from 'sentry/types/breadcrumbs';
|
|
|
+import {Crumb} from 'sentry/types/breadcrumbs';
|
|
|
import {EventTransaction} from 'sentry/types/event';
|
|
|
import {getPrevBreadcrumb} from 'sentry/utils/replays/getBreadcrumb';
|
|
|
|
|
|
+import BreadcrumbItem from './breadcrumbItem';
|
|
|
+
|
|
|
function CrumbPlaceholder({number}: {number: number}) {
|
|
|
return (
|
|
|
<Fragment>
|
|
@@ -40,20 +38,7 @@ type Props = {
|
|
|
event: EventTransaction | undefined;
|
|
|
};
|
|
|
|
|
|
-type ContainerProps = {
|
|
|
- isHovered: boolean;
|
|
|
- isSelected: boolean;
|
|
|
-};
|
|
|
-
|
|
|
-const USER_ACTIONS = [
|
|
|
- BreadcrumbType.ERROR,
|
|
|
- BreadcrumbType.INIT,
|
|
|
- BreadcrumbType.NAVIGATION,
|
|
|
- BreadcrumbType.UI,
|
|
|
- BreadcrumbType.USER,
|
|
|
-];
|
|
|
-
|
|
|
-function UserActionsNavigator({event, crumbs}: Props) {
|
|
|
+function Breadcrumbs({event, crumbs: allCrumbs}: Props) {
|
|
|
const {
|
|
|
setCurrentTime,
|
|
|
setCurrentHoverTime,
|
|
@@ -65,13 +50,14 @@ function UserActionsNavigator({event, crumbs}: Props) {
|
|
|
} = useReplayContext();
|
|
|
|
|
|
const startTimestamp = event?.startTimestamp || 0;
|
|
|
- const userActionCrumbs =
|
|
|
- crumbs?.filter(crumb => USER_ACTIONS.includes(crumb.type)) || [];
|
|
|
|
|
|
const isLoaded = Boolean(event);
|
|
|
|
|
|
+ const crumbs =
|
|
|
+ allCrumbs?.filter(crumb => !['console'].includes(crumb.category || '')) || [];
|
|
|
+
|
|
|
const currentUserAction = getPrevBreadcrumb({
|
|
|
- crumbs: userActionCrumbs,
|
|
|
+ crumbs,
|
|
|
targetTimestampMs: startTimestamp * 1000 + currentTime,
|
|
|
allowExact: true,
|
|
|
});
|
|
@@ -79,13 +65,13 @@ function UserActionsNavigator({event, crumbs}: Props) {
|
|
|
const closestUserAction =
|
|
|
currentHoverTime !== undefined
|
|
|
? getPrevBreadcrumb({
|
|
|
- crumbs: userActionCrumbs,
|
|
|
+ crumbs,
|
|
|
targetTimestampMs: startTimestamp * 1000 + (currentHoverTime ?? 0),
|
|
|
allowExact: true,
|
|
|
})
|
|
|
: undefined;
|
|
|
|
|
|
- const onMouseEnter = useCallback(
|
|
|
+ const handleMouseEnter = useCallback(
|
|
|
(item: Crumb) => {
|
|
|
if (startTimestamp) {
|
|
|
setCurrentHoverTime(relativeTimeInMs(item.timestamp ?? '', startTimestamp));
|
|
@@ -101,7 +87,7 @@ function UserActionsNavigator({event, crumbs}: Props) {
|
|
|
[setCurrentHoverTime, startTimestamp, highlight, clearAllHighlights]
|
|
|
);
|
|
|
|
|
|
- const onMouseLeave = useCallback(
|
|
|
+ const handleMouseLeave = useCallback(
|
|
|
(item: Crumb) => {
|
|
|
setCurrentHoverTime(undefined);
|
|
|
|
|
@@ -112,42 +98,33 @@ function UserActionsNavigator({event, crumbs}: Props) {
|
|
|
[setCurrentHoverTime, removeHighlight]
|
|
|
);
|
|
|
|
|
|
+ const handleClick = useCallback(
|
|
|
+ (crumb: Crumb) => {
|
|
|
+ crumb.timestamp !== undefined
|
|
|
+ ? setCurrentTime(relativeTimeInMs(crumb.timestamp, startTimestamp))
|
|
|
+ : null;
|
|
|
+ },
|
|
|
+ [setCurrentTime, startTimestamp]
|
|
|
+ );
|
|
|
+
|
|
|
return (
|
|
|
<Panel>
|
|
|
- <PanelHeader>{t('Event Chapters')}</PanelHeader>
|
|
|
+ <PanelHeader>{t('Breadcrumbs')}</PanelHeader>
|
|
|
|
|
|
<PanelBody>
|
|
|
{!isLoaded && <CrumbPlaceholder number={4} />}
|
|
|
{isLoaded &&
|
|
|
- userActionCrumbs.map(item => (
|
|
|
- <PanelItemCenter
|
|
|
- key={item.id}
|
|
|
- onMouseEnter={() => onMouseEnter(item)}
|
|
|
- onMouseLeave={() => onMouseLeave(item)}
|
|
|
- >
|
|
|
- <Container
|
|
|
- isHovered={closestUserAction?.id === item.id}
|
|
|
- isSelected={currentUserAction?.id === item.id}
|
|
|
- onClick={() =>
|
|
|
- item.timestamp !== undefined
|
|
|
- ? setCurrentTime(relativeTimeInMs(item.timestamp, startTimestamp))
|
|
|
- : null
|
|
|
- }
|
|
|
- >
|
|
|
- <Wrapper>
|
|
|
- <Type
|
|
|
- type={item.type}
|
|
|
- color={item.color}
|
|
|
- description={item.description}
|
|
|
- />
|
|
|
- <ActionCategory action={item} />
|
|
|
- </Wrapper>
|
|
|
- <PlayerRelativeTime
|
|
|
- relativeTime={startTimestamp}
|
|
|
- timestamp={item.timestamp}
|
|
|
- />
|
|
|
- </Container>
|
|
|
- </PanelItemCenter>
|
|
|
+ crumbs.map(crumb => (
|
|
|
+ <BreadcrumbItem
|
|
|
+ key={crumb.id}
|
|
|
+ crumb={crumb}
|
|
|
+ startTimestamp={startTimestamp}
|
|
|
+ isHovered={closestUserAction?.id === crumb.id}
|
|
|
+ isSelected={currentUserAction?.id === crumb.id}
|
|
|
+ onMouseEnter={handleMouseEnter}
|
|
|
+ onMouseLeave={handleMouseLeave}
|
|
|
+ onClick={handleClick}
|
|
|
+ />
|
|
|
))}
|
|
|
</PanelBody>
|
|
|
</Panel>
|
|
@@ -184,36 +161,9 @@ const PanelBody = styled(BasePanelBody)`
|
|
|
overflow-y: auto;
|
|
|
`;
|
|
|
|
|
|
-const PanelItemCenter = styled(PanelItem)`
|
|
|
- display: block;
|
|
|
- padding: ${space(0)};
|
|
|
- cursor: pointer;
|
|
|
-`;
|
|
|
-
|
|
|
-const Container = styled('button')<ContainerProps>`
|
|
|
- display: inline-flex;
|
|
|
- width: 100%;
|
|
|
- border: none;
|
|
|
- background: transparent;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- border-left: 4px solid transparent;
|
|
|
- padding: ${space(1)} ${space(1.5)};
|
|
|
- ${p => p.isHovered && `background: ${p.theme.surface400};`}
|
|
|
- ${p => p.isSelected && `border-left: 4px solid ${p.theme.purple300};`}
|
|
|
-`;
|
|
|
-
|
|
|
-const Wrapper = styled('div')`
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: ${space(1)};
|
|
|
- font-size: ${p => p.theme.fontSizeMedium};
|
|
|
- color: ${p => p.theme.gray500};
|
|
|
-`;
|
|
|
-
|
|
|
const PlaceholderMargin = styled(Placeholder)`
|
|
|
margin: ${space(1)} ${space(1.5)};
|
|
|
width: auto;
|
|
|
`;
|
|
|
|
|
|
-export default UserActionsNavigator;
|
|
|
+export default Breadcrumbs;
|