resourceLandingPageCharts.tsx 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import styled from '@emotion/styled';
  2. import {space} from 'sentry/styles/space';
  3. import {EMPTY_OPTION_VALUE, MutableSearch} from 'sentry/utils/tokenizeSearch';
  4. import {InsightsLineChartWidget} from 'sentry/views/insights/common/components/insightsLineChartWidget';
  5. import {useSpanMetricsSeries} from 'sentry/views/insights/common/queries/useDiscoverSeries';
  6. import {
  7. getDurationChartTitle,
  8. getThroughputChartTitle,
  9. } from 'sentry/views/insights/common/views/spans/types';
  10. import type {ModuleFilters} from 'sentry/views/insights/common/views/spans/useModuleFilters';
  11. import {SpanMetricsField} from 'sentry/views/insights/types';
  12. const {SPAN_SELF_TIME, SPAN_DESCRIPTION, SPAN_DOMAIN} = SpanMetricsField;
  13. type Props = {
  14. appliedFilters: ModuleFilters;
  15. extraQuery?: string[];
  16. };
  17. export function ResourceLandingPageCharts({appliedFilters, extraQuery}: Props) {
  18. let query: string = buildDiscoverQueryConditions(appliedFilters);
  19. if (extraQuery) {
  20. query += ` ${extraQuery.join(' ')}`;
  21. }
  22. const {data, isPending, error} = useSpanMetricsSeries(
  23. {
  24. search: new MutableSearch(query),
  25. yAxis: ['spm()', `avg(${SPAN_SELF_TIME})`],
  26. transformAliasToInputFormat: true,
  27. },
  28. 'api.starfish.span-time-charts'
  29. );
  30. return (
  31. <ChartsContainer>
  32. <ChartsContainerItem>
  33. <InsightsLineChartWidget
  34. title={getThroughputChartTitle('resource')}
  35. series={[data['spm()']]}
  36. isLoading={isPending}
  37. error={error}
  38. />
  39. </ChartsContainerItem>
  40. <ChartsContainerItem>
  41. <InsightsLineChartWidget
  42. title={getDurationChartTitle('resource')}
  43. series={[data[`avg(${SPAN_SELF_TIME})`]]}
  44. isLoading={isPending}
  45. error={error}
  46. />
  47. </ChartsContainerItem>
  48. </ChartsContainer>
  49. );
  50. }
  51. const SPAN_FILTER_KEYS = ['span_operation', SPAN_DOMAIN, 'action'];
  52. const buildDiscoverQueryConditions = (appliedFilters: ModuleFilters) => {
  53. const result = Object.keys(appliedFilters)
  54. .filter(key => SPAN_FILTER_KEYS.includes(key))
  55. // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
  56. .filter(key => Boolean(appliedFilters[key]))
  57. .map(key => {
  58. // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
  59. const value = appliedFilters[key];
  60. if (key === SPAN_DOMAIN && value === EMPTY_OPTION_VALUE) {
  61. return [`!has:${SPAN_DOMAIN}`];
  62. }
  63. return `${key}:${value}`;
  64. });
  65. result.push(`has:${SPAN_DESCRIPTION}`);
  66. return result.join(' ');
  67. };
  68. const ChartsContainer = styled('div')`
  69. display: flex;
  70. flex-direction: row;
  71. flex-wrap: wrap;
  72. gap: ${space(2)};
  73. `;
  74. const ChartsContainerItem = styled('div')`
  75. flex: 1;
  76. `;