messageSection.tsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. import {Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import {Role} from 'sentry/components/acl/role';
  4. import {Flex} from 'sentry/components/container/flex';
  5. import FeedbackItemUsername from 'sentry/components/feedback/feedbackItem/feedbackItemUsername';
  6. import FeedbackTimestampsTooltip from 'sentry/components/feedback/feedbackItem/feedbackTimestampsTooltip';
  7. import FeedbackViewers from 'sentry/components/feedback/feedbackItem/feedbackViewers';
  8. import {ScreenshotSection} from 'sentry/components/feedback/feedbackItem/screenshotSection';
  9. import TimeSince from 'sentry/components/timeSince';
  10. import {t} from 'sentry/locale';
  11. import {space} from 'sentry/styles/space';
  12. import type {Event} from 'sentry/types/event';
  13. import type {FeedbackIssue} from 'sentry/utils/feedback/types';
  14. import useOrganization from 'sentry/utils/useOrganization';
  15. interface Props {
  16. eventData: Event | undefined;
  17. feedbackItem: FeedbackIssue;
  18. }
  19. export default function MessageSection({eventData, feedbackItem}: Props) {
  20. const organization = useOrganization();
  21. const project = feedbackItem.project;
  22. return (
  23. <Fragment>
  24. <Flex wrap="wrap" flex="1 1 auto" gap={space(1)} justify="space-between">
  25. <FeedbackItemUsername feedbackIssue={feedbackItem} />
  26. <StyledTimeSince
  27. date={feedbackItem.firstSeen}
  28. tooltipProps={{
  29. title: eventData ? (
  30. <FeedbackTimestampsTooltip feedbackItem={feedbackItem} />
  31. ) : undefined,
  32. overlayStyle: {maxWidth: 300},
  33. }}
  34. />
  35. </Flex>
  36. <Blockquote>
  37. <pre>{feedbackItem.metadata.message}</pre>
  38. {eventData && project ? (
  39. <Role organization={organization} role={organization.attachmentsRole}>
  40. {({hasRole}) =>
  41. hasRole ? (
  42. <ScreenshotSection
  43. event={eventData}
  44. organization={organization}
  45. projectSlug={project.slug}
  46. />
  47. ) : null
  48. }
  49. </Role>
  50. ) : null}
  51. </Blockquote>
  52. <Flex justify="flex-end">
  53. <Flex gap={space(1)} align="center">
  54. <SeenBy>{t('Seen by')}</SeenBy>
  55. <FeedbackViewers feedbackItem={feedbackItem} />
  56. </Flex>
  57. </Flex>
  58. </Fragment>
  59. );
  60. }
  61. const StyledTimeSince = styled(TimeSince)`
  62. color: ${p => p.theme.subText};
  63. font-size: ${p => p.theme.fontSizeRelativeSmall};
  64. align-self: center;
  65. white-space: nowrap;
  66. `;
  67. const SeenBy = styled('span')`
  68. color: ${p => p.theme.subText};
  69. font-size: ${p => p.theme.fontSizeRelativeSmall};
  70. `;
  71. const Blockquote = styled('blockquote')`
  72. margin: 0;
  73. background: ${p => p.theme.purple100};
  74. display: flex;
  75. flex-direction: column;
  76. gap: ${space(2)};
  77. border-left: 2px solid ${p => p.theme.purple300};
  78. padding: ${space(2)};
  79. & > pre {
  80. margin-bottom: 0;
  81. background: none;
  82. font-family: inherit;
  83. font-size: ${p => p.theme.fontSizeMedium};
  84. line-height: 1.6;
  85. padding: 0;
  86. word-break: break-word;
  87. color: ${p => p.theme.textColor};
  88. }
  89. `;