useFlagSeries.tsx 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import {useTheme} from '@emotion/react';
  2. import moment from 'moment-timezone';
  3. import MarkLine from 'sentry/components/charts/components/markLine';
  4. import {t} from 'sentry/locale';
  5. import type {Event} from 'sentry/types/event';
  6. import {getFormattedDate} from 'sentry/utils/dates';
  7. import useOrganization from 'sentry/utils/useOrganization';
  8. import usePageFilters from 'sentry/utils/usePageFilters';
  9. import {hydrateToFlagSeries} from 'sentry/views/issueDetails/streamline/featureFlagUtils';
  10. import {useOrganizationFlagLog} from 'sentry/views/issueDetails/streamline/hooks/useOrganizationFlagLog';
  11. interface FlagSeriesProps {
  12. event: Event | undefined;
  13. query: Record<string, any>;
  14. }
  15. export default function useFlagSeries({query = {}, event}: FlagSeriesProps) {
  16. const theme = useTheme();
  17. const organization = useOrganization();
  18. const {
  19. data: rawFlagData,
  20. isError,
  21. isPending,
  22. } = useOrganizationFlagLog({organization, query});
  23. const {selection} = usePageFilters();
  24. if (!rawFlagData || !rawFlagData.data.length || isError || isPending) {
  25. return {
  26. seriesName: t('Feature Flags'),
  27. markLine: {},
  28. data: [],
  29. };
  30. }
  31. const hydratedFlagData = hydrateToFlagSeries(rawFlagData);
  32. const evaluatedFlagNames = event?.contexts.flags?.values.map(f => f.flag);
  33. const intersectionFlags = hydratedFlagData.filter(f =>
  34. evaluatedFlagNames?.includes(f.name)
  35. );
  36. // create a markline series using hydrated flag data
  37. const markLine = MarkLine({
  38. animation: false,
  39. lineStyle: {
  40. color: theme.blue300,
  41. opacity: 0.3,
  42. type: 'solid',
  43. },
  44. label: {
  45. show: false,
  46. },
  47. data: intersectionFlags,
  48. tooltip: {
  49. trigger: 'item',
  50. formatter: ({data}: any) => {
  51. const time = getFormattedDate(data.xAxis, 'MMM D, YYYY LT z', {
  52. local: !selection.datetime.utc,
  53. });
  54. const eventIsBefore = moment(event?.dateCreated).isBefore(moment(time));
  55. const formattedDate = moment(time).from(event?.dateCreated, true);
  56. const suffix = eventIsBefore
  57. ? t(' (%s after this event)', formattedDate)
  58. : t(' (%s before this event)', formattedDate);
  59. return [
  60. '<div class="tooltip-series">',
  61. `<div><span class="tooltip-label"><strong>${t(
  62. 'Feature Flag'
  63. )}</strong></span></div>`,
  64. `<span class="tooltip-label-align-start"><code class="tooltip-code-no-margin">${data.name}</code>${data.label.formatter()}</span>`,
  65. '</div>',
  66. '<div class="tooltip-footer">',
  67. time,
  68. event?.dateCreated && suffix,
  69. '</div>',
  70. '<div class="tooltip-arrow"></div>',
  71. ].join('');
  72. },
  73. },
  74. });
  75. return {
  76. seriesName: t('Feature Flags'),
  77. data: [],
  78. color: theme.blue200,
  79. markLine,
  80. type: 'line', // use this type so the bar chart doesn't shrink/grow
  81. };
  82. }