styles.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. import {useTheme} from '@emotion/react';
  2. import styled from '@emotion/styled';
  3. import {SectionHeading} from 'sentry/components/charts/styles';
  4. import {Panel} from 'sentry/components/panels';
  5. import {DurationPill, RowRectangle} from 'sentry/components/performance/waterfall/rowBar';
  6. import {pickBarColor, toPercent} from 'sentry/components/performance/waterfall/utils';
  7. import Tooltip from 'sentry/components/tooltip';
  8. import {IconArrow} from 'sentry/icons';
  9. import {t} from 'sentry/locale';
  10. import overflowEllipsis from 'sentry/styles/overflowEllipsis';
  11. import space from 'sentry/styles/space';
  12. import {formatPercentage} from 'sentry/utils/formatters';
  13. import {PerformanceDuration} from '../../utils';
  14. export const Actions = styled('div')`
  15. display: grid;
  16. grid-gap: ${space(2)};
  17. grid-template-columns: min-content 1fr min-content;
  18. align-items: center;
  19. `;
  20. export const UpperPanel = styled(Panel)`
  21. padding: ${space(1.5)} ${space(3)};
  22. margin-top: ${space(3)};
  23. margin-bottom: 0;
  24. border-bottom: 0;
  25. border-bottom-left-radius: 0;
  26. border-bottom-right-radius: 0;
  27. display: grid;
  28. grid-template-columns: 1fr;
  29. grid-gap: ${space(1.5)};
  30. @media (min-width: ${p => p.theme.breakpoints[1]}) {
  31. grid-template-columns: auto repeat(3, max-content);
  32. grid-gap: 48px;
  33. }
  34. `;
  35. export const LowerPanel = styled('div')<{expandable: boolean}>`
  36. > div {
  37. border-top-left-radius: 0;
  38. border-top-right-radius: 0;
  39. ${p =>
  40. p.expandable &&
  41. `
  42. margin-bottom: 0;
  43. border-bottom-left-radius: 0;
  44. border-bottom-right-radius: 0;
  45. `}
  46. }
  47. `;
  48. export const FooterPanel = styled(Panel)`
  49. font-size: ${p => p.theme.fontSizeMedium};
  50. padding: ${space(1)} ${space(0)} ${space(1)} ${space(3)};
  51. border-top: 0;
  52. border-top-left-radius: 0;
  53. border-top-right-radius: 0;
  54. `;
  55. type HeaderItemProps = {
  56. label: string;
  57. value: React.ReactNode;
  58. align: 'left' | 'right';
  59. isSortKey?: boolean;
  60. };
  61. export function HeaderItem(props: HeaderItemProps) {
  62. const {label, value, align, isSortKey} = props;
  63. const theme = useTheme();
  64. return (
  65. <HeaderItemContainer align={align}>
  66. {isSortKey && (
  67. <StyledIconArrow
  68. data-test-id="span-sort-arrow"
  69. size="xs"
  70. color={theme.subText as any}
  71. direction="down"
  72. />
  73. )}
  74. <SectionHeading>{label}</SectionHeading>
  75. <SectionValue>{value}</SectionValue>
  76. </HeaderItemContainer>
  77. );
  78. }
  79. export const HeaderItemContainer = styled('div')<{align: 'left' | 'right'}>`
  80. ${overflowEllipsis};
  81. @media (min-width: ${p => p.theme.breakpoints[1]}) {
  82. text-align: ${p => p.align};
  83. }
  84. `;
  85. const StyledIconArrow = styled(IconArrow)`
  86. margin-right: ${space(0.5)};
  87. `;
  88. const SectionValue = styled('h1')`
  89. font-size: ${p => p.theme.headerFontSize};
  90. font-weight: normal;
  91. line-height: 1.2;
  92. color: ${p => p.theme.textColor};
  93. margin-bottom: 0;
  94. `;
  95. export const SpanLabelContainer = styled('div')`
  96. ${overflowEllipsis};
  97. `;
  98. const EmptyValueContainer = styled('span')`
  99. color: ${p => p.theme.gray300};
  100. `;
  101. export const emptyValue = <EmptyValueContainer>{t('n/a')}</EmptyValueContainer>;
  102. const DurationBar = styled('div')`
  103. position: relative;
  104. display: flex;
  105. top: ${space(0.5)};
  106. background-color: ${p => p.theme.gray100};
  107. `;
  108. const DurationBarSection = styled(RowRectangle)`
  109. position: relative;
  110. width: 100%;
  111. top: 0;
  112. `;
  113. type SpanDurationBarProps = {
  114. spanOp: string;
  115. spanDuration: number;
  116. transactionDuration: number;
  117. };
  118. export function SpanDurationBar(props: SpanDurationBarProps) {
  119. const {spanOp, spanDuration, transactionDuration} = props;
  120. const widthPercentage = spanDuration / transactionDuration;
  121. const position = widthPercentage < 0.7 ? 'right' : 'inset';
  122. return (
  123. <DurationBar>
  124. <div style={{width: toPercent(widthPercentage)}}>
  125. <Tooltip title={formatPercentage(widthPercentage)} containerDisplayMode="block">
  126. <DurationBarSection
  127. spanBarHatch={false}
  128. style={{backgroundColor: pickBarColor(spanOp)}}
  129. >
  130. <DurationPill
  131. durationDisplay={position}
  132. showDetail={false}
  133. spanBarHatch={false}
  134. >
  135. <PerformanceDuration abbreviation milliseconds={spanDuration} />
  136. </DurationPill>
  137. </DurationBarSection>
  138. </Tooltip>
  139. </div>
  140. </DurationBar>
  141. );
  142. }