components.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import {Fragment, ReactNode, useState} from 'react';
  2. import styled from '@emotion/styled';
  3. import {KeyValueTable, KeyValueTableRow} from 'sentry/components/keyValueTable';
  4. import {Tooltip} from 'sentry/components/tooltip';
  5. import {IconChevron} from 'sentry/icons';
  6. import {t} from 'sentry/locale';
  7. import {space} from 'sentry/styles/space';
  8. export const Indent = styled('div')`
  9. padding-left: ${space(4)};
  10. `;
  11. const NotFoundText = styled('span')`
  12. color: ${p => p.theme.subText};
  13. font-size: ${p => p.theme.fontSizeSmall};
  14. `;
  15. const WarningText = styled('span')`
  16. color: ${p => p.theme.errorText};
  17. `;
  18. export function Warning({warnings}: {warnings: string[]}) {
  19. if (warnings.includes('JSON_TRUNCATED') || warnings.includes('TEXT_TRUNCATED')) {
  20. return (
  21. <WarningText>{t('Truncated (~~) due to exceeding 150k characters')}</WarningText>
  22. );
  23. }
  24. if (warnings.includes('INVALID_JSON')) {
  25. return <WarningText>{t('Invalid JSON')}</WarningText>;
  26. }
  27. return null;
  28. }
  29. export function SizeTooltip({children}: {children: ReactNode}) {
  30. return (
  31. <Tooltip
  32. title={t('It is possible the network transfer size is smaller due to compression.')}
  33. >
  34. {children}
  35. </Tooltip>
  36. );
  37. }
  38. export type KeyValueTuple = {
  39. key: string;
  40. value: string | ReactNode;
  41. type?: 'warning' | 'error';
  42. };
  43. export function keyValueTableOrNotFound(data: KeyValueTuple[], notFoundText: string) {
  44. return data.length ? (
  45. <StyledKeyValueTable noMargin>
  46. {data.map(({key, value, type}) => (
  47. <KeyValueTableRow
  48. key={key}
  49. keyName={key}
  50. type={type}
  51. value={<ValueContainer>{value}</ValueContainer>}
  52. />
  53. ))}
  54. </StyledKeyValueTable>
  55. ) : (
  56. <Indent>
  57. <NotFoundText>{notFoundText}</NotFoundText>
  58. </Indent>
  59. );
  60. }
  61. const ValueContainer = styled('span')`
  62. overflow: auto;
  63. `;
  64. const SectionTitle = styled('dt')``;
  65. const SectionTitleExtra = styled('span')`
  66. flex-grow: 1;
  67. text-align: right;
  68. font-weight: normal;
  69. `;
  70. const SectionData = styled('dd')`
  71. font-size: ${p => p.theme.fontSizeExtraSmall};
  72. `;
  73. const ToggleButton = styled('button')`
  74. background: ${p => p.theme.background};
  75. border: 0;
  76. color: ${p => p.theme.headingColor};
  77. font-size: ${p => p.theme.fontSizeSmall};
  78. font-weight: 600;
  79. line-height: ${p => p.theme.text.lineHeightBody};
  80. width: 100%;
  81. display: flex;
  82. align-items: center;
  83. justify-content: flex-start;
  84. gap: ${space(1)};
  85. padding: ${space(0.5)} ${space(1)};
  86. :hover {
  87. background: ${p => p.theme.backgroundSecondary};
  88. }
  89. `;
  90. export function SectionItem({
  91. children,
  92. title,
  93. titleExtra,
  94. }: {
  95. children: ReactNode;
  96. title: ReactNode;
  97. titleExtra?: ReactNode;
  98. }) {
  99. const [isOpen, setIsOpen] = useState(true);
  100. return (
  101. <Fragment>
  102. <SectionTitle>
  103. <ToggleButton aria-label={t('toggle section')} onClick={() => setIsOpen(!isOpen)}>
  104. <IconChevron direction={isOpen ? 'down' : 'right'} size="xs" />
  105. {title}
  106. {titleExtra ? <SectionTitleExtra>{titleExtra}</SectionTitleExtra> : null}
  107. </ToggleButton>
  108. </SectionTitle>
  109. <SectionData>{isOpen ? children : null}</SectionData>
  110. </Fragment>
  111. );
  112. }
  113. const StyledKeyValueTable = styled(KeyValueTable)`
  114. & > dt {
  115. font-size: ${p => p.theme.fontSizeSmall};
  116. padding-left: ${space(4)};
  117. }
  118. & > dd {
  119. ${p => p.theme.overflowEllipsis};
  120. font-size: ${p => p.theme.fontSizeSmall};
  121. display: flex;
  122. justify-content: flex-end;
  123. white-space: normal;
  124. text-align: right;
  125. }
  126. `;