index.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import {Fragment} from 'react';
  2. import {RouteComponentProps} from 'react-router';
  3. import {hasEveryAccess} from 'sentry/components/acl/access';
  4. import Feature from 'sentry/components/acl/feature';
  5. import Form from 'sentry/components/forms/form';
  6. import JsonForm from 'sentry/components/forms/jsonForm';
  7. import ExternalLink from 'sentry/components/links/externalLink';
  8. import {fields} from 'sentry/data/forms/projectIssueGrouping';
  9. import {t, tct} from 'sentry/locale';
  10. import ProjectsStore from 'sentry/stores/projectsStore';
  11. import {EventGroupingConfig, Organization, Project} from 'sentry/types';
  12. import routeTitleGen from 'sentry/utils/routeTitle';
  13. import DeprecatedAsyncView from 'sentry/views/deprecatedAsyncView';
  14. import SettingsPageHeader from 'sentry/views/settings/components/settingsPageHeader';
  15. import TextBlock from 'sentry/views/settings/components/text/textBlock';
  16. import PermissionAlert from 'sentry/views/settings/project/permissionAlert';
  17. import UpgradeGrouping from './upgradeGrouping';
  18. type Props = RouteComponentProps<{projectId: string}, {}> & {
  19. organization: Organization;
  20. project: Project;
  21. };
  22. type State = {
  23. groupingConfigs: EventGroupingConfig[] | null;
  24. } & DeprecatedAsyncView['state'];
  25. class ProjectIssueGrouping extends DeprecatedAsyncView<Props, State> {
  26. getTitle() {
  27. const {projectId} = this.props.params;
  28. return routeTitleGen(t('Issue Grouping'), projectId, false);
  29. }
  30. getDefaultState() {
  31. return {
  32. ...super.getDefaultState(),
  33. groupingConfigs: [],
  34. };
  35. }
  36. getEndpoints(): ReturnType<DeprecatedAsyncView['getEndpoints']> {
  37. const {organization, project} = this.props;
  38. return [
  39. [
  40. 'groupingConfigs',
  41. `/projects/${organization.slug}/${project.slug}/grouping-configs/`,
  42. ],
  43. ];
  44. }
  45. handleSubmit = (response: Project) => {
  46. // This will update our project context
  47. ProjectsStore.onUpdateSuccess(response);
  48. };
  49. renderBody() {
  50. const {groupingConfigs} = this.state;
  51. const {organization, project, params, location} = this.props;
  52. const endpoint = `/projects/${organization.slug}/${project.slug}/`;
  53. const access = new Set(organization.access.concat(project.access));
  54. const hasAccess = hasEveryAccess(['project:write'], {organization, project});
  55. const jsonFormProps = {
  56. additionalFieldProps: {
  57. organization,
  58. groupingConfigs,
  59. },
  60. features: new Set(organization.features),
  61. access,
  62. disabled: !hasAccess,
  63. };
  64. return (
  65. <Fragment>
  66. <SettingsPageHeader title={t('Issue Grouping')} />
  67. <TextBlock>
  68. {tct(
  69. `All events have a fingerprint. Events with the same fingerprint are grouped together into an issue. To learn more about issue grouping, [link: read the docs].`,
  70. {
  71. link: (
  72. <ExternalLink href="https://docs.sentry.io/product/data-management-settings/event-grouping/" />
  73. ),
  74. }
  75. )}
  76. </TextBlock>
  77. <PermissionAlert project={project} />
  78. <Form
  79. saveOnBlur
  80. allowUndo
  81. initialData={project}
  82. apiMethod="PUT"
  83. apiEndpoint={endpoint}
  84. onSubmitSuccess={this.handleSubmit}
  85. >
  86. <JsonForm
  87. {...jsonFormProps}
  88. title={t('Fingerprint Rules')}
  89. fields={[fields.fingerprintingRules]}
  90. />
  91. <JsonForm
  92. {...jsonFormProps}
  93. title={t('Stack Trace Rules')}
  94. fields={[fields.groupingEnhancements]}
  95. />
  96. <Feature features={['set-grouping-config']} organization={organization}>
  97. <JsonForm
  98. {...jsonFormProps}
  99. title={t('Change defaults')}
  100. fields={[
  101. fields.groupingConfig,
  102. fields.secondaryGroupingConfig,
  103. fields.secondaryGroupingExpiry,
  104. ]}
  105. />
  106. </Feature>
  107. <JsonForm
  108. {...jsonFormProps}
  109. title={t('Automatic Grouping Updates')}
  110. fields={[fields.groupingAutoUpdate]}
  111. />
  112. <UpgradeGrouping
  113. groupingConfigs={groupingConfigs ?? []}
  114. organization={organization}
  115. projectId={params.projectId}
  116. project={project}
  117. api={this.api}
  118. onUpgrade={this.fetchData}
  119. location={location}
  120. />
  121. </Form>
  122. </Fragment>
  123. );
  124. }
  125. }
  126. export default ProjectIssueGrouping;