resourcesAndMaybeSolutions.tsx 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. import {css} from '@emotion/react';
  2. import styled from '@emotion/styled';
  3. import {AiSuggestedSolution} from 'sentry/components/events/aiSuggestedSolution';
  4. import {Autofix} from 'sentry/components/events/autofix';
  5. import {EventDataSection} from 'sentry/components/events/eventDataSection';
  6. import {Resources} from 'sentry/components/events/interfaces/performance/resources';
  7. import {t} from 'sentry/locale';
  8. import {space} from 'sentry/styles/space';
  9. import {EntryType, type Event, type Group, type Project} from 'sentry/types';
  10. import {
  11. getConfigForIssueType,
  12. shouldShowCustomErrorResourceConfig,
  13. } from 'sentry/utils/issueTypeConfig';
  14. import useOrganization from 'sentry/utils/useOrganization';
  15. type Props = {
  16. event: Event;
  17. group: Group;
  18. project: Project;
  19. };
  20. // This section provides users with resources and maybe solutions on how to resolve an issue
  21. export function ResourcesAndMaybeSolutions({event, project, group}: Props) {
  22. const organization = useOrganization();
  23. const config = getConfigForIssueType(group, project);
  24. const hasStacktrace = event.entries.some(
  25. entry => entry.type === EntryType.EXCEPTION || entry.type === EntryType.STACKTRACE
  26. );
  27. // NOTE: Autofix is for INTERNAL testing only for now.
  28. const displayAiAutofix =
  29. project.features.includes('ai-autofix') &&
  30. organization.features.includes('issue-details-autofix-ui') &&
  31. !shouldShowCustomErrorResourceConfig(group, project) &&
  32. config.autofix &&
  33. hasStacktrace;
  34. const displayAiSuggestedSolution =
  35. // Skip showing AI suggested solution if the issue has a custom resource
  36. organization.aiSuggestedSolution &&
  37. !shouldShowCustomErrorResourceConfig(group, project) &&
  38. !displayAiAutofix;
  39. if (!config.resources && !(displayAiSuggestedSolution || displayAiAutofix)) {
  40. return null;
  41. }
  42. return (
  43. <Wrapper
  44. type="resources-and-maybe-solutions"
  45. title={t('Resources and Maybe Solutions')}
  46. configResources={!!config.resources}
  47. >
  48. <Content>
  49. {config.resources && (
  50. <Resources
  51. eventPlatform={event.platform}
  52. groupId={group.id}
  53. configResources={config.resources}
  54. />
  55. )}
  56. {displayAiSuggestedSolution && (
  57. <AiSuggestedSolution event={event} projectSlug={project.slug} />
  58. )}
  59. {displayAiAutofix && <Autofix event={event} group={group} />}
  60. </Content>
  61. </Wrapper>
  62. );
  63. }
  64. const Content = styled('div')`
  65. display: flex;
  66. flex-direction: column;
  67. gap: ${space(2)};
  68. `;
  69. const Wrapper = styled(EventDataSection)<{configResources: boolean}>`
  70. @media (min-width: ${p => p.theme.breakpoints.xlarge}) {
  71. ${p =>
  72. !p.configResources &&
  73. css`
  74. && {
  75. padding-top: ${space(3)};
  76. }
  77. `}
  78. }
  79. `;