traceRow.tsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import {Fragment} from 'react';
  2. import type {Theme} from '@emotion/react';
  3. import LoadingIndicator from 'sentry/components/loadingIndicator';
  4. import type {PlatformKey} from 'sentry/types/project';
  5. import {TraceTree} from '../traceModels/traceTree';
  6. import type {TraceTreeNode} from '../traceModels/traceTreeNode';
  7. import type {VirtualizedViewManager} from '../traceRenderers/virtualizedViewManager';
  8. export const TRACE_COUNT_FORMATTER = Intl.NumberFormat(undefined, {notation: 'compact'});
  9. export const TRACE_RIGHT_COLUMN_EVEN_CLASSNAME = `TraceRightColumn`;
  10. export const TRACE_RIGHT_COLUMN_ODD_CLASSNAME = [
  11. TRACE_RIGHT_COLUMN_EVEN_CLASSNAME,
  12. 'Odd',
  13. ].join(' ');
  14. export const TRACE_CHILDREN_COUNT_WRAPPER_CLASSNAME = `TraceChildrenCountWrapper`;
  15. export const TRACE_CHILDREN_COUNT_WRAPPER_ORPHANED_CLASSNAME = [
  16. TRACE_CHILDREN_COUNT_WRAPPER_CLASSNAME,
  17. 'Orphaned',
  18. ].join(' ');
  19. export interface TraceRowProps<T extends TraceTree.Node> {
  20. index: number;
  21. isEmbedded: boolean;
  22. listColumnClassName: string;
  23. listColumnStyle: React.CSSProperties;
  24. manager: VirtualizedViewManager;
  25. node: T;
  26. onExpand: (e: React.MouseEvent) => void;
  27. onExpandDoubleClick: (e: React.MouseEvent) => void;
  28. onRowClick: (e: React.MouseEvent<HTMLElement>) => void;
  29. onRowDoubleClick: (e: React.MouseEvent) => void;
  30. onRowKeyDown: (e: React.KeyboardEvent) => void;
  31. onSpanArrowClick: (e: React.MouseEvent) => void;
  32. onZoomIn: (e: React.MouseEvent) => void;
  33. previouslyFocusedNodeRef: React.MutableRefObject<TraceTreeNode<TraceTree.NodeValue> | null>;
  34. projects: Record<string, PlatformKey | undefined>;
  35. registerListColumnRef: (e: HTMLDivElement | null) => void;
  36. registerSpanArrowRef: (e: HTMLButtonElement | null) => void;
  37. registerSpanColumnRef: (e: HTMLDivElement | null) => void;
  38. rowSearchClassName: string;
  39. spanColumnClassName: string;
  40. style: React.CSSProperties;
  41. tabIndex: number;
  42. theme: Theme;
  43. trace_id: string | undefined;
  44. virtualized_index: number;
  45. }
  46. export function maybeFocusTraceRow(
  47. ref: HTMLDivElement | null,
  48. node: TraceTreeNode<TraceTree.NodeValue>,
  49. previouslyFocusedNodeRef: React.MutableRefObject<TraceTreeNode<TraceTree.NodeValue> | null>
  50. ) {
  51. if (!ref) {
  52. return;
  53. }
  54. if (node === previouslyFocusedNodeRef.current) {
  55. return;
  56. }
  57. previouslyFocusedNodeRef.current = node;
  58. ref.focus();
  59. }
  60. export function TraceRowConnectors(props: {
  61. manager: VirtualizedViewManager;
  62. node: TraceTreeNode<TraceTree.NodeValue>;
  63. }) {
  64. const hasChildren = TraceTree.HasVisibleChildren(props.node);
  65. const nodeDepth = TraceTree.Depth(props.node);
  66. return (
  67. <Fragment>
  68. {TraceTree.ConnectorsTo(props.node).map((c, i) => {
  69. return (
  70. <span
  71. key={i}
  72. style={{
  73. left: -(
  74. Math.abs(Math.abs(c) - nodeDepth) * props.manager.row_depth_padding
  75. ),
  76. }}
  77. className={`TraceVerticalConnector ${c <= 0 ? 'Orphaned' : ''}`}
  78. />
  79. );
  80. })}
  81. {hasChildren ? <span className="TraceExpandedVerticalConnector" /> : null}
  82. {TraceTree.IsLastChild(props.node) ? (
  83. <span className="TraceVerticalLastChildConnector" />
  84. ) : null}
  85. </Fragment>
  86. );
  87. }
  88. export function TraceChildrenButton(props: {
  89. children: React.ReactNode;
  90. expanded: boolean;
  91. icon: React.ReactNode;
  92. onClick: (e: React.MouseEvent) => void;
  93. onDoubleClick: (e: React.MouseEvent) => void;
  94. status: TraceTreeNode<any>['fetchStatus'] | undefined;
  95. }) {
  96. return (
  97. <button
  98. className={`TraceChildrenCount`}
  99. onClick={props.onClick}
  100. onDoubleClick={props.onDoubleClick}
  101. >
  102. <div className="TraceChildrenCountContent">{props.children}</div>
  103. <div className="TraceChildrenCountAction">
  104. {props.icon}
  105. {props.status === 'loading' ? (
  106. <LoadingIndicator className="TraceActionsLoadingIndicator" size={8} />
  107. ) : null}
  108. </div>
  109. </button>
  110. );
  111. }