setupAlertIntegrationButton.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  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 SetupAlertIntegrationModal from 'sentry/views/alerts/rules/issue/setupAlertIntegrationModal';
  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 {organization} = this.props;
  48. const {detailedProject} = this.state;
  49. // don't render anything if we don't have the project yet or if an alert integration
  50. // is installed
  51. if (!detailedProject || detailedProject.hasAlertIntegrationInstalled) {
  52. return null;
  53. }
  54. if (organization.features.includes('messaging-integration-onboarding')) {
  55. // TODO(Mia): only render if organization has team plan and above
  56. return (
  57. <Tooltip
  58. title={t('Send alerts to your messaging service. Install the integration now.')}
  59. >
  60. <Button
  61. size="sm"
  62. icon={
  63. <IconWrapper>
  64. <PluginIcon pluginId="slack" size={16} />
  65. <PluginIcon pluginId="msteams" size={16} />
  66. <PluginIcon pluginId="discord" size={16} />
  67. </IconWrapper>
  68. }
  69. onClick={() =>
  70. openModal(deps => <SetupAlertIntegrationModal {...deps} />, {
  71. closeEvents: 'escape-key',
  72. })
  73. }
  74. >
  75. {t('Connect to messaging')}
  76. </Button>
  77. </Tooltip>
  78. );
  79. }
  80. const {isSelfHosted} = ConfigStore.getState();
  81. // link to docs to set up Slack for self-hosted folks
  82. const referrerQuery = '?referrer=issue-alert-builder';
  83. const buttonProps = isSelfHosted
  84. ? {
  85. href: `https://develop.sentry.dev/integrations/slack/${referrerQuery}`,
  86. }
  87. : {
  88. to: `/settings/${organization.slug}/integrations/slack/${referrerQuery}`,
  89. };
  90. // TOOD(Steve): need to use the Tooltip component because adding a title to the button
  91. // puts the tooltip in the upper left hand corner of the page instead of the button
  92. return (
  93. <Tooltip title={t('Send Alerts to Slack. Install the integration now.')}>
  94. <Button
  95. size="sm"
  96. icon={<PluginIcon pluginId="slack" size={16} />}
  97. {...buttonProps}
  98. >
  99. {t('Set Up Slack Now')}
  100. </Button>
  101. </Tooltip>
  102. );
  103. }
  104. }
  105. const IconWrapper = styled('div')`
  106. display: flex;
  107. gap: ${space(1)};
  108. `;