Skip to content
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

feat(apm): Virtual horizontal scrollbar for span view #22504

Merged
merged 12 commits into from
Dec 8, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ import React from 'react';
import styled from '@emotion/styled';

import space from 'app/styles/space';
import {SentryTransactionEvent} from 'app/types';

import * as CursorGuideHandler from './cursorGuideHandler';
import * as DividerHandlerManager from './dividerHandlerManager';
import {DragManagerChildrenProps} from './dragManager';
import MeasurementsPanel from './measurementsPanel';
import * as ScrollbarManager from './scrollbarManager';
import {zIndex} from './styles';
import {
ParsedTraceType,
Expand All @@ -24,17 +28,21 @@ import {
toPercent,
} from './utils';

export const MINIMAP_CONTAINER_HEIGHT = 106;
export const MINIMAP_SPAN_BAR_HEIGHT = 4;
const MINIMAP_HEIGHT = 120;
export const NUM_OF_SPANS_FIT_IN_MINI_MAP = MINIMAP_HEIGHT / MINIMAP_SPAN_BAR_HEIGHT;
const TIME_AXIS_HEIGHT = 20;
const VIEW_HANDLE_HEIGHT = 18;
const SECONDARY_HEADER_HEIGHT = 20;
export const MINIMAP_CONTAINER_HEIGHT =
MINIMAP_HEIGHT + TIME_AXIS_HEIGHT + SECONDARY_HEADER_HEIGHT + 1;

type PropType = {
minimapInteractiveRef: React.RefObject<HTMLDivElement>;
virtualScrollBarContainerRef: React.RefObject<HTMLDivElement>;
dragProps: DragManagerChildrenProps;
trace: ParsedTraceType;
event: SentryTransactionEvent;
};

class TraceViewHeader extends React.Component<PropType> {
Expand Down Expand Up @@ -266,6 +274,65 @@ class TraceViewHeader extends React.Component<PropType> {
);
}

generateBounds() {
const {dragProps, trace} = this.props;

return boundsGenerator({
traceStartTimestamp: trace.traceStartTimestamp,
traceEndTimestamp: trace.traceEndTimestamp,
viewStart: dragProps.viewWindowStart,
viewEnd: dragProps.viewWindowEnd,
});
}

renderSecondaryHeader() {
const {event} = this.props;

const hasMeasurements = Object.keys(event.measurements ?? {}).length > 0;

return (
<DividerHandlerManager.Consumer>
{dividerHandlerChildrenProps => {
const {dividerPosition} = dividerHandlerChildrenProps;

return (
<SecondaryHeader>
<ScrollBarContainer
ref={this.props.virtualScrollBarContainerRef}
style={{
// the width of this component is shrunk to compensate for half of the width of the divider line
width: `calc(${toPercent(dividerPosition)} - 0.5px)`,
}}
>
<ScrollbarManager.Consumer>
{({virtualScrollbarRef, onDragStart}) => {
return (
<VirtualScrollBar
data-type="virtual-scrollbar"
ref={virtualScrollbarRef}
onMouseDown={onDragStart}
>
<VirtualScrollBarGrip />
</VirtualScrollBar>
);
}}
</ScrollbarManager.Consumer>
</ScrollBarContainer>
<DividerSpacer />
{hasMeasurements ? (
<MeasurementsPanel
event={event}
generateBounds={this.generateBounds()}
dividerPosition={dividerPosition}
/>
) : null}
</SecondaryHeader>
);
}}
</DividerHandlerManager.Consumer>
);
}

render() {
return (
<HeaderContainer>
Expand Down Expand Up @@ -322,6 +389,7 @@ class TraceViewHeader extends React.Component<PropType> {
</div>
)}
</CursorGuideHandler.Consumer>
{this.renderSecondaryHeader()}
</HeaderContainer>
);
}
Expand Down Expand Up @@ -484,7 +552,7 @@ const TimeAxis = styled('div')`
width: 100%;
position: absolute;
left: 0;
bottom: 0;
top: ${MINIMAP_HEIGHT}px;
border-top: 1px solid ${p => p.theme.border};
height: ${TIME_AXIS_HEIGHT}px;
background-color: ${p => p.theme.background};
Expand Down Expand Up @@ -580,7 +648,7 @@ const HeaderContainer = styled('div')`
z-index: ${zIndex.minimapContainer};
background-color: ${p => p.theme.background};
border-bottom: 1px solid ${p => p.theme.border};
height: ${MINIMAP_HEIGHT + TIME_AXIS_HEIGHT + 1}px;
height: ${MINIMAP_CONTAINER_HEIGHT}px;
`;

const MinimapBackground = styled('div')`
Expand Down Expand Up @@ -683,4 +751,52 @@ const WindowSelection = styled('div')`
background-color: rgba(69, 38, 80, 0.1);
`;

