traceRow.tsx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import {Fragment, useMemo} from 'react';
  2. import styled from '@emotion/styled';
  3. import Panel from 'sentry/components/panels/panel';
  4. import PanelHeader from 'sentry/components/panels/panelHeader';
  5. import PanelItem from 'sentry/components/panels/panelItem';
  6. import PerformanceDuration from 'sentry/components/performanceDuration';
  7. import {Tooltip} from 'sentry/components/tooltip';
  8. import {t} from 'sentry/locale';
  9. import {space} from 'sentry/styles/space';
  10. import {FieldDateTime} from 'sentry/utils/discover/styles';
  11. import {decodeScalar} from 'sentry/utils/queryString';
  12. import {useLocation} from 'sentry/utils/useLocation';
  13. import type {IndexedResponse} from 'sentry/views/starfish/types';
  14. import {SpanIndexedField} from 'sentry/views/starfish/types';
  15. import {SpanIdRenderer, TraceIdRenderer} from './table/fieldRenderers';
  16. import type {Field} from './data';
  17. interface TraceRowProps {
  18. spans: Pick<IndexedResponse, Field>[];
  19. traceId: string;
  20. }
  21. export function TraceRow({traceId, spans}: TraceRowProps) {
  22. const location = useLocation();
  23. const timestamp = spans[0]?.timestamp;
  24. const utc = useMemo(() => {
  25. return decodeScalar(location?.query?.utc) === 'true';
  26. }, [location]);
  27. return (
  28. <TracePanel>
  29. <TraceInfo>
  30. <TraceInfoHeader>
  31. <TraceIdRenderer traceId={traceId} timestamp={timestamp} />
  32. </TraceInfoHeader>
  33. </TraceInfo>
  34. <SpanRowLayout>
  35. <SpansHeader lightText align="left">
  36. {t('Span ID')}
  37. </SpansHeader>
  38. <SpansHeader lightText align="left">
  39. {t('Span Op')}
  40. </SpansHeader>
  41. <SpansHeader lightText align="left">
  42. {t('Span Description')}
  43. </SpansHeader>
  44. <SpansHeader lightText align="right">
  45. {t('Span Duration')}
  46. </SpansHeader>
  47. <SpansHeader lightText align="right">
  48. {t('Span Self Time')}
  49. </SpansHeader>
  50. <SpansHeader lightText align="right">
  51. {t('Timestamp')}
  52. </SpansHeader>
  53. {spans.map(span => {
  54. return (
  55. <Fragment key={span[SpanIndexedField.ID]}>
  56. <SpanItem align="left">
  57. <SpanIdRenderer
  58. projectSlug={span[SpanIndexedField.PROJECT]}
  59. spanId={span[SpanIndexedField.ID]}
  60. transactionId={span[SpanIndexedField.TRANSACTION_ID]}
  61. />
  62. </SpanItem>
  63. <SpanItem align="left">
  64. {span[SpanIndexedField.SPAN_OP] ? (
  65. <Tooltip
  66. containerDisplayMode="inline"
  67. showOnlyOnOverflow
  68. title={span[SpanIndexedField.SPAN_OP]}
  69. >
  70. {span[SpanIndexedField.SPAN_OP]}
  71. </Tooltip>
  72. ) : (
  73. <EmptyValue>{t('No Op Available')}</EmptyValue>
  74. )}
  75. </SpanItem>
  76. <SpanItem align="left">
  77. {span[SpanIndexedField.SPAN_DESCRIPTION] ? (
  78. <Tooltip
  79. containerDisplayMode="inline"
  80. showOnlyOnOverflow
  81. title={span[SpanIndexedField.SPAN_DESCRIPTION]}
  82. >
  83. {span[SpanIndexedField.SPAN_DESCRIPTION]}
  84. </Tooltip>
  85. ) : (
  86. <EmptyValue>{t('No Description Available')}</EmptyValue>
  87. )}
  88. </SpanItem>
  89. <SpanItem align="right">
  90. <PerformanceDuration
  91. milliseconds={span[SpanIndexedField.SPAN_DURATION]}
  92. abbreviation
  93. />
  94. </SpanItem>
  95. <SpanItem align="right">
  96. <PerformanceDuration
  97. milliseconds={span[SpanIndexedField.SPAN_SELF_TIME]}
  98. abbreviation
  99. />
  100. </SpanItem>
  101. <SpanItem align="right">
  102. <FieldDateTime date={timestamp} year seconds timeZone utc={utc} />
  103. </SpanItem>
  104. </Fragment>
  105. );
  106. })}
  107. </SpanRowLayout>
  108. </TracePanel>
  109. );
  110. }
  111. const TracePanel = styled(Panel)`
  112. margin-bottom: 0px;
  113. `;
  114. const TraceInfo = styled('div')`
  115. padding: ${space(1.5)} ${space(2)};
  116. `;
  117. const TraceInfoHeader = styled('div')`
  118. font-size: ${p => p.theme.fontSizeExtraLarge};
  119. `;
  120. const SpanRowLayout = styled('div')`
  121. display: grid;
  122. grid-template-columns: min-content 1fr 2fr repeat(3, min-content);
  123. align-items: center;
  124. width: 100%;
  125. `;
  126. const SpansHeader = styled(PanelHeader)<{align: 'left' | 'right'}>`
  127. border-top: 1px solid ${p => p.theme.border};
  128. border-top-left-radius: 0;
  129. border-top-right-radius: 0;
  130. padding: ${space(1.5)} ${space(2)};
  131. font-size: ${p => p.theme.fontSizeSmall};
  132. ${p => p.theme.overflowEllipsis};
  133. ${p =>
  134. p.align === 'right'
  135. ? `
  136. text-align: right;
  137. font-variant-numeric: tabular-nums;
  138. `
  139. : ''}
  140. `;
  141. const SpanItem = styled(PanelItem)<{align: 'left' | 'right'}>`
  142. padding: ${space(1)} ${space(2)};
  143. ${p => p.theme.overflowEllipsis};
  144. ${p =>
  145. p.align === 'right'
  146. ? `
  147. text-align: right;
  148. font-variant-numeric: tabular-nums;
  149. `
  150. : ''}
  151. `;
  152. const EmptyValue = styled('span')`
  153. color: ${p => p.theme.gray300};
  154. `;