123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- import {CSSProperties, forwardRef} from 'react';
- import styled from '@emotion/styled';
- import FileSize from 'sentry/components/fileSize';
- import {useReplayContext} from 'sentry/components/replays/replayContext';
- import {relativeTimeInMs} from 'sentry/components/replays/utils';
- import {Tooltip} from 'sentry/components/tooltip';
- import space from 'sentry/styles/space';
- import useSortNetwork from 'sentry/views/replays/detail/network/useSortNetwork';
- import TimestampButton from 'sentry/views/replays/detail/timestampButton';
- import type {NetworkSpan} from 'sentry/views/replays/types';
- const EMPTY_CELL = '\u00A0';
- type Props = {
- columnIndex: number;
- handleClick: (span: NetworkSpan) => void;
- handleMouseEnter: (span: NetworkSpan) => void;
- handleMouseLeave: (span: NetworkSpan) => void;
- isCurrent: boolean;
- isHovered: boolean;
- sortConfig: ReturnType<typeof useSortNetwork>['sortConfig'];
- span: NetworkSpan;
- startTimestampMs: number;
- style: CSSProperties;
- };
- function NetworkTableCell({
- columnIndex,
- handleClick,
- handleMouseEnter,
- handleMouseLeave,
- isCurrent,
- isHovered,
- sortConfig,
- span,
- startTimestampMs,
- style,
- }: Props) {
- const {currentTime} = useReplayContext();
- const startMs = span.startTimestamp * 1000;
- const endMs = span.endTimestamp * 1000;
- const statusCode = span.data.statusCode;
- const isByTimestamp = sortConfig.by === 'startTimestamp';
- const columnProps = {
- hasOccurred: isByTimestamp
- ? currentTime >= relativeTimeInMs(span.startTimestamp * 1000, startTimestampMs)
- : undefined,
- hasOccurredAsc: isByTimestamp ? sortConfig.asc : undefined,
- isCurrent,
- isHovered,
- isStatusError: typeof statusCode === 'number' && statusCode >= 400,
- onMouseEnter: () => handleMouseEnter(span),
- onMouseLeave: () => handleMouseLeave(span),
- style,
- };
- const renderFns = [
- () => (
- <Cell {...columnProps}>
- <Text>{statusCode ? statusCode : EMPTY_CELL}</Text>
- </Cell>
- ),
- () => (
- <Cell {...columnProps}>
- <Tooltip
- title={span.description}
- isHoverable
- showOnlyOnOverflow
- overlayStyle={{maxWidth: '500px !important'}}
- >
- <Text>{span.description || EMPTY_CELL}</Text>
- </Tooltip>
- </Cell>
- ),
- () => (
- <Cell {...columnProps}>
- <Tooltip title={span.op.replace('resource.', '')} isHoverable showOnlyOnOverflow>
- <Text>{span.op.replace('resource.', '')}</Text>
- </Tooltip>
- </Cell>
- ),
- () => (
- <Cell {...columnProps} numeric>
- <Text>
- {span.data.size === undefined ? (
- EMPTY_CELL
- ) : (
- <FileSize bytes={span.data.size} />
- )}
- </Text>
- </Cell>
- ),
- () => (
- <Cell {...columnProps} numeric>
- <Text>{`${(endMs - startMs).toFixed(2)}ms`}</Text>
- </Cell>
- ),
- () => (
- <Cell {...columnProps} numeric>
- <TimestampButton
- format="mm:ss.SSS"
- onClick={() => handleClick(span)}
- startTimestampMs={startTimestampMs}
- timestampMs={startMs}
- />
- </Cell>
- ),
- ];
- return renderFns[columnIndex]();
- }
- const cellBackground = p => {
- if (p.hasOccurred === undefined && !p.isStatusError) {
- return `background-color: ${p.isHovered ? p.theme.hover : 'inherit'};`;
- }
- const color = p.isStatusError ? p.theme.alert.error.backgroundLight : 'inherit';
- return `background-color: ${color};`;
- };
- const cellBorder = p => {
- if (p.hasOccurred === undefined) {
- return null;
- }
- const color = p.isCurrent
- ? p.theme.purple300
- : p.isHovered
- ? p.theme.purple200
- : 'transparent';
- return p.hasOccurredAsc
- ? `border-bottom: 1px solid ${color};`
- : `border-top: 1px solid ${color};`;
- };
- const cellColor = p => {
- const colors = p.isStatusError
- ? [p.theme.alert.error.borderHover, p.theme.alert.error.iconColor]
- : ['inherit', p.theme.gray300];
- if (p.hasOccurred === undefined) {
- return `color: ${colors[0]};`;
- }
- return `color: ${p.hasOccurred ? colors[0] : colors[1]};`;
- };
- const Cell = styled('div')<{
- hasOccurred: boolean | undefined;
- hasOccurredAsc: boolean | undefined;
- isCurrent: boolean;
- isHovered: boolean;
- isStatusError: boolean;
- numeric?: boolean;
- }>`
- display: flex;
- align-items: center;
- padding: ${space(0.75)} ${space(1.5)};
- font-size: ${p => p.theme.fontSizeSmall};
- ${cellBackground}
- ${cellBorder}
- ${cellColor}
- ${p =>
- p.numeric &&
- `
- font-variant-numeric: tabular-nums;
- justify-content: flex-end;
- `};
- `;
- const Text = styled('div')`
- text-overflow: ellipsis;
- white-space: nowrap;
- overflow: hidden;
- `;
- export default forwardRef<HTMLDivElement, Props>(NetworkTableCell);
|