const SecondaryHeader = styled('div')`
position: absolute;
top: ${MINIMAP_HEIGHT + TIME_AXIS_HEIGHT}px;
left: 0;
height: ${TIME_AXIS_HEIGHT}px;
width: 100%;
background-color: ${p => p.theme.backgroundSecondary};
display: flex;
border-top: 1px solid ${p => p.theme.border};
`;

const DividerSpacer = styled('div')`
width: 1px;
background-color: ${p => p.theme.gray200};
`;

const ScrollBarContainer = styled('div')`
display: flex;
align-items: center;
width: 100%;
height: ${SECONDARY_HEADER_HEIGHT}px;
left: 0;
bottom: 0;
& > div[data-type='virtual-scrollbar'].dragging > div {
background-color: ${p => p.theme.gray500};
cursor: grabbing;
}
`;

const VirtualScrollBar = styled('div')`
height: 8px;
width: 0;
padding-left: 4px;
padding-right: 4px;
position: relative;
top: 0;
left: 0;
cursor: grab;
`;

const VirtualScrollBarGrip = styled('div')`
height: 8px;
width: 100%;
border-radius: 20px;
transition: background-color 150ms ease;
background-color: rgba(48, 40, 57, 0.5);
`;

export default TraceViewHeader;

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
WEB_VITAL_ACRONYMS,
} from 'app/views/performance/transactionVitals/constants';

import * as MeasurementsManager from './measurementsManager';
import {
getMeasurementBounds,
getMeasurements,
Expand Down Expand Up @@ -47,8 +46,6 @@ class MeasurementsPanel extends React.PureComponent<Props> {

const names = Object.keys(verticalMark.marks);

const hoverMeasurementName = names.join('');

// generate vertical marker label
const acronyms = names.map(name => WEB_VITAL_ACRONYMS[name]);
const lastAcronym = acronyms.pop() as string;
Expand All @@ -64,25 +61,13 @@ class MeasurementsPanel extends React.PureComponent<Props> {
: lastName;

return (
<MeasurementsManager.Consumer key={String(timestamp)}>
{({hoveringMeasurement, notHovering}) => {
return (
<LabelContainer
key={label}
failedThreshold={verticalMark.failedThreshold}
label={label}
tooltipLabel={tooltipLabel}
left={toPercent(bounds.left || 0)}
onMouseLeave={() => {
notHovering();
}}
onMouseOver={() => {
hoveringMeasurement(hoverMeasurementName);
}}
/>
);
}}
</MeasurementsManager.Consumer>
<LabelContainer
key={String(timestamp)}
failedThreshold={verticalMark.failedThreshold}
label={label}
tooltipLabel={tooltipLabel}
left={toPercent(bounds.left || 0)}
/>
);
})}
</Container>
Expand Down Expand Up @@ -118,8 +103,6 @@ type LabelContainerProps = {
left: string;
label: string;
tooltipLabel: string;
onMouseLeave: () => void;
onMouseOver: () => void;
failedThreshold: boolean;
};

Expand All @@ -145,27 +128,14 @@ class LabelContainer extends React.Component<LabelContainerProps> {
elementDOMRef = React.createRef<HTMLDivElement>();

render() {
const {
left,
onMouseLeave,
onMouseOver,
label,
tooltipLabel,
failedThreshold,
} = this.props;
const {left, label, tooltipLabel, failedThreshold} = this.props;

return (
<StyledLabelContainer
ref={this.elementDOMRef}
style={{
left: `clamp(calc(0.5 * ${this.state.width}px), ${left}, calc(100% - 0.5 * ${this.state.width}px))`,
}}
onMouseLeave={() => {
onMouseLeave();
}}
onMouseOver={() => {
onMouseOver();
}}
>
<Label failedThreshold={failedThreshold}>
<Tooltip
Expand Down
Loading