components.tsx 3.6 KB

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