traceErrorList.tsx 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. import {memo} from 'react';
  2. import styled from '@emotion/styled';
  3. import flatten from 'lodash/flatten';
  4. import groupBy from 'lodash/groupBy';
  5. import List from 'sentry/components/list';
  6. import ListItem from 'sentry/components/list/listItem';
  7. import {tct, tn} from 'sentry/locale';
  8. import {TraceError} from 'sentry/utils/performance/quickTrace/types';
  9. import {ParsedTraceType, SpanType} from './types';
  10. interface TraceErrorListProps {
  11. errors: TraceError[];
  12. onClickSpan: (event: React.MouseEvent, spanId: SpanType['span_id']) => void;
  13. trace: ParsedTraceType;
  14. }
  15. function TraceErrorList({trace, errors, onClickSpan}: TraceErrorListProps) {
  16. return (
  17. <List symbol="bullet" data-test-id="trace-error-list">
  18. {flatten(
  19. Object.entries(groupBy(errors, 'span')).map(([spanId, spanErrors]) => {
  20. return Object.entries(groupBy(spanErrors, 'level')).map(
  21. ([level, spanLevelErrors]) => (
  22. <ListItem key={`${spanId}-${level}`}>
  23. {tct('[errors] [link]', {
  24. errors: tn(
  25. '%s %s error in ',
  26. '%s %s errors in ',
  27. spanLevelErrors.length,
  28. level === 'error' ? '' : level // Prevents awkward "error errors" copy if the level is "error"
  29. ),
  30. link: (
  31. <ErrorLink onClick={event => onClickSpan(event, spanId)}>
  32. {findSpanById(trace, spanId).op}
  33. </ErrorLink>
  34. ),
  35. })}
  36. </ListItem>
  37. )
  38. );
  39. })
  40. )}
  41. </List>
  42. );
  43. }
  44. const ErrorLink = styled('a')`
  45. color: ${p => p.theme.textColor};
  46. :hover {
  47. color: ${p => p.theme.textColor};
  48. }
  49. `;
  50. // Given a span ID, find the associated span. It might be the trace itself
  51. // (which is technically a type of span) or a specific span associated with
  52. // the trace
  53. const findSpanById = (trace: ParsedTraceType, spanId: SpanType['span_id']) => {
  54. return trace.spans.find(span => span.span_id === spanId && span?.op) || trace;
  55. };
  56. export default memo(TraceErrorList);