setupAlertIntegrationButton.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. import styled from '@emotion/styled';
  2. import {openModal} from 'sentry/actionCreators/modal';
  3. import {Button} from 'sentry/components/button';
  4. import DeprecatedAsyncComponent from 'sentry/components/deprecatedAsyncComponent';
  5. import {Tooltip} from 'sentry/components/tooltip';
  6. import {t} from 'sentry/locale';
  7. import PluginIcon from 'sentry/plugins/components/pluginIcon';
  8. import ConfigStore from 'sentry/stores/configStore';
  9. import {space} from 'sentry/styles/space';
  10. import type {Organization} from 'sentry/types/organization';
  11. import type {Project} from 'sentry/types/project';
  12. import MessagingIntegrationModal from 'sentry/views/alerts/rules/issue/messagingIntegrationModal';
  13. type Props = DeprecatedAsyncComponent['props'] & {
  14. organization: Organization;
  15. projectSlug: string;
  16. };
  17. type State = DeprecatedAsyncComponent['state'] & {
  18. detailedProject?: Project & {
  19. hasAlertIntegrationInstalled: boolean;
  20. };
  21. };
  22. /**
  23. * This component renders a button to Set up an alert integration (just Slack for now)
  24. * if the project has no alerting integrations setup already.
  25. */
  26. export default class SetupAlertIntegrationButton extends DeprecatedAsyncComponent<
  27. Props,
  28. State
  29. > {
  30. getEndpoints(): ReturnType<DeprecatedAsyncComponent['getEndpoints']> {
  31. const {projectSlug, organization} = this.props;
  32. return [
  33. [
  34. 'detailedProject',
  35. `/projects/${organization.slug}/${projectSlug}/?expand=hasAlertIntegration`,
  36. ],
  37. ];
  38. }
  39. renderLoading() {
  40. return null;
  41. }
  42. // if there is an error, just show nothing
  43. renderError() {
  44. return null;
  45. }
  46. renderBody(): React.ReactNode {
  47. const headerContent = <h1>Connect with a messaging tool</h1>;
  48. const bodyContent = <p>Receive alerts and digests right where you work.</p>;
  49. const providerKeys = ['slack', 'discord', 'msteams'];
  50. const {organization} = this.props;
  51. const {detailedProject} = this.state;
  52. // don't render anything if we don't have the project yet or if an alert integration
  53. // is installed
  54. if (!detailedProject || detailedProject.hasAlertIntegrationInstalled) {
  55. return null;
  56. }
  57. if (organization.features.includes('messaging-integration-onboarding')) {
  58. // TODO(Mia): only render if organization has team plan and above
  59. return (
  60. <Tooltip
  61. title={t('Send alerts to your messaging service. Install the integration now.')}
  62. >
  63. <Button
  64. size="sm"
  65. icon={
  66. <IconWrapper>
  67. {providerKeys.map((value: string) => {
  68. return <PluginIcon key={value} pluginId={value} size={16} />;
  69. })}
  70. </IconWrapper>
  71. }
  72. onClick={() =>
  73. openModal(
  74. deps => (
  75. <MessagingIntegrationModal
  76. {...deps}
  77. headerContent={headerContent}
  78. bodyContent={bodyContent}
  79. providerKeys={providerKeys}
  80. organization={organization}
  81. project={detailedProject}
  82. />
  83. ),
  84. {
  85. closeEvents: 'escape-key',
  86. }
  87. )
  88. }
  89. >
  90. {t('Connect to messaging')}
  91. </Button>
  92. </Tooltip>
  93. );
  94. }
  95. const {isSelfHosted} = ConfigStore.getState();
  96. // link to docs to set up Slack for self-hosted folks
  97. const referrerQuery = '?referrer=issue-alert-builder';
  98. const buttonProps = isSelfHosted
  99. ? {
  100. href: `https://develop.sentry.dev/integrations/slack/${referrerQuery}`,
  101. }
  102. : {
  103. to: `/settings/${organization.slug}/integrations/slack/${referrerQuery}`,
  104. };
  105. // TOOD(Steve): need to use the Tooltip component because adding a title to the button
  106. // puts the tooltip in the upper left hand corner of the page instead of the button
  107. return (
  108. <Tooltip title={t('Send Alerts to Slack. Install the integration now.')}>
  109. <Button
  110. size="sm"
  111. icon={<PluginIcon pluginId="slack" size={16} />}
  112. {...buttonProps}
  113. >
  114. {t('Set Up Slack Now')}
  115. </Button>
  116. </Tooltip>
  117. );
  118. }
  119. }
  120. const IconWrapper = styled('div')`
  121. display: flex;
  122. gap: ${space(1)};
  123. `;