globalSdkUpdateAlert.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import {Fragment, useCallback, useEffect, useState} from 'react';
  2. import {promptsCheck, promptsUpdate} from 'sentry/actionCreators/prompts';
  3. import Alert, {AlertProps} from 'sentry/components/alert';
  4. import {ALL_ACCESS_PROJECTS} from 'sentry/constants/pageFilters';
  5. import {t} from 'sentry/locale';
  6. import SidebarPanelStore from 'sentry/stores/sidebarPanelStore';
  7. import {ProjectSdkUpdates} from 'sentry/types';
  8. import trackAdvancedAnalyticsEvent from 'sentry/utils/analytics/trackAdvancedAnalyticsEvent';
  9. import {promptIsDismissed} from 'sentry/utils/promptIsDismissed';
  10. import useApi from 'sentry/utils/useApi';
  11. import useOrganization from 'sentry/utils/useOrganization';
  12. import usePageFilters from 'sentry/utils/usePageFilters';
  13. import withSdkUpdates from 'sentry/utils/withSdkUpdates';
  14. import {SidebarPanelKey} from './sidebar/types';
  15. import Button from './button';
  16. interface InnerGlobalSdkSuggestionsProps extends AlertProps {
  17. className?: string;
  18. sdkUpdates?: ProjectSdkUpdates[] | null;
  19. }
  20. function InnerGlobalSdkUpdateAlert(
  21. props: InnerGlobalSdkSuggestionsProps
  22. ): React.ReactElement | null {
  23. const api = useApi();
  24. const organization = useOrganization();
  25. const {selection} = usePageFilters();
  26. const [showUpdateAlert, setShowUpdateAlert] = useState<boolean>(false);
  27. const handleSnoozePrompt = useCallback(() => {
  28. promptsUpdate(api, {
  29. organizationId: organization.id,
  30. feature: 'sdk_updates',
  31. status: 'snoozed',
  32. });
  33. trackAdvancedAnalyticsEvent('sdk_updates.snoozed', {organization});
  34. setShowUpdateAlert(false);
  35. }, [api, organization]);
  36. const handleReviewUpdatesClick = useCallback(() => {
  37. SidebarPanelStore.activatePanel(SidebarPanelKey.Broadcasts);
  38. trackAdvancedAnalyticsEvent('sdk_updates.clicked', {organization});
  39. }, [organization]);
  40. useEffect(() => {
  41. trackAdvancedAnalyticsEvent('sdk_updates.seen', {organization});
  42. let isUnmounted = false;
  43. promptsCheck(api, {
  44. organizationId: organization.id,
  45. feature: 'sdk_updates',
  46. }).then(prompt => {
  47. if (isUnmounted) {
  48. return;
  49. }
  50. setShowUpdateAlert(!promptIsDismissed(prompt));
  51. });
  52. return () => {
  53. isUnmounted = true;
  54. };
  55. }, [api, organization]);
  56. if (!showUpdateAlert || !props.sdkUpdates?.length) {
  57. return null;
  58. }
  59. // withSdkUpdates explicitly only queries My Projects. This means that when
  60. // looking at any projects outside of My Projects (like All Projects), this
  61. // will only show the updates relevant to the to user.
  62. const projectSpecificUpdates =
  63. selection?.projects?.length === 0 || selection?.projects[0] === ALL_ACCESS_PROJECTS
  64. ? props.sdkUpdates
  65. : props.sdkUpdates.filter(update =>
  66. selection?.projects?.includes(parseInt(update.projectId, 10))
  67. );
  68. // Check if we have at least one suggestion out of the list of updates
  69. if (projectSpecificUpdates.every(v => v.suggestions.length === 0)) {
  70. return null;
  71. }
  72. return (
  73. <Alert
  74. type="info"
  75. showIcon
  76. className={props.className}
  77. trailingItems={
  78. <Fragment>
  79. <Button
  80. priority="link"
  81. size="zero"
  82. title={t('Dismiss for the next two weeks')}
  83. onClick={handleSnoozePrompt}
  84. >
  85. {t('Remind me later')}
  86. </Button>
  87. <span>|</span>
  88. <Button priority="link" size="zero" onClick={handleReviewUpdatesClick}>
  89. {t('Review updates')}
  90. </Button>
  91. </Fragment>
  92. }
  93. >
  94. {t(
  95. `You have outdated SDKs in your projects. Update them for important fixes and features.`
  96. )}
  97. </Alert>
  98. );
  99. }
  100. const WithSdkUpdatesGlobalSdkUpdateAlert = withSdkUpdates(InnerGlobalSdkUpdateAlert);
  101. export {
  102. WithSdkUpdatesGlobalSdkUpdateAlert as GlobalSdkUpdateAlert,
  103. InnerGlobalSdkUpdateAlert,
  104. };