setupMessagingIntegrationButton.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. import styled from '@emotion/styled';
  2. import {openModal} from 'sentry/actionCreators/modal';
  3. import {Button} from 'sentry/components/button';
  4. import {Tooltip} from 'sentry/components/tooltip';
  5. import {t} from 'sentry/locale';
  6. import PluginIcon from 'sentry/plugins/components/pluginIcon';
  7. import {space} from 'sentry/styles/space';
  8. import type {IntegrationProvider} from 'sentry/types/integrations';
  9. import type {Project} from 'sentry/types/project';
  10. import {trackAnalytics} from 'sentry/utils/analytics';
  11. import {getIntegrationFeatureGate} from 'sentry/utils/integrationUtil';
  12. import {useApiQuery} from 'sentry/utils/queryClient';
  13. import useRouteAnalyticsParams from 'sentry/utils/routeAnalytics/useRouteAnalyticsParams';
  14. import useOrganization from 'sentry/utils/useOrganization';
  15. import MessagingIntegrationModal from 'sentry/views/alerts/rules/issue/messagingIntegrationModal';
  16. interface ProjectWithAlertIntegrationInfo extends Project {
  17. hasAlertIntegrationInstalled: boolean;
  18. }
  19. export enum MessagingIntegrationAnalyticsView {
  20. ALERT_RULE_CREATION = 'alert_rule_creation',
  21. }
  22. type Props = {
  23. projectSlug: string;
  24. refetchConfigs: () => void;
  25. analyticsParams?: {
  26. view: MessagingIntegrationAnalyticsView;
  27. };
  28. };
  29. function SetupMessagingIntegrationButton({
  30. projectSlug,
  31. refetchConfigs,
  32. analyticsParams,
  33. }: Props) {
  34. const providerKeys = ['slack', 'discord', 'msteams'];
  35. const organization = useOrganization();
  36. const onAddIntegration = () => {
  37. projectQuery.refetch();
  38. refetchConfigs();
  39. };
  40. const projectQuery = useApiQuery<ProjectWithAlertIntegrationInfo>(
  41. [
  42. `/projects/${organization.slug}/${projectSlug}/`,
  43. {query: {expand: 'hasAlertIntegration'}},
  44. ],
  45. {staleTime: Infinity}
  46. );
  47. // Only need to fetch the first provider to check if the feature is enabled, as all providers will return the same response
  48. const integrationQuery = useApiQuery<{providers: IntegrationProvider[]}>(
  49. [
  50. `/organizations/${organization.slug}/config/integrations/?provider_key=${providerKeys[0]}`,
  51. ],
  52. {staleTime: Infinity}
  53. );
  54. const {IntegrationFeatures} = getIntegrationFeatureGate();
  55. const shouldRenderSetupButton =
  56. projectQuery.data != null &&
  57. !projectQuery.data.hasAlertIntegrationInstalled &&
  58. integrationQuery.data != null;
  59. useRouteAnalyticsParams({
  60. setup_message_integration_button_shown: shouldRenderSetupButton,
  61. });
  62. if (
  63. projectQuery.isLoading ||
  64. projectQuery.isError ||
  65. integrationQuery.isLoading ||
  66. integrationQuery.isError
  67. ) {
  68. return null;
  69. }
  70. if (!shouldRenderSetupButton) {
  71. return null;
  72. }
  73. return (
  74. <IntegrationFeatures
  75. organization={organization}
  76. features={integrationQuery.data.providers[0].metadata.features}
  77. >
  78. {({disabled, disabledReason}) => (
  79. <Tooltip
  80. title={
  81. disabled
  82. ? disabledReason
  83. : t('Send alerts to your messaging service. Install the integration now.')
  84. }
  85. >
  86. <Button
  87. size="sm"
  88. icon={
  89. <IconWrapper>
  90. {providerKeys.map((value: string) => {
  91. return <PluginIcon key={value} pluginId={value} size={16} />;
  92. })}
  93. </IconWrapper>
  94. }
  95. disabled={disabled}
  96. onClick={() => {
  97. openModal(
  98. deps => (
  99. <MessagingIntegrationModal
  100. {...deps}
  101. headerContent={t('Connect with a messaging tool')}
  102. bodyContent={t('Receive alerts and digests right where you work.')}
  103. providerKeys={providerKeys}
  104. project={projectQuery.data}
  105. onAddIntegration={onAddIntegration}
  106. />
  107. ),
  108. {
  109. closeEvents: 'escape-key',
  110. }
  111. );
  112. trackAnalytics('onboarding.messaging_integration_modal_rendered', {
  113. project_id: projectQuery.data.id,
  114. organization,
  115. ...analyticsParams,
  116. });
  117. }}
  118. >
  119. {t('Connect to messaging')}
  120. </Button>
  121. </Tooltip>
  122. )}
  123. </IntegrationFeatures>
  124. );
  125. }
  126. const IconWrapper = styled('div')`
  127. display: flex;
  128. gap: ${space(1)};
  129. `;
  130. export default SetupMessagingIntegrationButton;