renderHeadCell.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  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, CACHE_ITEM_SIZE} = SpanMetricsField;
  25. const {
  26. TIME_SPENT_PERCENTAGE,
  27. SPS,
  28. SPM,
  29. HTTP_ERROR_COUNT,
  30. HTTP_RESPONSE_RATE,
  31. CACHE_HIT_RATE,
  32. CACHE_MISS_RATE,
  33. } = SpanFunction;
  34. export const SORTABLE_FIELDS = new Set([
  35. `avg(${SPAN_SELF_TIME})`,
  36. `p95(${SPAN_SELF_TIME})`,
  37. `p75(transaction.duration)`,
  38. `transaction.duration`,
  39. 'transaction',
  40. `count()`,
  41. `${SPS}()`,
  42. `${SPM}()`,
  43. `${TIME_SPENT_PERCENTAGE}()`,
  44. `${HTTP_ERROR_COUNT}()`,
  45. `${HTTP_RESPONSE_RATE}(2)`,
  46. `${HTTP_RESPONSE_RATE}(4)`,
  47. `${HTTP_RESPONSE_RATE}(5)`,
  48. `avg(${HTTP_RESPONSE_CONTENT_LENGTH})`,
  49. `${CACHE_HIT_RATE}()`,
  50. `${CACHE_MISS_RATE}()`,
  51. SpanIndexedField.TIMESTAMP,
  52. SpanIndexedField.SPAN_DURATION,
  53. `avg(${CACHE_ITEM_SIZE})`,
  54. SpanIndexedField.MESSAGING_MESSAGE_DESTINATION_NAME,
  55. 'count_op(queue.publish)',
  56. 'count_op(queue.process)',
  57. 'avg_if(span.duration,span.op,queue.process)',
  58. 'avg(messaging.message.receive.latency)',
  59. 'time_spent_percentage(app,span.duration)',
  60. ]);
  61. const NUMERIC_FIELDS = new Set([
  62. 'transaction.duration',
  63. SpanMetricsField.CACHE_ITEM_SIZE,
  64. SpanIndexedField.SPAN_SELF_TIME,
  65. SpanIndexedField.SPAN_DURATION,
  66. SpanIndexedField.CACHE_ITEM_SIZE,
  67. SpanIndexedField.MESSAGING_MESSAGE_BODY_SIZE,
  68. SpanIndexedField.MESSAGING_MESSAGE_RETRY_COUNT,
  69. ]);
  70. export const renderHeadCell = ({column, location, sort, sortParameterName}: Options) => {
  71. const {key, name} = column;
  72. const alignment = getAlignment(key);
  73. let newSortDirection: Sort['kind'] = 'desc';
  74. if (sort?.field === column.key) {
  75. if (sort.kind === 'desc') {
  76. newSortDirection = 'asc';
  77. }
  78. }
  79. const newSort = `${newSortDirection === 'desc' ? '-' : ''}${key}`;
  80. return (
  81. <SortLink
  82. align={alignment}
  83. canSort={Boolean(location && sort && SORTABLE_FIELDS.has(key))}
  84. direction={sort?.field === column.key ? sort.kind : undefined}
  85. title={name}
  86. generateSortLink={() => {
  87. return {
  88. ...location,
  89. query: {
  90. ...location?.query,
  91. [sortParameterName ?? DEFAULT_SORT_PARAMETER_NAME]: newSort,
  92. },
  93. };
  94. }}
  95. />
  96. );
  97. };
  98. export const getAlignment = (key: string): Alignments => {
  99. const result = parseFunction(key);
  100. if (result) {
  101. const outputType = aggregateFunctionOutputType(result.name, result.arguments[0]);
  102. if (outputType) {
  103. return fieldAlignment(key, outputType);
  104. }
  105. } else {
  106. if (NUMERIC_FIELDS.has(key)) {
  107. return 'right';
  108. }
  109. }
  110. return 'left';
  111. };