index.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. import {memo} from 'react';
  2. import {css} from '@emotion/react';
  3. import styled from '@emotion/styled';
  4. import space from 'sentry/styles/space';
  5. import {Organization} from 'sentry/types';
  6. import {BreadcrumbType, Crumb} from 'sentry/types/breadcrumbs';
  7. import {Event} from 'sentry/types/event';
  8. import Category from './category';
  9. import Data from './data';
  10. import Level from './level';
  11. import Time from './time';
  12. import Type from './type';
  13. type Props = Pick<React.ComponentProps<typeof Data>, 'route' | 'router'> & {
  14. breadcrumb: Crumb;
  15. ['data-test-id']: string;
  16. displayRelativeTime: boolean;
  17. event: Event;
  18. onLoad: () => void;
  19. organization: Organization;
  20. relativeTime: string;
  21. scrollbarSize: number;
  22. searchTerm: string;
  23. style: React.CSSProperties;
  24. height?: string;
  25. };
  26. const Breadcrumb = memo(function Breadcrumb({
  27. organization,
  28. event,
  29. breadcrumb,
  30. relativeTime,
  31. displayRelativeTime,
  32. searchTerm,
  33. onLoad,
  34. scrollbarSize,
  35. style,
  36. route,
  37. router,
  38. ['data-test-id']: dataTestId,
  39. }: Props) {
  40. const {type, description, color, level, category, timestamp} = breadcrumb;
  41. const error = breadcrumb.type === BreadcrumbType.ERROR;
  42. return (
  43. <Wrapper
  44. style={style}
  45. error={error}
  46. onLoad={onLoad}
  47. data-test-id={dataTestId}
  48. scrollbarSize={scrollbarSize}
  49. >
  50. <Type type={type} color={color} description={description} error={error} />
  51. <Category category={category} searchTerm={searchTerm} />
  52. <Data
  53. event={event}
  54. organization={organization}
  55. breadcrumb={breadcrumb}
  56. searchTerm={searchTerm}
  57. route={route}
  58. router={router}
  59. />
  60. <div>
  61. <Level level={level} searchTerm={searchTerm} />
  62. </div>
  63. <Time
  64. timestamp={timestamp}
  65. relativeTime={relativeTime}
  66. displayRelativeTime={displayRelativeTime}
  67. searchTerm={searchTerm}
  68. />
  69. </Wrapper>
  70. );
  71. });
  72. export default Breadcrumb;
  73. const Wrapper = styled('div')<{error: boolean; scrollbarSize: number}>`
  74. display: grid;
  75. grid-template-columns: 64px 140px 1fr 106px 100px ${p => p.scrollbarSize}px;
  76. > * {
  77. padding: ${space(1)} ${space(2)};
  78. }
  79. @media (max-width: ${props => props.theme.breakpoints.small}) {
  80. grid-template-rows: repeat(2, auto);
  81. grid-template-columns: max-content 1fr 74px 82px ${p => p.scrollbarSize}px;
  82. > * {
  83. padding: ${space(1)};
  84. /* Type */
  85. :nth-child(5n-4) {
  86. grid-row: 1/-1;
  87. padding-right: 0;
  88. padding-left: 0;
  89. margin-left: ${space(2)};
  90. margin-right: ${space(1)};
  91. }
  92. /* Data */
  93. :nth-child(5n-2) {
  94. grid-row: 2/2;
  95. grid-column: 2/-1;
  96. padding-top: 0;
  97. padding-right: ${space(2)};
  98. }
  99. /* Level */
  100. :nth-child(5n-1) {
  101. padding-right: 0;
  102. display: flex;
  103. justify-content: flex-end;
  104. align-items: flex-start;
  105. }
  106. /* Time */
  107. :nth-child(5n) {
  108. padding: ${space(1)} ${space(2)};
  109. }
  110. }
  111. }
  112. word-break: break-all;
  113. white-space: pre-wrap;
  114. :not(:last-child) {
  115. border-bottom: 1px solid ${p => (p.error ? p.theme.red300 : p.theme.innerBorder)};
  116. }
  117. ${p =>
  118. p.error &&
  119. css`
  120. :after {
  121. content: '';
  122. position: absolute;
  123. top: -1px;
  124. left: 0;
  125. height: 1px;
  126. width: 100%;
  127. background: ${p.theme.red300};
  128. }
  129. `}
  130. `;