actions.tsx 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. import {Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import ActionButton from 'sentry/components/actions/button';
  4. import MenuItemActionLink from 'sentry/components/actions/menuItemActionLink';
  5. import {Button} from 'sentry/components/button';
  6. import ButtonBar from 'sentry/components/buttonBar';
  7. import ConfirmDelete from 'sentry/components/confirmDelete';
  8. import DropdownLink from 'sentry/components/dropdownLink';
  9. import {Tooltip} from 'sentry/components/tooltip';
  10. import {IconEllipsis} from 'sentry/icons/iconEllipsis';
  11. import {t} from 'sentry/locale';
  12. import {space} from 'sentry/styles/space';
  13. import {CustomRepoType} from 'sentry/types/debugFiles';
  14. import TextBlock from 'sentry/views/settings/components/text/textBlock';
  15. type Props = {
  16. hasAccess: boolean;
  17. hasFeature: boolean;
  18. onDelete: () => void;
  19. onEdit: () => void;
  20. repositoryName: string;
  21. repositoryType: string;
  22. disabled?: boolean;
  23. syncNowButton?: React.ReactElement;
  24. };
  25. function Actions({
  26. repositoryName,
  27. repositoryType,
  28. disabled,
  29. onEdit,
  30. onDelete,
  31. hasFeature,
  32. hasAccess,
  33. syncNowButton,
  34. }: Props) {
  35. function renderConfirmDelete(element: React.ReactElement) {
  36. return (
  37. <ConfirmDelete
  38. confirmText={t('Delete Repository')}
  39. message={
  40. repositoryType === CustomRepoType.APP_STORE_CONNECT ? (
  41. <Fragment>
  42. <TextBlock>
  43. <strong>
  44. {t(
  45. 'Removing App Store Connect symbol source does not remove current dSYMs.'
  46. )}
  47. </strong>
  48. </TextBlock>
  49. <TextBlock>
  50. {t(
  51. 'The App Store Connect symbol source periodically imports dSYMs into the "Uploaded debug information files". Removing this symbol source does not delete those files and they will remain available for symbolication until deleted directly.'
  52. )}
  53. </TextBlock>
  54. </Fragment>
  55. ) : (
  56. <Fragment>
  57. <TextBlock>
  58. <strong>
  59. {t('Removing this repository applies instantly to new events.')}
  60. </strong>
  61. </TextBlock>
  62. <TextBlock>
  63. {t(
  64. 'Debug files from this repository will not be used to symbolicate future events. This may create new issues and alert members in your organization.'
  65. )}
  66. </TextBlock>
  67. </Fragment>
  68. )
  69. }
  70. confirmInput={repositoryName}
  71. priority="danger"
  72. onConfirm={onDelete}
  73. >
  74. {element}
  75. </ConfirmDelete>
  76. );
  77. }
  78. const actionsDisabled = !hasAccess || !hasFeature || disabled;
  79. return (
  80. <StyledButtonBar gap={1}>
  81. {syncNowButton}
  82. <ButtonTooltip
  83. title={
  84. !hasFeature
  85. ? undefined
  86. : !hasAccess
  87. ? t(
  88. 'You do not have permission to edit custom repositories configurations.'
  89. )
  90. : undefined
  91. }
  92. disabled={actionsDisabled}
  93. >
  94. <ActionBtn disabled={actionsDisabled} onClick={onEdit} size="sm">
  95. {t('Configure')}
  96. </ActionBtn>
  97. </ButtonTooltip>
  98. {actionsDisabled ? (
  99. <ButtonTooltip
  100. title={
  101. !hasFeature
  102. ? undefined
  103. : !hasAccess
  104. ? t(
  105. 'You do not have permission to delete custom repositories configurations.'
  106. )
  107. : undefined
  108. }
  109. disabled={actionsDisabled}
  110. >
  111. <ActionBtn size="sm" disabled>
  112. {t('Delete')}
  113. </ActionBtn>
  114. </ButtonTooltip>
  115. ) : (
  116. renderConfirmDelete(<ActionBtn size="sm">{t('Delete')}</ActionBtn>)
  117. )}
  118. <DropDownWrapper>
  119. <DropdownLink
  120. caret={false}
  121. disabled={actionsDisabled}
  122. customTitle={
  123. <StyledActionButton
  124. aria-label={t('Actions')}
  125. disabled={actionsDisabled}
  126. title={
  127. !hasFeature
  128. ? undefined
  129. : !hasAccess
  130. ? t(
  131. 'You do not have permission to edit and delete custom repositories configurations.'
  132. )
  133. : undefined
  134. }
  135. icon={<IconEllipsis />}
  136. />
  137. }
  138. anchorRight
  139. >
  140. <MenuItemActionLink onClick={onEdit}>{t('Configure')}</MenuItemActionLink>
  141. {renderConfirmDelete(<MenuItemActionLink>{t('Delete')}</MenuItemActionLink>)}
  142. </DropdownLink>
  143. </DropDownWrapper>
  144. </StyledButtonBar>
  145. );
  146. }
  147. export default Actions;
  148. const StyledActionButton = styled(ActionButton)`
  149. height: 32px;
  150. `;
  151. const StyledButtonBar = styled(ButtonBar)`
  152. gap: ${space(1)};
  153. grid-column: 2/2;
  154. grid-row: 4/4;
  155. grid-auto-flow: row;
  156. margin-top: ${space(0.5)};
  157. @media (min-width: ${p => p.theme.breakpoints.small}) {
  158. grid-column: 3/3;
  159. grid-row: 1/3;
  160. grid-auto-flow: column;
  161. margin-top: 0;
  162. }
  163. `;
  164. const ButtonTooltip = styled(Tooltip)`
  165. @media (min-width: ${p => p.theme.breakpoints.small}) {
  166. display: none;
  167. }
  168. `;
  169. const ActionBtn = styled(Button)`
  170. width: 100%;
  171. @media (min-width: ${p => p.theme.breakpoints.small}) {
  172. display: none;
  173. }
  174. `;
  175. const DropDownWrapper = styled('div')`
  176. display: none;
  177. @media (min-width: ${p => p.theme.breakpoints.small}) {
  178. display: block;
  179. }
  180. `;