renderHeadCell.tsx 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import type {Location} from 'history';
  2. import type {GridColumnHeader} from 'sentry/components/gridEditable';
  3. import type {Alignments} from 'sentry/components/gridEditable/sortLink';
  4. import SortLink from 'sentry/components/gridEditable/sortLink';
  5. import type {Sort} from 'sentry/utils/discover/fields';
  6. import {
  7. aggregateFunctionOutputType,
  8. fieldAlignment,
  9. parseFunction,
  10. } from 'sentry/utils/discover/fields';
  11. import {
  12. SpanFunction,
  13. SpanIndexedField,
  14. SpanMetricsField,
  15. } from 'sentry/views/starfish/types';
  16. import type {QueryParameterNames} from 'sentry/views/starfish/views/queryParameters';
  17. type Options = {
  18. column: GridColumnHeader<string>;
  19. location?: Location;
  20. sort?: Sort;
  21. sortParameterName?: QueryParameterNames | typeof DEFAULT_SORT_PARAMETER_NAME;
  22. };
  23. const DEFAULT_SORT_PARAMETER_NAME = 'sort';
  24. const {SPAN_SELF_TIME, HTTP_RESPONSE_CONTENT_LENGTH} = SpanMetricsField;
  25. const {RESPONSE_CODE, CACHE_ITEM_SIZE} = SpanIndexedField;
  26. const {TIME_SPENT_PERCENTAGE, SPS, SPM, HTTP_ERROR_COUNT, HTTP_RESPONSE_RATE} =
  27. SpanFunction;
  28. export const SORTABLE_FIELDS = new Set([
  29. `avg(${SPAN_SELF_TIME})`,
  30. `p95(${SPAN_SELF_TIME})`,
  31. `p75(transaction.duration)`,
  32. `transaction.duration`,
  33. 'transaction',
  34. `count()`,
  35. `${SPS}()`,
  36. `${SPM}()`,
  37. `${TIME_SPENT_PERCENTAGE}()`,
  38. `${HTTP_ERROR_COUNT}()`,
  39. `${HTTP_RESPONSE_RATE}(2)`,
  40. `${HTTP_RESPONSE_RATE}(4)`,
  41. `${HTTP_RESPONSE_RATE}(5)`,
  42. `avg(${HTTP_RESPONSE_CONTENT_LENGTH})`,
  43. ]);
  44. const NUMERIC_FIELDS = new Set([
  45. `${RESPONSE_CODE}`,
  46. CACHE_ITEM_SIZE,
  47. 'transaction.duration',
  48. ]);
  49. export const renderHeadCell = ({column, location, sort, sortParameterName}: Options) => {
  50. const {key, name} = column;
  51. const alignment = getAlignment(key);
  52. let newSortDirection: Sort['kind'] = 'desc';
  53. if (sort?.field === column.key) {
  54. if (sort.kind === 'desc') {
  55. newSortDirection = 'asc';
  56. }
  57. }
  58. const newSort = `${newSortDirection === 'desc' ? '-' : ''}${key}`;
  59. return (
  60. <SortLink
  61. align={alignment}
  62. canSort={Boolean(location && sort && SORTABLE_FIELDS.has(key))}
  63. direction={sort?.field === column.key ? sort.kind : undefined}
  64. title={name}
  65. generateSortLink={() => {
  66. return {
  67. ...location,
  68. query: {
  69. ...location?.query,
  70. [sortParameterName ?? DEFAULT_SORT_PARAMETER_NAME]: newSort,
  71. },
  72. };
  73. }}
  74. />
  75. );
  76. };
  77. export const getAlignment = (key: string): Alignments => {
  78. const result = parseFunction(key);
  79. if (result) {
  80. const outputType = aggregateFunctionOutputType(result.name, result.arguments[0]);
  81. if (outputType) {
  82. return fieldAlignment(key, outputType);
  83. }
  84. } else {
  85. if (NUMERIC_FIELDS.has(key)) {
  86. return 'right';
  87. }
  88. }
  89. return 'left';
  90. };