|
@@ -18,7 +18,6 @@ import * as qs from 'query-string';
|
|
|
import LoadingIndicator from 'sentry/components/loadingIndicator';
|
|
|
import {pickBarColor} from 'sentry/components/performance/waterfall/utils';
|
|
|
import Placeholder from 'sentry/components/placeholder';
|
|
|
-import {IconFire} from 'sentry/icons';
|
|
|
import {t} from 'sentry/locale';
|
|
|
import type {Organization, PlatformKey, Project} from 'sentry/types';
|
|
|
import {getDuration} from 'sentry/utils/formatters';
|
|
@@ -61,8 +60,6 @@ function Chevron(props: {direction: 'up' | 'down' | 'left'}) {
|
|
|
<svg
|
|
|
viewBox="0 0 16 16"
|
|
|
style={{
|
|
|
- fill: 'currentcolor',
|
|
|
- color: 'currentcolor',
|
|
|
transition: 'transform 120ms ease-in-out',
|
|
|
transform: `rotate(${props.direction === 'up' ? 0 : props.direction === 'down' ? 180 : -90}deg)`,
|
|
|
}}
|
|
@@ -72,6 +69,22 @@ function Chevron(props: {direction: 'up' | 'down' | 'left'}) {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+function Fire() {
|
|
|
+ return (
|
|
|
+ <svg viewBox="0 0 16 16">
|
|
|
+ <path d="M8.08,15.92A6.58,6.58,0,0,1,1.51,9.34a4.88,4.88,0,0,1,2.2-4.25.74.74,0,0,1,1,.34,6,6,0,0,1,4-5.3A.74.74,0,0,1,9.4.22a.73.73,0,0,1,.33.61v.31A15.07,15.07,0,0,0,10,4.93a3.72,3.72,0,0,1,2.3-1.7.74.74,0,0,1,.66.12.75.75,0,0,1,.3.6A6.21,6.21,0,0,0,14,6.79a5.78,5.78,0,0,1,.68,2.55A6.58,6.58,0,0,1,8.08,15.92ZM3.59,7.23A4.25,4.25,0,0,0,3,9.34a5.07,5.07,0,1,0,10.14,0,4.6,4.6,0,0,0-.54-1.94,8,8,0,0,1-.76-2.32A2,2,0,0,0,11.07,7a.75.75,0,0,1-1.32.58C8.4,6,8.25,4.22,8.23,2c-2,1.29-2.15,3.58-2.09,5.85A7.52,7.52,0,0,1,6.14,9a.74.74,0,0,1-.46.63.77.77,0,0,1-.76-.11A4.56,4.56,0,0,1,3.59,7.23Z" />
|
|
|
+ </svg>
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+function Profile() {
|
|
|
+ return (
|
|
|
+ <svg viewBox="0 0 20 16">
|
|
|
+ <path d="M15.25,0H.75C.33,0,0,.34,0,.75V5.59c0,.41,.34,.75,.75,.75h1.49v4.09c0,.41,.34,.75,.75,.75h1.73v4.09c0,.41,.34,.75,.75,.75h5.06c.41,0,.75-.34,.75-.75v-4.09h1.73c.41,0,.75-.34,.75-.75V6.34h1.49c.41,0,.75-.34,.75-.75V.75c0-.41-.34-.75-.75-.75Zm-5.47,14.52h-3.56v-3.34h3.56v3.34Zm2.48-4.84H3.74v-3.34H12.25v3.34Zm2.24-4.84H1.5V1.5H14.5v3.34Z" />
|
|
|
+ </svg>
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
function decodeScrollQueue(maybePath: unknown): TraceTree.NodePath[] | null {
|
|
|
if (Array.isArray(maybePath)) {
|
|
|
return maybePath;
|
|
@@ -792,6 +805,7 @@ function RenderRow(props: {
|
|
|
node_spaces={props.node.autogroupedSegments}
|
|
|
errors={props.node.errors}
|
|
|
performance_issues={props.node.performance_issues}
|
|
|
+ profiles={props.node.profiles}
|
|
|
/>
|
|
|
<button
|
|
|
ref={ref =>
|
|
@@ -907,6 +921,7 @@ function RenderRow(props: {
|
|
|
node_space={props.node.space}
|
|
|
errors={props.node.value.errors}
|
|
|
performance_issues={props.node.value.performance_issues}
|
|
|
+ profiles={props.node.profiles}
|
|
|
/>
|
|
|
<button
|
|
|
ref={ref =>
|
|
@@ -1023,6 +1038,7 @@ function RenderRow(props: {
|
|
|
node_space={props.node.space}
|
|
|
errors={props.node.value.errors}
|
|
|
performance_issues={props.node.value.performance_issues}
|
|
|
+ profiles={NO_ERRORS}
|
|
|
/>
|
|
|
<button
|
|
|
ref={ref =>
|
|
@@ -1097,8 +1113,9 @@ function RenderRow(props: {
|
|
|
manager={props.manager}
|
|
|
color={pickBarColor('missing-instrumentation')}
|
|
|
node_space={props.node.space}
|
|
|
- errors={NO_ERRORS}
|
|
|
performance_issues={NO_ERRORS}
|
|
|
+ profiles={NO_ERRORS}
|
|
|
+ errors={NO_ERRORS}
|
|
|
/>
|
|
|
<button
|
|
|
ref={ref =>
|
|
@@ -1185,6 +1202,7 @@ function RenderRow(props: {
|
|
|
node_space={props.node.space}
|
|
|
errors={NO_ERRORS}
|
|
|
performance_issues={NO_ERRORS}
|
|
|
+ profiles={NO_ERRORS}
|
|
|
/>
|
|
|
<button
|
|
|
ref={ref =>
|
|
@@ -1266,7 +1284,7 @@ function RenderRow(props: {
|
|
|
>
|
|
|
{typeof props.node.value.timestamp === 'number' ? (
|
|
|
<div className="TraceError">
|
|
|
- <IconFire color="errorText" size="xs" />
|
|
|
+ <Fire />
|
|
|
</div>
|
|
|
) : null}
|
|
|
</InvisibleTraceBar>
|
|
@@ -1435,8 +1453,8 @@ interface TraceBarProps {
|
|
|
manager: VirtualizedViewManager;
|
|
|
node_space: [number, number] | null;
|
|
|
performance_issues: TraceTreeNode<TraceTree.Transaction>['value']['performance_issues'];
|
|
|
+ profiles: TraceTreeNode<TraceTree.NodeValue>['profiles'];
|
|
|
virtualized_index: number;
|
|
|
- duration?: number;
|
|
|
}
|
|
|
|
|
|
function TraceBar(props: TraceBarProps) {
|
|
@@ -1467,6 +1485,13 @@ function TraceBar(props: TraceBarProps) {
|
|
|
} as React.CSSProperties
|
|
|
}
|
|
|
>
|
|
|
+ {props.profiles.length > 0 ? (
|
|
|
+ <Profiles
|
|
|
+ node_space={props.node_space}
|
|
|
+ profiles={props.profiles}
|
|
|
+ manager={props.manager}
|
|
|
+ />
|
|
|
+ ) : null}
|
|
|
{props.errors.length > 0 ? (
|
|
|
<Errors
|
|
|
node_space={props.node_space}
|
|
@@ -1571,7 +1596,7 @@ function PerformanceIssues(props: PerformanceIssuesProps) {
|
|
|
style={{left: left * 100 + '%', width: width + '%'}}
|
|
|
>
|
|
|
<div className="TraceError" style={{left: 0}}>
|
|
|
- <IconFire color="errorText" size="xs" />
|
|
|
+ <Fire />
|
|
|
</div>
|
|
|
</div>
|
|
|
);
|
|
@@ -1587,6 +1612,10 @@ interface ErrorsProps {
|
|
|
}
|
|
|
|
|
|
function Errors(props: ErrorsProps) {
|
|
|
+ if (!props.errors.length) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
return (
|
|
|
<Fragment>
|
|
|
{props.errors.map((error, _i) => {
|
|
@@ -1607,7 +1636,45 @@ function Errors(props: ErrorsProps) {
|
|
|
className="TraceError"
|
|
|
style={{left: left * 100 + '%'}}
|
|
|
>
|
|
|
- <IconFire color="errorText" size="xs" />
|
|
|
+ <Fire />
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ })}
|
|
|
+ </Fragment>
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+interface ProfilesProps {
|
|
|
+ manager: VirtualizedViewManager;
|
|
|
+ node_space: [number, number] | null;
|
|
|
+ profiles: TraceTree.Profile[];
|
|
|
+}
|
|
|
+
|
|
|
+function Profiles(props: ProfilesProps) {
|
|
|
+ if (!props.profiles.length) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return (
|
|
|
+ <Fragment>
|
|
|
+ {props.profiles.map((profile, _i) => {
|
|
|
+ const timestamp = profile.space[0];
|
|
|
+ // Clamp the profile timestamp to the span's timestamp
|
|
|
+ const left = props.manager.computeRelativeLeftPositionFromOrigin(
|
|
|
+ clamp(
|
|
|
+ timestamp,
|
|
|
+ props.node_space![0],
|
|
|
+ props.node_space![0] + props.node_space![1]
|
|
|
+ ),
|
|
|
+ props.node_space!
|
|
|
+ );
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div
|
|
|
+ key={profile.profile_id}
|
|
|
+ className="TraceProfile"
|
|
|
+ style={{left: left * 100 + '%'}}
|
|
|
+ >
|
|
|
+ <Profile />
|
|
|
</div>
|
|
|
);
|
|
|
})}
|
|
@@ -1622,8 +1689,8 @@ interface AutogroupedTraceBarProps {
|
|
|
manager: VirtualizedViewManager;
|
|
|
node_spaces: [number, number][];
|
|
|
performance_issues: TraceTreeNode<TraceTree.Transaction>['value']['performance_issues'];
|
|
|
+ profiles: TraceTreeNode<TraceTree.NodeValue>['profiles'];
|
|
|
virtualized_index: number;
|
|
|
- duration?: number;
|
|
|
}
|
|
|
|
|
|
function AutogroupedTraceBar(props: AutogroupedTraceBarProps) {
|
|
@@ -1634,9 +1701,9 @@ function AutogroupedTraceBar(props: AutogroupedTraceBarProps) {
|
|
|
node_space={props.entire_space}
|
|
|
manager={props.manager}
|
|
|
virtualized_index={props.virtualized_index}
|
|
|
- duration={props.duration}
|
|
|
errors={props.errors}
|
|
|
performance_issues={props.performance_issues}
|
|
|
+ profiles={props.profiles}
|
|
|
/>
|
|
|
);
|
|
|
}
|
|
@@ -1686,7 +1753,13 @@ function AutogroupedTraceBar(props: AutogroupedTraceBarProps) {
|
|
|
/>
|
|
|
);
|
|
|
})}
|
|
|
-
|
|
|
+ {props.profiles.length > 0 ? (
|
|
|
+ <Profiles
|
|
|
+ node_space={props.entire_space}
|
|
|
+ profiles={props.profiles}
|
|
|
+ manager={props.manager}
|
|
|
+ />
|
|
|
+ ) : null}
|
|
|
{props.errors.length > 0 ? (
|
|
|
<Errors
|
|
|
node_space={props.entire_space}
|
|
@@ -1908,6 +1981,24 @@ const TraceStylingWrapper = styled('div')`
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ .TraceProfile {
|
|
|
+ position: absolute;
|
|
|
+ top: 50%;
|
|
|
+ transform: translate(-50%, -50%) scaleX(var(--inverse-span-scale));
|
|
|
+ background: ${p => p.theme.background};
|
|
|
+ width: 18px !important;
|
|
|
+ height: 18px !important;
|
|
|
+ background-color: ${p => p.theme.purple300};
|
|
|
+ border-radius: 50%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+
|
|
|
+ svg {
|
|
|
+ fill: ${p => p.theme.white};
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
.TracePerformanceIssue {
|
|
|
position: absolute;
|
|
|
top: 0;
|
|
@@ -2066,6 +2157,11 @@ const TraceStylingWrapper = styled('div')`
|
|
|
transform: translate(-50%, 0);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ svg {
|
|
|
+ width: 14px;
|
|
|
+ height: 14px;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
.TraceArrow {
|