useReleaseMarkLineSeries.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import {useTheme} from '@emotion/react';
  2. import MarkLine from 'sentry/components/charts/components/markLine';
  3. import {t} from 'sentry/locale';
  4. import type {Group} from 'sentry/types/group';
  5. import {escape} from 'sentry/utils';
  6. import {getFormattedDate} from 'sentry/utils/dates';
  7. import {useApiQuery} from 'sentry/utils/queryClient';
  8. import {useNavigate} from 'sentry/utils/useNavigate';
  9. import useOrganization from 'sentry/utils/useOrganization';
  10. import {formatVersion} from 'sentry/utils/versions/formatVersion';
  11. import {useIssueDetailsEventView} from 'sentry/views/issueDetails/streamline/useIssueDetailsDiscoverQuery';
  12. interface ReleaseStat {
  13. date: string;
  14. version: string;
  15. }
  16. export function useReleaseMarkLineSeries({group}: {group: Group}) {
  17. const navigate = useNavigate();
  18. const theme = useTheme();
  19. const eventView = useIssueDetailsEventView({group});
  20. const organization = useOrganization();
  21. const {
  22. data: releases = [],
  23. isPending: isLoadingReleases,
  24. error: releasesError,
  25. } = useApiQuery<ReleaseStat[]>(
  26. [
  27. `/organizations/${organization.slug}/releases/stats/`,
  28. {
  29. query: {
  30. project: eventView.project,
  31. environment: eventView.environment,
  32. start: eventView.start,
  33. end: eventView.end,
  34. statsPeriod: eventView.statsPeriod,
  35. },
  36. },
  37. ],
  38. {
  39. staleTime: 0,
  40. }
  41. );
  42. if (isLoadingReleases || releasesError) {
  43. return {
  44. seriesName: t('Releases'),
  45. markLine: {},
  46. data: [],
  47. };
  48. }
  49. const markLine = MarkLine({
  50. animation: false,
  51. lineStyle: {
  52. color: theme.purple300,
  53. opacity: 0.3,
  54. type: 'solid',
  55. },
  56. label: {
  57. show: false,
  58. },
  59. data: releases.map(release => ({
  60. xAxis: +new Date(release.date),
  61. name: formatVersion(release.version, true),
  62. value: formatVersion(release.version, true),
  63. onClick: () => {
  64. navigate({
  65. pathname: `/organizations/${
  66. organization.slug
  67. }/releases/${encodeURIComponent(release.version)}/`,
  68. });
  69. },
  70. label: {
  71. formatter: () => formatVersion(release.version, true),
  72. },
  73. })),
  74. tooltip: {
  75. trigger: 'item',
  76. formatter: ({data}: any) => {
  77. const time = getFormattedDate(data.value, 'MMM D, YYYY LT', {
  78. local: !eventView.utc,
  79. });
  80. const version = escape(formatVersion(data.name, true));
  81. return [
  82. '<div class="tooltip-series">',
  83. `<div><span class="tooltip-label"><strong>${t(
  84. 'Release'
  85. )}</strong></span> ${version}</div>`,
  86. '</div>',
  87. '<div class="tooltip-footer">',
  88. time,
  89. '</div>',
  90. '<div class="tooltip-arrow"></div>',
  91. ].join('');
  92. },
  93. },
  94. });
  95. return {
  96. seriesName: t('Releases'),
  97. data: [],
  98. markLine,
  99. color: theme.purple200,
  100. type: 'line',
  101. };
  102. }