setupMessagingIntegrationButton.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import styled from '@emotion/styled';
  2. import {openModal} from 'sentry/actionCreators/modal';
  3. import {Button} from 'sentry/components/button';
  4. import {t} from 'sentry/locale';
  5. import PluginIcon from 'sentry/plugins/components/pluginIcon';
  6. import {space} from 'sentry/styles/space';
  7. import type {
  8. IntegrationProvider,
  9. OrganizationIntegration,
  10. } from 'sentry/types/integrations';
  11. import {getIntegrationFeatureGate} from 'sentry/utils/integrationUtil';
  12. import {useApiQueries, useApiQuery} from 'sentry/utils/queryClient';
  13. import useOrganization from 'sentry/utils/useOrganization';
  14. import MessagingIntegrationModal from 'sentry/views/alerts/rules/issue/messagingIntegrationModal';
  15. export enum MessagingIntegrationAnalyticsView {
  16. ALERT_RULE_CREATION = 'alert_rule_creation_messaging_integration_onboarding',
  17. PROJECT_CREATION = 'project_creation_messaging_integration_onboarding',
  18. }
  19. type Props = {
  20. analyticsView: MessagingIntegrationAnalyticsView;
  21. projectId?: string;
  22. refetchConfigs?: () => void;
  23. };
  24. function SetupMessagingIntegrationButton({
  25. refetchConfigs,
  26. analyticsView,
  27. projectId,
  28. }: Props) {
  29. const providerKeys = ['slack', 'discord', 'msteams'];
  30. const organization = useOrganization();
  31. const onAddIntegration = () => {
  32. messagingIntegrationsQuery.refetch();
  33. if (refetchConfigs) {
  34. refetchConfigs();
  35. }
  36. };
  37. const messagingIntegrationsQuery = useApiQuery<OrganizationIntegration[]>(
  38. [`/organizations/${organization.slug}/integrations/?integrationType=messaging`],
  39. {staleTime: Infinity}
  40. );
  41. const integrationProvidersQuery = useApiQueries<{providers: IntegrationProvider[]}>(
  42. providerKeys.map((providerKey: string) => [
  43. `/organizations/${organization.slug}/config/integrations/?provider_key=${providerKey}`,
  44. ]),
  45. {staleTime: Infinity}
  46. );
  47. const {IntegrationFeatures} = getIntegrationFeatureGate();
  48. const shouldRenderSetupButton = messagingIntegrationsQuery.data?.every(
  49. integration => integration.status !== 'active'
  50. );
  51. if (
  52. messagingIntegrationsQuery.isPending ||
  53. messagingIntegrationsQuery.isError ||
  54. integrationProvidersQuery.some(({isPending}) => isPending) ||
  55. integrationProvidersQuery.some(({isError}) => isError) ||
  56. integrationProvidersQuery[0]!.data === undefined
  57. ) {
  58. return null;
  59. }
  60. if (!shouldRenderSetupButton) {
  61. return null;
  62. }
  63. return (
  64. <IntegrationFeatures
  65. organization={organization}
  66. features={integrationProvidersQuery[0]!.data.providers[0]?.metadata?.features!}
  67. >
  68. {({disabled, disabledReason}) => (
  69. <div>
  70. <Button
  71. size="sm"
  72. icon={
  73. <IconWrapper>
  74. {providerKeys.map((value: string) => {
  75. return <PluginIcon key={value} pluginId={value} size={16} />;
  76. })}
  77. </IconWrapper>
  78. }
  79. disabled={disabled}
  80. title={
  81. disabled
  82. ? disabledReason
  83. : t('Send alerts to your messaging service. Install the integration now.')
  84. }
  85. onClick={() => {
  86. openModal(
  87. deps => (
  88. <MessagingIntegrationModal
  89. {...deps}
  90. headerContent={t('Connect with a messaging tool')}
  91. bodyContent={t('Receive alerts and digests right where you work.')}
  92. providers={integrationProvidersQuery
  93. .map(result => result.data?.providers[0])
  94. .filter(
  95. (provider): provider is IntegrationProvider =>
  96. provider !== undefined
  97. )}
  98. onAddIntegration={onAddIntegration}
  99. {...(projectId && {modalParams: {projectId}})}
  100. analyticsView={analyticsView}
  101. />
  102. ),
  103. {
  104. closeEvents: 'escape-key',
  105. }
  106. );
  107. }}
  108. >
  109. {t('Connect to messaging')}
  110. </Button>
  111. </div>
  112. )}
  113. </IntegrationFeatures>
  114. );
  115. }
  116. const IconWrapper = styled('div')`
  117. display: flex;
  118. gap: ${space(1)};
  119. `;
  120. export default SetupMessagingIntegrationButton;