import {Fragment} from 'react';
import styled from '@emotion/styled';
import DateTime from 'sentry/components/dateTime';
import {Tooltip} from 'sentry/components/tooltip';
import {t} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import type {Event} from 'sentry/types';
import {TraceTimelineTooltip} from 'sentry/views/issueDetails/traceTimeline/traceTimelineTooltip';
import type {TimelineEvent} from './useTraceTimelineEvents';
import {useTraceTimelineEvents} from './useTraceTimelineEvents';
import {getChunkTimeRange, getEventsByColumn} from './utils';
// Adjusting this will change the number of tooltip groups
const PARENT_WIDTH = 12;
// Adjusting subwidth changes how many dots to render
const CHILD_WIDTH = 4;
interface TraceTimelineEventsProps {
event: Event;
width: number;
}
export function TraceTimelineEvents({event, width}: TraceTimelineEventsProps) {
const {startTimestamp, endTimestamp, data} = useTraceTimelineEvents({event});
let durationMs = endTimestamp - startTimestamp;
const paddedStartTime = startTimestamp - 200;
let paddedEndTime = endTimestamp + 100;
// Will need to figure out padding
if (durationMs === 0) {
durationMs = 1000;
// If the duration is 0, we need to pad the end time
paddedEndTime = startTimestamp + 1000;
}
const totalColumns = Math.floor(width / PARENT_WIDTH);
const eventsByColumn = getEventsByColumn(
durationMs,
data,
totalColumns,
paddedStartTime
);
const columnSize = width / totalColumns;
return (
{Array.from(eventsByColumn.entries()).map(([column, colEvents]) => {
// Calculate the timestamp range that this column represents
const timeRange = getChunkTimeRange(
paddedStartTime,
column - 1,
durationMs / totalColumns
);
return (
);
})}
);
}
/**
* Use grid to create columns that we can place child nodes into.
* Leveraging grid for alignment means we don't need to calculate percent offset
* nor use position:absolute to lay out items.
*
*
* ...
* ...
*
*/
const TimelineColumns = styled('ul')<{totalColumns: number}>`
/* Reset defaults for
*/
list-style: none;
margin: 0;
padding: 0;
/* Layout of the lines */
display: grid;
grid-template-columns: repeat(${p => p.totalColumns}, 1fr);
margin-top: -1px;
`;
const TimestampColumns = styled('div')`
display: grid;
grid-template-columns: repeat(3, 1fr);
margin-top: ${space(1)};
`;
const TimestampItem = styled('div')`
place-items: stretch;
display: grid;
align-items: center;
position: relative;
color: ${p => p.theme.subText};
font-size: ${p => p.theme.fontSizeSmall};
`;
function NodeGroup({
event,
timeRange,
colEvents,
columnSize,
currentEventId,
}: {
colEvents: TimelineEvent[];
columnSize: number;
currentEventId: string;
event: Event;
timeRange: [number, number];
}) {
const totalSubColumns = Math.floor(columnSize / CHILD_WIDTH);
const durationMs = timeRange[1] - timeRange[0];
const eventsByColumn = getEventsByColumn(
durationMs,
colEvents,
totalSubColumns,
timeRange[0]
);
return (
}
overlayStyle={{
padding: `0 !important`,
maxWidth: '250px !important',
width: '250px',
}}
offset={10}
position="bottom"
isHoverable
skipWrapper
>
{Array.from(eventsByColumn.entries()).map(([column, groupEvents]) => (
{groupEvents.map(groupEvent => (
// TODO: use sentry colors and add the other styles
))}
))}
);
}
const EventColumn = styled('li')`
place-items: stretch;
display: grid;
align-items: center;
position: relative;
&:hover {
z-index: ${p => p.theme.zIndex.initial};
}
`;
const IconNode = styled('div')`
position: absolute;
grid-column: 1;
grid-row: 1;
width: 8px;
height: 8px;
border-radius: 50%;
color: ${p => p.theme.white};
box-shadow: ${p => p.theme.dropShadowLight};
user-select: none;
background-color: rgb(181, 19, 7, 0.2);
`;