upgradeGrouping.tsx 4.9 KB

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