canvasSupportNotice.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import styled from '@emotion/styled';
  2. import Alert from 'sentry/components/alert';
  3. import {Button} from 'sentry/components/button';
  4. import ExternalLink from 'sentry/components/links/externalLink';
  5. import {useReplayContext} from 'sentry/components/replays/replayContext';
  6. import {IconClose} from 'sentry/icons';
  7. import {t, tct} from 'sentry/locale';
  8. import {space} from 'sentry/styles/space';
  9. import {trackAnalytics} from 'sentry/utils/analytics';
  10. import useDismissAlert from 'sentry/utils/useDismissAlert';
  11. import useOrganization from 'sentry/utils/useOrganization';
  12. import useProjectSdkNeedsUpdate from 'sentry/utils/useProjectSdkNeedsUpdate';
  13. const LOCAL_STORAGE_KEY = 'replay-canvas-supported';
  14. /**
  15. * Displays a notice about canvas support if a <canvas> element is detected in the replay, but not recorded
  16. */
  17. export function CanvasSupportNotice() {
  18. const organization = useOrganization();
  19. const {dismiss, isDismissed} = useDismissAlert({key: LOCAL_STORAGE_KEY});
  20. const {isFetching, replay} = useReplayContext();
  21. const projectId = replay?.getReplay().project_id;
  22. const {needsUpdate} = useProjectSdkNeedsUpdate({
  23. minVersion: '7.98.0',
  24. organization,
  25. projectId: [projectId ?? '-1'],
  26. });
  27. // No need for notice if they are not feature flagged into the replayer
  28. if (!organization.features.includes('session-replay-enable-canvas-replayer')) {
  29. return null;
  30. }
  31. // User has dismissed this alert already, do not show
  32. if (isDismissed || isFetching) {
  33. return null;
  34. }
  35. // If we're already recording canvas, or no canvas elements detected, then do not show alert
  36. if (
  37. replay?.getSDKOptions()?.shouldRecordCanvas ||
  38. !replay?.hasCanvasElementInReplay()
  39. ) {
  40. return null;
  41. }
  42. return (
  43. <StyledAlert
  44. type="info"
  45. showIcon
  46. trailingItems={
  47. <Button
  48. aria-label={t('Dismiss banner')}
  49. icon={<IconClose />}
  50. onClick={dismiss}
  51. size="zero"
  52. borderless
  53. />
  54. }
  55. >
  56. {needsUpdate
  57. ? tct(
  58. 'This replay contains a [code:canvas] element. Please update your SDK to 7.98.0 or higher to enable [code:canvas] recording. [link:Learn more in our docs].',
  59. {
  60. code: <code />,
  61. link: (
  62. <ExternalLink
  63. onClick={() => {
  64. trackAnalytics('replay.canvas-detected-banner-clicked', {
  65. sdk_needs_update: true,
  66. organization,
  67. });
  68. }}
  69. href="https://docs.sentry.io/platforms/javascript/session-replay/#canvas-recording"
  70. />
  71. ),
  72. }
  73. )
  74. : tct(
  75. 'This replay contains a [code:canvas] element. Learn how to enable [code:canvas] recording [link:in our docs].',
  76. {
  77. code: <code />,
  78. link: (
  79. <ExternalLink
  80. onClick={() => {
  81. trackAnalytics('replay.canvas-detected-banner-clicked', {
  82. sdk_needs_update: false,
  83. organization,
  84. });
  85. }}
  86. href="https://docs.sentry.io/platforms/javascript/session-replay/#canvas-recording"
  87. />
  88. ),
  89. }
  90. )}
  91. </StyledAlert>
  92. );
  93. }
  94. const StyledAlert = styled(Alert)`
  95. margin-bottom: ${space(1)};
  96. `;