spansTable.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. import {Fragment, useMemo} from 'react';
  2. import EmptyStateWarning from 'sentry/components/emptyStateWarning';
  3. import LoadingIndicator from 'sentry/components/loadingIndicator';
  4. import Pagination from 'sentry/components/pagination';
  5. import {IconWarning} from 'sentry/icons';
  6. import {t} from 'sentry/locale';
  7. import type {NewQuery} from 'sentry/types/organization';
  8. import EventView from 'sentry/utils/discover/eventView';
  9. import {fieldAlignment} from 'sentry/utils/discover/fields';
  10. import usePageFilters from 'sentry/utils/usePageFilters';
  11. import {
  12. Table,
  13. TableBody,
  14. TableBodyCell,
  15. TableHead,
  16. TableHeadCell,
  17. TableRow,
  18. TableStatus,
  19. useTableStyles,
  20. } from 'sentry/views/explore/components/table';
  21. import {useSpanTags} from 'sentry/views/explore/contexts/spanTagsContext';
  22. import {useDataset} from 'sentry/views/explore/hooks/useDataset';
  23. import {useSampleFields} from 'sentry/views/explore/hooks/useSampleFields';
  24. import {useSorts} from 'sentry/views/explore/hooks/useSorts';
  25. import {useUserQuery} from 'sentry/views/explore/hooks/useUserQuery';
  26. import {useSpansQuery} from 'sentry/views/insights/common/queries/useSpansQuery';
  27. import {FieldRenderer} from './fieldRenderer';
  28. interface SpansTableProps {}
  29. export function SpansTable({}: SpansTableProps) {
  30. const {selection} = usePageFilters();
  31. const [dataset] = useDataset();
  32. const [fields] = useSampleFields();
  33. const [sorts] = useSorts({fields});
  34. const [query] = useUserQuery();
  35. const eventView = useMemo(() => {
  36. const queryFields = [
  37. ...fields,
  38. 'project',
  39. 'trace',
  40. 'transaction.span_id',
  41. 'span_id',
  42. 'timestamp',
  43. ];
  44. const discoverQuery: NewQuery = {
  45. id: undefined,
  46. name: 'Explore - Span Samples',
  47. fields: queryFields,
  48. orderby: sorts.map(sort => `${sort.kind === 'desc' ? '-' : ''}${sort.field}`),
  49. query,
  50. version: 2,
  51. dataset,
  52. };
  53. return EventView.fromNewQueryWithPageFilters(discoverQuery, selection);
  54. }, [dataset, fields, sorts, query, selection]);
  55. const columns = useMemo(() => eventView.getColumns(), [eventView]);
  56. const result = useSpansQuery({
  57. eventView,
  58. initialData: [],
  59. referrer: 'api.explore.spans-samples-table',
  60. });
  61. const {tableStyles} = useTableStyles({
  62. items: fields.map(field => {
  63. return {
  64. label: field,
  65. value: field,
  66. };
  67. }),
  68. });
  69. const meta = result.meta ?? {};
  70. const numberTags = useSpanTags('number');
  71. const stringTags = useSpanTags('string');
  72. return (
  73. <Fragment>
  74. <Table style={tableStyles}>
  75. <TableHead>
  76. <TableRow>
  77. {fields.map((field, i) => {
  78. // Hide column names before alignment is determined
  79. if (result.isPending) {
  80. return <TableHeadCell key={i} isFirst={i === 0} />;
  81. }
  82. const fieldType = meta.fields?.[field];
  83. const align = fieldAlignment(field, fieldType);
  84. const tag = stringTags[field] ?? numberTags[field] ?? null;
  85. return (
  86. <TableHeadCell align={align} key={i} isFirst={i === 0}>
  87. <span>{tag?.name ?? field}</span>
  88. </TableHeadCell>
  89. );
  90. })}
  91. </TableRow>
  92. </TableHead>
  93. <TableBody>
  94. {result.isPending ? (
  95. <TableStatus>
  96. <LoadingIndicator />
  97. </TableStatus>
  98. ) : result.isError ? (
  99. <TableStatus>
  100. <IconWarning data-test-id="error-indicator" color="gray300" size="lg" />
  101. </TableStatus>
  102. ) : result.isFetched && result.data?.length ? (
  103. result.data?.map((row, i) => (
  104. <TableRow key={i}>
  105. {fields.map((field, j) => {
  106. return (
  107. <TableBodyCell key={j}>
  108. <FieldRenderer
  109. column={columns[j]}
  110. data={row}
  111. unit={meta?.units?.[field]}
  112. meta={meta}
  113. />
  114. </TableBodyCell>
  115. );
  116. })}
  117. </TableRow>
  118. ))
  119. ) : (
  120. <TableStatus>
  121. <EmptyStateWarning>
  122. <p>{t('No spans found')}</p>
  123. </EmptyStateWarning>
  124. </TableStatus>
  125. )}
  126. </TableBody>
  127. </Table>
  128. <Pagination pageLinks={result.pageLinks} />
  129. </Fragment>
  130. );
  131. }