Skip to content

feat(trace-view): Info panel tab for new users #82408

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
import styled from '@emotion/styled';

import image from 'sentry-images/spot/tracing-keyboard-shortcuts.svg';

import ExternalLink from 'sentry/components/links/externalLink';
import {IconDocs} from 'sentry/icons';
import {t} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import {
KEYBOARD_SHORTCUTS,
Shortcuts,
ShortcutsLayout,
TIMELINE_SHORTCUTS,
} from 'sentry/views/performance/newTraceDetails/traceShortcutsModal';

export function TraceIntroductionView() {
return (
<MainContainer>
<HeaderContainer>
<TitleWrapper>
<Title>{t('Trace All The Things')}</Title>
<Subtitle>{t('Intro to Workflows & Shortcuts')}</Subtitle>
</TitleWrapper>
<IconDocs size="sm" />
</HeaderContainer>

<ContentWrapper>
<InfoText>
<p>
{t(
`If you’re seeing this, it means you’ve successfully set up Tracing in your SDK. Nice!`
)}
</p>

<p>
<strong>{t('What is this? ')}</strong>
{t(`
A trace is a map of everything that happens when a request moves through your stack—browser sessions, function calls, db queries, and third-party api requests.
Each recorded step is a “span” with timestamps and metadata. Put these spans together, and you get a “trace” showing how your system handled the request from start to finish.
`)}
</p>

<p>
<strong>{t('Why is this useful? ')}</strong>
{t(`
When something slows down or breaks, you won’t need to guess where the problem is hidden in your code.
You get a precise view into the entire chain of events so you can see context that you might not get in an exception handler.
`)}
</p>

<p>
<strong>{t('Learn how to use Tracing:')}</strong>
</p>
</InfoText>

<LinksWithImage>
<LinkSection />
<ImageWrapper src={image} alt={t('Sentry cant fix this')} />
</LinksWithImage>

<p>
<strong>{t('Ways to utilize Tracing:')}</strong>
</p>

<SecondaryLinkSection />

<ShortcutSection>
<ShortcutsLayout>
<div>
<Shortcuts>
{KEYBOARD_SHORTCUTS.map(([key, description]) => (
<Shortcut key={key}>
<strong>{key}</strong>
<div>{description}</div>
</Shortcut>
))}
{TIMELINE_SHORTCUTS.map(([key, description]) => (
<Shortcut key={key}>
<strong>{key}</strong>
<div>{description}</div>
</Shortcut>
))}
</Shortcuts>
</div>
</ShortcutsLayout>
</ShortcutSection>
</ContentWrapper>
</MainContainer>
);
}

function SecondaryLinkSection() {
return (
<StyledList>
<li>
<ExternalLink
openInNewTab
href="https://blog.sentry.io/observability-and-tracing-how-to-improve-your-debugging-workflow/"
>
{t('Debug faster, improve performance, and fix Core Web Vitals issues')}
</ExternalLink>
</li>
<li>
<ExternalLink
openInNewTab
href="https://blog.sentry.io/how-to-identify-fetch-waterfalls-in-react/"
>
{t('Fixing Fetch waterfalls / common slowdowns in React')}
</ExternalLink>
</li>
<li>
<ExternalLink
openInNewTab
href="https://blog.sentry.io/how-i-cut-22-3-seconds-off-an-api-call-using-trace-view/"
>
{t('Trimming 22 seconds off a GenAI operation')}
</ExternalLink>
</li>
<li>
<ExternalLink
openInNewTab
href="https://blog.sentry.io/how-i-reduced-an-api-call-from-greater-than-5-seconds-to-under-100ms/"
>
{t('Optimizing API calls from 5s to <100ms with Distributed Tracing ')}
</ExternalLink>
</li>
<li>
<ExternalLink
openInNewTab
href="https://blog.sentry.io/fix-your-actual-slow-loading-assets-with-resource-monitoring/"
>
{t('Finding & fixing slow-loading assets')}
</ExternalLink>
</li>
<li>
<ExternalLink
openInNewTab
href="https://blog.sentry.io/your-bad-lcp-score-might-be-a-backend-issue/"
>
{t('Fixing bad LCP scores')}
</ExternalLink>
</li>
</StyledList>
);
}

function LinkSection() {
return (
<StyledList>
<li>
<ExternalLink
openInNewTab
href="https://blog.sentry.io/everyone-needs-to-know-how-to-trace/"
>
{t('What is Tracing, and how do I use it to debug?')}
</ExternalLink>
</li>
<li>
<ExternalLink
openInNewTab
href="https://docs.sentry.io/product/tracing/#how-to-use-tracing-in-sentry"
>
{t('Product Walkthrough: Tracing')}
</ExternalLink>
</li>
<li>
<ExternalLink
openInNewTab
href="https://docs.sentry.io/concepts/key-terms/tracing/distributed-tracing/#what-is-distributed-tracing"
>
{t('What is Distributed Tracing?')}
</ExternalLink>
</li>
<li>
<ExternalLink
openInNewTab
href="https://blog.sentry.io/my-errors-are-gone-with-a-trace/"
>
{t('How does tracing show helpful context not found in errors?')}
</ExternalLink>
</li>
<li>
<ExternalLink openInNewTab href="https://docs.sentry.io/product/explore/traces/">
{t('Learn how to find trends with the Trace Explorer')}
</ExternalLink>
</li>
<li>
<ExternalLink
openInNewTab
href="https://blog.sentry.io/backend-insights-with-caches-queues-requests-queries/"
>
{t('Identifying backend issues with Performance Insights')}
</ExternalLink>
</li>
<li>
<ExternalLink openInNewTab href="https://docs.sentry.io/product/performance/">
{t('How are Performance Monitoring & Traces related?')}
</ExternalLink>
</li>
</StyledList>
);
}

