upgradeGrouping.tsx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import {Fragment, useEffect} from 'react';
  2. import {Location} from 'history';
  3. import {addLoadingMessage, clearIndicators} from 'sentry/actionCreators/indicator';
  4. import {Client} from 'sentry/api';
  5. import {Alert} from 'sentry/components/alert';
  6. import {Button} from 'sentry/components/button';
  7. import {openConfirmModal} from 'sentry/components/confirm';
  8. import FieldGroup from 'sentry/components/forms/fieldGroup';
  9. import {Panel, PanelBody, PanelHeader} from 'sentry/components/panels';
  10. import {t, tct} from 'sentry/locale';
  11. import ProjectsStore from 'sentry/stores/projectsStore';
  12. import {EventGroupingConfig, Organization, Project} from 'sentry/types';
  13. import {handleXhrErrorResponse} from 'sentry/utils/handleXhrErrorResponse';
  14. import marked from 'sentry/utils/marked';
  15. import TextBlock from 'sentry/views/settings/components/text/textBlock';
  16. import {getGroupingChanges, getGroupingRisk} from './utils';
  17. const upgradeGroupingId = 'upgrade-grouping';
  18. type Props = {
  19. api: Client;
  20. groupingConfigs: EventGroupingConfig[];
  21. location: Location;
  22. onUpgrade: () => void;
  23. organization: Organization;
  24. project: Project;
  25. projectId: string;
  26. };
  27. function UpgradeGrouping({
  28. groupingConfigs,
  29. organization,
  30. projectId,
  31. project,
  32. onUpgrade,
  33. api,
  34. location,
  35. }: Props) {
  36. const hasProjectWriteAccess = organization.access.includes('project:write');
  37. const {updateNotes, riskLevel, latestGroupingConfig} = getGroupingChanges(
  38. project,
  39. groupingConfigs
  40. );
  41. const {riskNote, alertType} = getGroupingRisk(riskLevel);
  42. const noUpdates = project.groupingAutoUpdate || !latestGroupingConfig;
  43. const priority = riskLevel >= 2 ? 'danger' : 'primary';
  44. useEffect(() => {
  45. if (
  46. location.hash !== `#${upgradeGroupingId}` ||
  47. noUpdates ||
  48. !groupingConfigs ||
  49. !hasProjectWriteAccess
  50. ) {
  51. return;
  52. }
  53. handleOpenConfirmModal();
  54. // eslint-disable-next-line react-hooks/exhaustive-deps
  55. }, [location.hash]);
  56. if (!groupingConfigs) {
  57. return null;
  58. }
  59. async function handleConfirmUpgrade() {
  60. const newData: Record<string, string | number> = {};
  61. if (latestGroupingConfig) {
  62. const now = Math.floor(new Date().getTime() / 1000);
  63. const ninety_days = 3600 * 24 * 90;
  64. newData.groupingConfig = latestGroupingConfig.id;
  65. newData.secondaryGroupingConfig = project.groupingConfig;
  66. newData.secondaryGroupingExpiry = now + ninety_days;
  67. }
  68. addLoadingMessage(t('Changing grouping\u2026'));
  69. try {
  70. const response = await api.requestPromise(
  71. `/projects/${organization.slug}/${projectId}/`,
  72. {
  73. method: 'PUT',
  74. data: newData,
  75. }
  76. );
  77. clearIndicators();
  78. ProjectsStore.onUpdateSuccess(response);
  79. onUpgrade();
  80. } catch (err) {
  81. handleXhrErrorResponse('Unable to upgrade config', err);
  82. }
  83. }
  84. function handleOpenConfirmModal() {
  85. openConfirmModal({
  86. confirmText: t('Upgrade'),
  87. priority,
  88. onConfirm: handleConfirmUpgrade,
  89. message: (
  90. <Fragment>
  91. <TextBlock>
  92. <strong>{t('Upgrade Grouping Strategy')}</strong>
  93. </TextBlock>
  94. <TextBlock>
  95. {t(
  96. 'You can upgrade the grouping strategy to the latest but this is an irreversible operation.'
  97. )}
  98. </TextBlock>
  99. <TextBlock>
  100. <strong>{t('New Behavior')}</strong>
  101. <div dangerouslySetInnerHTML={{__html: marked(updateNotes)}} />
  102. </TextBlock>
  103. <TextBlock>
  104. <Alert type={alertType}>{riskNote}</Alert>
  105. </TextBlock>
  106. </Fragment>
  107. ),
  108. });
  109. }
  110. function getButtonTitle() {
  111. if (project.groupingAutoUpdate) {
  112. return t('Disabled because automatic upgrading is enabled');
  113. }
  114. if (!hasProjectWriteAccess) {
  115. return t('You do not have sufficient permissions to do this');
  116. }
  117. if (noUpdates) {
  118. return t('You are already on the latest version');
  119. }
  120. return undefined;
  121. }
  122. return (
  123. <Panel id={upgradeGroupingId}>
  124. <PanelHeader>{t('Upgrade Grouping')}</PanelHeader>
  125. <PanelBody>
  126. <FieldGroup
  127. label={t('Upgrade Grouping Strategy')}
  128. help={tct(
  129. 'If the project uses an old grouping strategy an update is possible.[linebreak]Doing so will cause new events to group differently.',
  130. {
  131. linebreak: <br />,
  132. }
  133. )}
  134. disabled
  135. >
  136. <div>
  137. <Button
  138. onClick={handleOpenConfirmModal}
  139. disabled={!hasProjectWriteAccess || noUpdates}
  140. title={getButtonTitle()}
  141. priority={priority}
  142. >
  143. {t('Upgrade Grouping Strategy')}
  144. </Button>
  145. </div>
  146. </FieldGroup>
  147. </PanelBody>
  148. </Panel>
  149. );
  150. }
  151. export default UpgradeGrouping;