index.tsx 4.3 KB

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