traceRow.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  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. listColumnClassName: string;
  22. listColumnStyle: React.CSSProperties;
  23. manager: VirtualizedViewManager;
  24. node: T;
  25. onExpand: (e: React.MouseEvent) => void;
  26. onExpandDoubleClick: (e: React.MouseEvent) => void;
  27. onRowClick: (e: React.MouseEvent<HTMLElement>) => void;
  28. onRowDoubleClick: (e: React.MouseEvent) => void;
  29. onRowKeyDown: (e: React.KeyboardEvent) => void;
  30. onSpanArrowClick: (e: React.MouseEvent) => void;
  31. onZoomIn: (e: React.MouseEvent) => void;
  32. previouslyFocusedNodeRef: React.MutableRefObject<TraceTreeNode<TraceTree.NodeValue> | null>;
  33. projects: Record<string, PlatformKey | undefined>;
  34. registerListColumnRef: (e: HTMLDivElement | null) => void;
  35. registerSpanArrowRef: (e: HTMLButtonElement | null) => void;
  36. registerSpanColumnRef: (e: HTMLDivElement | null) => void;
  37. rowSearchClassName: string;
  38. spanColumnClassName: string;
  39. style: React.CSSProperties;
  40. tabIndex: number;
  41. theme: Theme;
  42. trace_id: string | undefined;
  43. virtualized_index: number;
  44. }
  45. export function maybeFocusTraceRow(
  46. ref: HTMLDivElement | null,
  47. node: TraceTreeNode<TraceTree.NodeValue>,
  48. previouslyFocusedNodeRef: React.MutableRefObject<TraceTreeNode<TraceTree.NodeValue> | null>
  49. ) {
  50. if (!ref) {
  51. return;
  52. }
  53. if (node === previouslyFocusedNodeRef.current) {
  54. return;
  55. }
  56. previouslyFocusedNodeRef.current = node;
  57. ref.focus();
  58. }
  59. export function TraceRowConnectors(props: {
  60. manager: VirtualizedViewManager;
  61. node: TraceTreeNode<TraceTree.NodeValue>;
  62. }) {
  63. const hasChildren = TraceTree.HasVisibleChildren(props.node);
  64. const nodeDepth = TraceTree.Depth(props.node);
  65. return (
  66. <Fragment>
  67. {TraceTree.ConnectorsTo(props.node).map((c, i) => {
  68. return (
  69. <span
  70. key={i}
  71. style={{
  72. left: -(
  73. Math.abs(Math.abs(c) - nodeDepth) * props.manager.row_depth_padding
  74. ),
  75. }}
  76. className={`TraceVerticalConnector ${c <= 0 ? 'Orphaned' : ''}`}
  77. />
  78. );
  79. })}
  80. {hasChildren ? <span className="TraceExpandedVerticalConnector" /> : null}
  81. {TraceTree.IsLastChild(props.node) ? (
  82. <span className="TraceVerticalLastChildConnector" />
  83. ) : null}
  84. </Fragment>
  85. );
  86. }
  87. export function TraceChildrenButton(props: {
  88. children: React.ReactNode;
  89. expanded: boolean;
  90. icon: React.ReactNode;
  91. onClick: (e: React.MouseEvent) => void;
  92. onDoubleClick: (e: React.MouseEvent) => void;
  93. status: TraceTreeNode<any>['fetchStatus'] | undefined;
  94. }) {
  95. return (
  96. <button
  97. className={`TraceChildrenCount`}
  98. onClick={props.onClick}
  99. onDoubleClick={props.onDoubleClick}
  100. >
  101. <div className="TraceChildrenCountContent">{props.children}</div>
  102. <div className="TraceChildrenCountAction">
  103. {props.icon}
  104. {props.status === 'loading' ? (
  105. <LoadingIndicator className="TraceActionsLoadingIndicator" size={8} />
  106. ) : null}
  107. </div>
  108. </button>
  109. );
  110. }