autofixSetupWriteAccessModal.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. import {Fragment, useMemo} from 'react';
  2. import styled from '@emotion/styled';
  3. import type {ModalRenderProps} from 'sentry/actionCreators/modal';
  4. import {Button, LinkButton} from 'sentry/components/button';
  5. import ButtonBar from 'sentry/components/buttonBar';
  6. import {GitRepoLink} from 'sentry/components/events/autofix/autofixSetupModal';
  7. import {useAutofixSetup} from 'sentry/components/events/autofix/useAutofixSetup';
  8. import ExternalLink from 'sentry/components/links/externalLink';
  9. import {IconCheckmark} from 'sentry/icons';
  10. import {t, tct} from 'sentry/locale';
  11. import {space} from 'sentry/styles/space';
  12. interface AutofixSetupWriteAccessModalProps extends ModalRenderProps {
  13. groupId: string;
  14. }
  15. function Content({groupId, closeModal}: {closeModal: () => void; groupId: string}) {
  16. const {canCreatePullRequests, data} = useAutofixSetup(
  17. {groupId, checkWriteAccess: true},
  18. {refetchOnWindowFocus: true} // We want to check each time the user comes back to the tab
  19. );
  20. const sortedRepos = useMemo(
  21. () =>
  22. data?.githubWriteIntegration?.repos.toSorted((a: any, b: any) => {
  23. if (a.ok === b.ok) {
  24. return `${a.owner}/${a.name}`.localeCompare(`${b.owner}/${b.name}`);
  25. }
  26. return a.ok ? -1 : 1;
  27. }) ?? [],
  28. [data]
  29. );
  30. if (canCreatePullRequests) {
  31. return (
  32. <DoneWrapper>
  33. <DoneIcon color="success" size="xxl" isCircled />
  34. <p>{t("You've successfully configured write access!")}</p>
  35. <Button onClick={closeModal} priority="primary">
  36. {t("Let's go")}
  37. </Button>
  38. </DoneWrapper>
  39. );
  40. }
  41. if (sortedRepos.length > 0) {
  42. return (
  43. <Fragment>
  44. <p>
  45. {tct(
  46. 'In order to create pull requests, install and grant write access to the [link:Sentry Autofix GitHub App] for the following repositories:',
  47. {
  48. link: (
  49. <ExternalLink
  50. href={`https://github.com/apps/sentry-autofix/installations/new`}
  51. />
  52. ),
  53. }
  54. )}
  55. </p>
  56. <RepoLinkUl>
  57. {sortedRepos.map((repo: any) => (
  58. <GitRepoLink key={`${repo.owner}/${repo.name}`} repo={repo} />
  59. ))}
  60. </RepoLinkUl>
  61. </Fragment>
  62. );
  63. }
  64. return (
  65. <Fragment>
  66. <p>
  67. {tct(
  68. 'In order to create pull requests, install and grant write access to the [link:Sentry Autofix GitHub App] for the relevant repositories.',
  69. {
  70. link: (
  71. <ExternalLink
  72. href={`https://github.com/apps/sentry-autofix/installations/new`}
  73. />
  74. ),
  75. }
  76. )}
  77. </p>
  78. </Fragment>
  79. );
  80. }
  81. export function AutofixSetupWriteAccessModal({
  82. Header,
  83. Body,
  84. Footer,
  85. groupId,
  86. closeModal,
  87. }: AutofixSetupWriteAccessModalProps) {
  88. const {canCreatePullRequests} = useAutofixSetup({groupId, checkWriteAccess: true});
  89. return (
  90. <div id="autofix-write-access-modal">
  91. <Header closeButton>
  92. <h3>{t('Allow Autofix to Make Pull Requests')}</h3>
  93. </Header>
  94. <Body>
  95. <Content groupId={groupId} closeModal={closeModal} />
  96. </Body>
  97. {!canCreatePullRequests && (
  98. <Footer>
  99. <ButtonBar gap={1}>
  100. <Button onClick={closeModal}>{t('Later')}</Button>
  101. <LinkButton
  102. href="https://github.com/apps/sentry-autofix/installations/new"
  103. external
  104. priority="primary"
  105. >
  106. {t('Install the Autofix GitHub App')}
  107. </LinkButton>
  108. </ButtonBar>
  109. </Footer>
  110. )}
  111. </div>
  112. );
  113. }
  114. const DoneWrapper = styled('div')`
  115. position: relative;
  116. display: flex;
  117. align-items: center;
  118. justify-content: center;
  119. flex-direction: column;
  120. padding: 40px;
  121. font-size: ${p => p.theme.fontSizeLarge};
  122. `;
  123. const DoneIcon = styled(IconCheckmark)`
  124. margin-bottom: ${space(4)};
  125. `;
  126. const RepoLinkUl = styled('ul')`
  127. display: flex;
  128. flex-direction: column;
  129. gap: ${space(0.5)};
  130. padding: 0;
  131. `;