metricsRibbon.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import type {ComponentProps} from 'react';
  2. import {useMemo} from 'react';
  3. import styled from '@emotion/styled';
  4. import type {Polarity} from 'sentry/components/percentChange';
  5. import {space} from 'sentry/styles/space';
  6. import type {NewQuery} from 'sentry/types/organization';
  7. import type {TableData, TableDataRow} from 'sentry/utils/discover/discoverQuery';
  8. import EventView from 'sentry/utils/discover/eventView';
  9. import type {DiscoverDatasets} from 'sentry/utils/discover/types';
  10. import {MutableSearch} from 'sentry/utils/tokenizeSearch';
  11. import {useLocation} from 'sentry/utils/useLocation';
  12. import usePageFilters from 'sentry/utils/usePageFilters';
  13. import {MetricReadout} from 'sentry/views/insights/common/components/metricReadout';
  14. import {ReadoutRibbon} from 'sentry/views/insights/common/components/ribbon';
  15. import {useReleaseSelection} from 'sentry/views/insights/common/queries/useReleases';
  16. import {appendReleaseFilters} from 'sentry/views/insights/common/utils/releaseComparison';
  17. import useCrossPlatformProject from 'sentry/views/insights/mobile/common/queries/useCrossPlatformProject';
  18. import {useTableQuery} from 'sentry/views/insights/mobile/screenload/components/tables/screensTable';
  19. interface BlockProps {
  20. dataKey: string | ((data?: TableDataRow[]) => number | undefined);
  21. title: string;
  22. unit: ComponentProps<typeof MetricReadout>['unit'];
  23. allowZero?: boolean;
  24. preferredPolarity?: Polarity;
  25. }
  26. export function MobileMetricsRibbon({
  27. filters,
  28. blocks,
  29. fields,
  30. referrer,
  31. dataset,
  32. }: {
  33. blocks: BlockProps[];
  34. dataset: DiscoverDatasets;
  35. fields: string[];
  36. referrer: string;
  37. filters?: string[];
  38. }) {
  39. const {selection} = usePageFilters();
  40. const location = useLocation();
  41. const {
  42. primaryRelease,
  43. secondaryRelease,
  44. isLoading: isReleasesLoading,
  45. } = useReleaseSelection();
  46. const {isProjectCrossPlatform, selectedPlatform} = useCrossPlatformProject();
  47. const queryString = useMemo(() => {
  48. const searchQuery = new MutableSearch([...(filters ?? [])]);
  49. if (isProjectCrossPlatform) {
  50. searchQuery.addFilterValue('os.name', selectedPlatform);
  51. }
  52. return appendReleaseFilters(searchQuery, primaryRelease, secondaryRelease);
  53. }, [
  54. filters,
  55. isProjectCrossPlatform,
  56. primaryRelease,
  57. secondaryRelease,
  58. selectedPlatform,
  59. ]);
  60. const newQuery: NewQuery = {
  61. name: 'ScreenMetricsRibbon',
  62. fields,
  63. query: queryString,
  64. dataset,
  65. version: 2,
  66. projects: selection.projects,
  67. };
  68. const eventView = EventView.fromNewQueryWithLocation(newQuery, location);
  69. const {data, isPending} = useTableQuery({
  70. eventView,
  71. enabled: !isReleasesLoading,
  72. referrer,
  73. });
  74. return (
  75. <StyledReadoutRibbon>
  76. {blocks.map(({title, dataKey, unit, preferredPolarity}) => (
  77. <MetricsBlock
  78. key={title}
  79. title={title}
  80. unit={unit}
  81. dataKey={dataKey}
  82. data={data}
  83. isLoading={isPending}
  84. preferredPolarity={preferredPolarity}
  85. />
  86. ))}
  87. </StyledReadoutRibbon>
  88. );
  89. }
  90. const StyledReadoutRibbon = styled(ReadoutRibbon)`
  91. margin-bottom: ${space(2)};
  92. `;
  93. function MetricsBlock({
  94. title,
  95. unit,
  96. data,
  97. dataKey,
  98. isLoading,
  99. allowZero,
  100. preferredPolarity,
  101. }: {
  102. isLoading: boolean;
  103. title: string;
  104. data?: TableData;
  105. release?: string;
  106. } & BlockProps) {
  107. const value =
  108. typeof dataKey === 'function'
  109. ? dataKey(data?.data)
  110. : (data?.data?.[0]?.[dataKey] as number);
  111. const hasData = (value && value !== 0) || (value === 0 && allowZero);
  112. return (
  113. <MetricReadout
  114. title={title}
  115. value={hasData ? value : undefined}
  116. isLoading={isLoading}
  117. unit={unit}
  118. preferredPolarity={preferredPolarity}
  119. />
  120. );
  121. }