eventsTableRow.tsx 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import AttachmentUrl from 'sentry/components/attachmentUrl';
  2. import UserAvatar from 'sentry/components/avatar/userAvatar';
  3. import DateTime from 'sentry/components/dateTime';
  4. import {DeviceName} from 'sentry/components/deviceName';
  5. import FileSize from 'sentry/components/fileSize';
  6. import GlobalSelectionLink from 'sentry/components/globalSelectionLink';
  7. import {AvatarUser, Organization, Tag} from 'sentry/types';
  8. import {Event} from 'sentry/types/event';
  9. import withOrganization from 'sentry/utils/withOrganization';
  10. type Props = {
  11. event: Event;
  12. groupId: string;
  13. orgId: string;
  14. organization: Organization;
  15. projectId: string;
  16. tagList: Tag[];
  17. className?: string;
  18. hasUser?: boolean;
  19. };
  20. function EventsTableRow({
  21. className,
  22. event,
  23. projectId,
  24. orgId,
  25. groupId,
  26. tagList,
  27. hasUser,
  28. }: Props) {
  29. const crashFileLink = !event.crashFile ? null : (
  30. <AttachmentUrl projectId={projectId} eventId={event.id} attachment={event.crashFile}>
  31. {url =>
  32. url ? (
  33. <small>
  34. {event.crashFile?.type === 'event.minidump' ? 'Minidump' : 'Crash file'}:{' '}
  35. <a href={`${url}?download=1`}>{event.crashFile?.name}</a> (
  36. <FileSize bytes={event.crashFile?.size || 0} />)
  37. </small>
  38. ) : null
  39. }
  40. </AttachmentUrl>
  41. );
  42. const tagMap = Object.fromEntries(event.tags.map(tag => [tag.key, tag.value]));
  43. return (
  44. <tr key={event.id} className={className}>
  45. <td>
  46. <h5>
  47. <GlobalSelectionLink
  48. to={`/organizations/${orgId}/issues/${groupId}/events/${event.id}/`}
  49. >
  50. <DateTime date={event.dateCreated} year seconds timeZone />
  51. </GlobalSelectionLink>
  52. <small>{event.title.substr(0, 100)}</small>
  53. {crashFileLink}
  54. </h5>
  55. </td>
  56. {hasUser && (
  57. <td className="event-user table-user-info">
  58. {event.user ? (
  59. <div>
  60. <UserAvatar
  61. // TODO(ts): Some of the user fields are optional from event,
  62. // this cast can probably be removed in the future
  63. user={event.user as AvatarUser}
  64. size={24}
  65. className="avatar"
  66. gravatar={false}
  67. />
  68. {event.user.email}
  69. </div>
  70. ) : (
  71. <span>—</span>
  72. )}
  73. </td>
  74. )}
  75. {tagList.map(tag => (
  76. <td key={tag.key}>
  77. <div>
  78. {tag.key === 'device' ? (
  79. <DeviceName value={tagMap[tag.key]} />
  80. ) : (
  81. tagMap[tag.key]
  82. )}
  83. </div>
  84. </td>
  85. ))}
  86. </tr>
  87. );
  88. }
  89. export default withOrganization(EventsTableRow);