index.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import {Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import Alert from 'sentry/components/alert';
  4. import {PanelTable} from 'sentry/components/panels';
  5. import {t} from 'sentry/locale';
  6. import EventView from 'sentry/utils/discover/eventView';
  7. import type {Sort} from 'sentry/utils/discover/fields';
  8. import getRouteStringFromRoutes from 'sentry/utils/getRouteStringFromRoutes';
  9. import {useLocation} from 'sentry/utils/useLocation';
  10. import useOrganization from 'sentry/utils/useOrganization';
  11. import {useRoutes} from 'sentry/utils/useRoutes';
  12. import type {ReplayListRecordWithTx} from 'sentry/views/performance/transactionSummary/transactionReplays/useReplaysFromTransaction';
  13. import HeaderCell from 'sentry/views/replays/replayTable/headerCell';
  14. import {
  15. ActivityCell,
  16. DurationCell,
  17. ErrorCountCell,
  18. ProjectCell,
  19. SessionCell,
  20. StartedAtCell,
  21. TransactionCell,
  22. } from 'sentry/views/replays/replayTable/tableCell';
  23. import {ReplayColumns} from 'sentry/views/replays/replayTable/types';
  24. import type {ReplayListRecord} from 'sentry/views/replays/types';
  25. type Props = {
  26. fetchError: undefined | Error;
  27. isFetching: boolean;
  28. replays: undefined | ReplayListRecord[] | ReplayListRecordWithTx[];
  29. sort: Sort | undefined;
  30. visibleColumns: Array<keyof typeof ReplayColumns>;
  31. };
  32. function ReplayTable({fetchError, isFetching, replays, sort, visibleColumns}: Props) {
  33. const routes = useRoutes();
  34. const location = useLocation();
  35. const organization = useOrganization();
  36. const tableHeaders = visibleColumns.map(column => (
  37. <HeaderCell key={column} column={column} sort={sort} />
  38. ));
  39. if (fetchError && !isFetching) {
  40. return (
  41. <StyledPanelTable
  42. headers={tableHeaders}
  43. isLoading={false}
  44. visibleColumns={visibleColumns}
  45. >
  46. <StyledAlert type="error" showIcon>
  47. {typeof fetchError === 'string'
  48. ? fetchError
  49. : t(
  50. 'Sorry, the list of replays could not be loaded. This could be due to invalid search parameters or an internal systems error.'
  51. )}
  52. </StyledAlert>
  53. </StyledPanelTable>
  54. );
  55. }
  56. const referrer = getRouteStringFromRoutes(routes);
  57. const eventView = EventView.fromLocation(location);
  58. return (
  59. <StyledPanelTable
  60. headers={tableHeaders}
  61. isEmpty={replays?.length === 0}
  62. isLoading={isFetching}
  63. visibleColumns={visibleColumns}
  64. >
  65. {replays?.map(replay => {
  66. return (
  67. <Fragment key={replay.id}>
  68. {visibleColumns.map(column => {
  69. switch (column) {
  70. case 'session':
  71. return (
  72. <SessionCell
  73. key="session"
  74. replay={replay}
  75. eventView={eventView}
  76. organization={organization}
  77. referrer={referrer}
  78. />
  79. );
  80. case 'projectId':
  81. return <ProjectCell key="projectId" replay={replay} />;
  82. case 'slowestTransaction':
  83. return (
  84. <TransactionCell
  85. key="slowestTransaction"
  86. replay={replay}
  87. organization={organization}
  88. />
  89. );
  90. case 'startedAt':
  91. return <StartedAtCell key="startedAt" replay={replay} />;
  92. case 'duration':
  93. return <DurationCell key="duration" replay={replay} />;
  94. case 'countErrors':
  95. return <ErrorCountCell key="countErrors" replay={replay} />;
  96. case 'activity':
  97. return <ActivityCell key="activity" replay={replay} />;
  98. default:
  99. return null;
  100. }
  101. })}
  102. </Fragment>
  103. );
  104. })}
  105. </StyledPanelTable>
  106. );
  107. }
  108. const StyledPanelTable = styled(PanelTable)<{
  109. visibleColumns: Array<keyof typeof ReplayColumns>;
  110. }>`
  111. grid-template-columns: ${p =>
  112. p.visibleColumns
  113. .map(column => (column === 'session' ? 'minmax(100px, 1fr)' : 'max-content'))
  114. .join(' ')};
  115. `;
  116. const StyledAlert = styled(Alert)`
  117. border-radius: 0;
  118. border-width: 1px 0 0 0;
  119. grid-column: 1/-1;
  120. margin-bottom: 0;
  121. `;
  122. export default ReplayTable;