styles.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. import styled from '@emotion/styled';
  2. import {LocationDescriptor} from 'history';
  3. import MenuHeader from 'sentry/components/actions/menuHeader';
  4. import ExternalLink from 'sentry/components/links/externalLink';
  5. import MenuItem from 'sentry/components/menuItem';
  6. import Tag, {Background} from 'sentry/components/tag';
  7. import Truncate from 'sentry/components/truncate';
  8. import space from 'sentry/styles/space';
  9. import {getDuration} from 'sentry/utils/formatters';
  10. import {QuickTraceEvent} from 'sentry/utils/performance/quickTrace/types';
  11. import {Theme} from 'sentry/utils/theme';
  12. export const SectionSubtext = styled('div')`
  13. color: ${p => p.theme.subText};
  14. font-size: ${p => p.theme.fontSizeMedium};
  15. `;
  16. export const QuickTraceContainer = styled('div')`
  17. display: flex;
  18. align-items: center;
  19. height: 24px;
  20. `;
  21. const nodeColors = (theme: Theme) => ({
  22. error: {
  23. color: theme.white,
  24. background: theme.red300,
  25. border: theme.red300,
  26. },
  27. warning: {
  28. color: theme.red300,
  29. background: theme.background,
  30. border: theme.red300,
  31. },
  32. white: {
  33. color: theme.textColor,
  34. background: theme.background,
  35. border: theme.textColor,
  36. },
  37. black: {
  38. color: theme.background,
  39. background: theme.textColor,
  40. border: theme.textColor,
  41. },
  42. });
  43. export const EventNode = styled(Tag)<{shouldOffset?: boolean}>`
  44. span {
  45. display: flex;
  46. color: ${p => nodeColors(p.theme)[p.type || 'white'].color};
  47. }
  48. & ${/* sc-selector */ Background} {
  49. background-color: ${p => nodeColors(p.theme)[p.type || 'white'].background};
  50. border: 1px solid ${p => nodeColors(p.theme)[p.type || 'white'].border};
  51. }
  52. /*
  53. * When the EventNode is contains an icon, we need to offset the
  54. * component a little for all the EventNodes to be aligned.
  55. */
  56. ${p => p.shouldOffset && `margin-top: ${space(0.5)}`}
  57. `;
  58. export const TraceConnector = styled('div')`
  59. width: ${space(1)};
  60. border-top: 1px solid ${p => p.theme.textColor};
  61. `;
  62. /**
  63. * The DropdownLink component is styled directly with less and the way the
  64. * elements are laid out within means we can't apply any styles directly
  65. * using emotion. Instead, we wrap it all inside a span and indirectly
  66. * style it here.
  67. */
  68. export const DropdownContainer = styled('span')`
  69. .dropdown-menu {
  70. padding: 0;
  71. }
  72. `;
  73. export const DropdownMenuHeader = styled(MenuHeader)<{first?: boolean}>`
  74. background: ${p => p.theme.backgroundSecondary};
  75. ${p => p.first && 'border-radius: 2px'};
  76. padding: ${space(1)} ${space(1.5)};
  77. `;
  78. const StyledMenuItem = styled(MenuItem)<{width: 'small' | 'large'}>`
  79. width: ${p => (p.width === 'large' ? '350px' : '200px')};
  80. &:not(:last-child) {
  81. border-bottom: 1px solid ${p => p.theme.innerBorder};
  82. }
  83. `;
  84. const MenuItemContent = styled('div')`
  85. display: flex;
  86. justify-content: space-between;
  87. width: 100%;
  88. `;
  89. type DropdownItemProps = {
  90. children: React.ReactNode;
  91. allowDefaultEvent?: boolean;
  92. onSelect?: (eventKey: any) => void;
  93. to?: string | LocationDescriptor;
  94. width?: 'small' | 'large';
  95. };
  96. export function DropdownItem({
  97. children,
  98. onSelect,
  99. allowDefaultEvent,
  100. to,
  101. width = 'large',
  102. }: DropdownItemProps) {
  103. return (
  104. <StyledMenuItem
  105. to={to}
  106. onSelect={onSelect}
  107. width={width}
  108. allowDefaultEvent={allowDefaultEvent}
  109. >
  110. <MenuItemContent>{children}</MenuItemContent>
  111. </StyledMenuItem>
  112. );
  113. }
  114. export const DropdownItemSubContainer = styled('div')`
  115. display: flex;
  116. flex-direction: row;
  117. > a {
  118. padding-left: 0 !important;
  119. }
  120. `;
  121. export const QuickTraceValue = styled(Truncate)`
  122. margin-left: ${space(1)};
  123. white-space: nowrap;
  124. `;
  125. export const ErrorNodeContent = styled('div')`
  126. display: grid;
  127. grid-template-columns: repeat(2, auto);
  128. gap: ${space(0.25)};
  129. align-items: center;
  130. `;
  131. export const ExternalDropdownLink = styled(ExternalLink)`
  132. display: inherit !important;
  133. padding: 0 !important;
  134. color: ${p => p.theme.textColor};
  135. &:hover {
  136. color: ${p => p.theme.textColor};
  137. }
  138. `;
  139. export function SingleEventHoverText({event}: {event: QuickTraceEvent}) {
  140. return (
  141. <div>
  142. <Truncate
  143. value={event.transaction}
  144. maxLength={30}
  145. leftTrim
  146. trimRegex={/\.|\//g}
  147. expandable={false}
  148. />
  149. <div>
  150. {getDuration(
  151. event['transaction.duration'] / 1000,
  152. event['transaction.duration'] < 1000 ? 0 : 2,
  153. true
  154. )}
  155. </div>
  156. </div>
  157. );
  158. }