const MainContainer = styled('div')`
display: flex;
flex-direction: column;
padding: ${space(3)};
`;

const HeaderContainer = styled('div')`
display: flex;
flex-direction: row;
justify-content: space-between;
`;

const TitleWrapper = styled('div')`
display: flex;
flex-direction: column;
margin-bottom: ${space(2)};
`;

const Title = styled('div')`
font-size: ${p => p.theme.fontSizeExtraLarge};
font-weight: ${p => p.theme.fontWeightBold};
`;

const Subtitle = styled('div')`
font-size: ${p => p.theme.fontSizeMedium};
font-weight: ${p => p.theme.fontWeightNormal};
color: ${p => p.theme.subText};
`;

const ContentWrapper = styled('div')`
display: flex;
flex-direction: column;

font-size: ${p => p.theme.fontSizeMedium};
`;

const InfoText = styled('div')``;

const LinksWithImage = styled('div')`
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;

margin-bottom: ${space(3)};
`;

const StyledList = styled('ul')`
min-width: 200px;
color: ${p => p.theme.blue300};
`;

const ImageWrapper = styled('img')`
max-width: 400px;
max-height: 400px;

min-width: 100px;
min-height: 100px;
`;

const ShortcutSection = styled('div')`
border: 1px solid ${p => p.theme.border};
border-radius: ${p => p.theme.borderRadius};
padding: ${space(2)};
`;

const Shortcut = styled('li')`
height: 28px;
display: grid;
grid-template-columns: min-content 1fr;

strong {
display: inline-block;
min-width: 130px;
}

div {
min-width: 150px;
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,14 @@ import pick from 'lodash/pick';

import type {Tag} from 'sentry/actionCreators/events';
import {Button} from 'sentry/components/button';
import {IconChevron, IconCircleFill, IconClose, IconPanel, IconPin} from 'sentry/icons';
import {
IconChevron,
IconCircleFill,
IconClose,
IconInfo,
IconPanel,
IconPin,
} from 'sentry/icons';
import {t} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import type {EventTransaction} from 'sentry/types/event';
Expand All @@ -21,6 +28,7 @@ import type RequestError from 'sentry/utils/requestError/requestError';
import type {Color} from 'sentry/utils/theme';
import {useLocation} from 'sentry/utils/useLocation';
import useOrganization from 'sentry/utils/useOrganization';
import {TraceIntroductionView} from 'sentry/views/performance/newTraceDetails/traceDrawer/details/traceIntroductionView';
import type {ReplayRecord} from 'sentry/views/replays/types';

import {traceAnalytics} from '../traceAnalytics';
Expand Down Expand Up @@ -459,6 +467,8 @@ export function TraceDrawer(props: TraceDrawerProps) {
tree={props.trace}
onScrollToNode={props.onScrollToNode}
/>
) : traceState.tabs.current_tab.node === 'help' ? (
<TraceIntroductionView />
) : (
<TraceTreeNodeDetails
replay={props.replay}
Expand Down Expand Up @@ -503,7 +513,11 @@ function TraceDrawerTab(props: TraceDrawerTabProps) {
props.tab === props.trace_state.tabs.current_tab ? 'true' : 'false'
}
onClick={() => {
if (props.tab.node !== 'vitals' && props.tab.node !== 'profiles') {
if (
props.tab.node !== 'vitals' &&
props.tab.node !== 'profiles' &&
props.tab.node !== 'help'
) {
traceAnalytics.trackTabView(node, organization);
props.onTabScrollToNode(root);
}
Expand All @@ -513,11 +527,15 @@ function TraceDrawerTab(props: TraceDrawerTabProps) {
{/* A trace is technically an entry in the list, so it has a color */}
{props.tab.node === 'trace' ||
props.tab.node === 'vitals' ||
props.tab.node === 'profiles' ? null : (
props.tab.node === 'profiles' ||
props.tab.node === 'help' ? null : (
<TabButtonIndicator
backgroundColor={makeTraceNodeBarColor(props.theme, root)}
/>
)}
{props.tab.node === 'help' && (
<IconInfo size="xs" style={{marginRight: space(0.25)}} />
)}
<TabButton>{props.tab.label ?? node}</TabButton>
</Tab>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ export function isTraceNode(
);
}

export function isHelpNode(
node: TraceTreeNode<TraceTree.NodeValue>
): node is TraceTreeNode<TraceTree.Help> {
return !!(node.value && 'type' in node.value && node.value.type === 'help');
}

export function shouldAddMissingInstrumentationSpan(sdk: string | undefined): boolean {
if (!sdk) {
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ export declare namespace TraceTree {
};
type Root = null;

interface Help {
type: 'help';
}

// All possible node value types
type NodeValue =
| Trace
Expand All @@ -147,8 +151,8 @@ export declare namespace TraceTree {
| SiblingAutogroup
| ChildrenAutogroup
| CollapsedNode
| Root;

| Root
| Help;
interface CollapsedNode {
type: 'collapsed';
}
Expand Down
Loading
Loading