allEventsTable.tsx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import {useEffect, useState} from 'react';
  2. import {Location} from 'history';
  3. import LoadingError from 'sentry/components/loadingError';
  4. import {PlatformCategory, PlatformKey} from 'sentry/data/platformCategories';
  5. import {t} from 'sentry/locale';
  6. import {Group, IssueCategory, Organization} from 'sentry/types';
  7. import EventView, {decodeSorts} from 'sentry/utils/discover/eventView';
  8. import {DiscoverDatasets} from 'sentry/utils/discover/types';
  9. import {getConfigForIssueType} from 'sentry/utils/issueTypeConfig';
  10. import {platformToCategory} from 'sentry/utils/platform';
  11. import {useRoutes} from 'sentry/utils/useRoutes';
  12. import EventsTable from 'sentry/views/performance/transactionSummary/transactionEvents/eventsTable';
  13. export interface Props {
  14. group: Group;
  15. issueId: string;
  16. location: Location;
  17. organization: Organization;
  18. excludedTags?: string[];
  19. }
  20. const AllEventsTable = (props: Props) => {
  21. const {location, organization, issueId, excludedTags, group} = props;
  22. const config = getConfigForIssueType(props.group);
  23. const [error, setError] = useState<string>('');
  24. const routes = useRoutes();
  25. const {fields, columnTitles} = getColumns(group, organization);
  26. const eventView: EventView = EventView.fromLocation(props.location);
  27. if (config.usesIssuePlatform) {
  28. eventView.dataset = DiscoverDatasets.ISSUE_PLATFORM;
  29. }
  30. eventView.fields = fields.map(fieldName => ({field: fieldName}));
  31. eventView.sorts = decodeSorts(location).filter(sort => fields.includes(sort.field));
  32. useEffect(() => {
  33. setError('');
  34. }, [eventView.query]);
  35. if (!eventView.sorts.length) {
  36. eventView.sorts = [{field: 'timestamp', kind: 'desc'}];
  37. }
  38. const idQuery =
  39. group.issueCategory === IssueCategory.PERFORMANCE
  40. ? `performance.issue_ids:${issueId} event.type:transaction`
  41. : `issue.id:${issueId}`;
  42. eventView.project = [parseInt(group.project.id, 10)];
  43. eventView.query = `${idQuery} ${props.location.query.query || ''}`;
  44. eventView.statsPeriod = '90d';
  45. if (error) {
  46. return <LoadingError message={error} onRetry={() => setError('')} />;
  47. }
  48. return (
  49. <EventsTable
  50. eventView={eventView}
  51. location={location}
  52. issueId={issueId}
  53. organization={organization}
  54. routes={routes}
  55. excludedTags={excludedTags}
  56. projectSlug={group.project.slug}
  57. customColumns={['minidump']}
  58. setError={(msg: string | undefined) => setError(msg ?? '')}
  59. transactionName=""
  60. columnTitles={columnTitles.slice()}
  61. referrer="api.issues.issue_events"
  62. />
  63. );
  64. };
  65. type ColumnInfo = {columnTitles: string[]; fields: string[]};
  66. const getColumns = (group: Group, organization: Organization): ColumnInfo => {
  67. const isPerfIssue = group.issueCategory === IssueCategory.PERFORMANCE;
  68. const isReplayEnabled = organization.features.includes('session-replay');
  69. const {fields: platformSpecificFields, columnTitles: platformSpecificColumnTitles} =
  70. getPlatformColumns(group.project.platform ?? group.platform, {isReplayEnabled});
  71. const fields: string[] = [
  72. 'id',
  73. 'transaction',
  74. 'title',
  75. 'release',
  76. 'environment',
  77. 'user.display',
  78. 'device',
  79. 'os',
  80. ...platformSpecificFields,
  81. ...(isPerfIssue ? ['transaction.duration'] : []),
  82. 'timestamp',
  83. ];
  84. const columnTitles: string[] = [
  85. t('event id'),
  86. t('transaction'),
  87. t('title'),
  88. t('release'),
  89. t('environment'),
  90. t('user'),
  91. t('device'),
  92. t('os'),
  93. ...platformSpecificColumnTitles,
  94. ...(isPerfIssue ? [t('total duration')] : []),
  95. t('timestamp'),
  96. t('minidump'),
  97. ];
  98. return {
  99. fields,
  100. columnTitles,
  101. };
  102. };
  103. const getPlatformColumns = (
  104. platform: PlatformKey | undefined,
  105. options: {isReplayEnabled: boolean}
  106. ): ColumnInfo => {
  107. const replayField = options.isReplayEnabled ? ['replayId'] : [];
  108. const replayColumnTitle = options.isReplayEnabled ? [t('replay')] : [];
  109. const backendServerlessColumnInfo = {
  110. fields: ['url', 'runtime'],
  111. columnTitles: [t('url'), t('runtime')],
  112. };
  113. const categoryToColumnMap: Record<PlatformCategory, ColumnInfo> = {
  114. [PlatformCategory.BACKEND]: backendServerlessColumnInfo,
  115. [PlatformCategory.SERVERLESS]: backendServerlessColumnInfo,
  116. [PlatformCategory.FRONTEND]: {
  117. fields: ['url', 'browser', ...replayField],
  118. columnTitles: [t('url'), t('browser'), ...replayColumnTitle],
  119. },
  120. [PlatformCategory.MOBILE]: {
  121. fields: ['url'],
  122. columnTitles: [t('url')],
  123. },
  124. [PlatformCategory.DESKTOP]: {
  125. fields: [],
  126. columnTitles: [],
  127. },
  128. [PlatformCategory.OTHER]: {
  129. fields: [],
  130. columnTitles: [],
  131. },
  132. };
  133. const platformCategory = platformToCategory(platform);
  134. return categoryToColumnMap[platformCategory];
  135. };
  136. export default AllEventsTable;