import {Fragment, useCallback, useEffect, useState} from 'react'; import styled from '@emotion/styled'; import {addSuccessMessage} from 'sentry/actionCreators/indicator'; import {Button} from 'sentry/components/button'; import ButtonBar from 'sentry/components/buttonBar'; import EmptyMessage from 'sentry/components/emptyMessage'; import FeatureBadge from 'sentry/components/featureBadge'; import {feedbackClient} from 'sentry/components/featureFeedback/feedbackModal'; import LoadingError from 'sentry/components/loadingError'; import {Panel, PanelBody, PanelFooter, PanelHeader} from 'sentry/components/panels'; import {IconFile, IconFlag, IconHappy, IconMeh, IconSad} from 'sentry/icons'; import {IconChevron} from 'sentry/icons/iconChevron'; import {t} from 'sentry/locale'; import ConfigStore from 'sentry/stores/configStore'; import {space} from 'sentry/styles/space'; import {isActiveSuperuser} from 'sentry/utils/isActiveSuperuser'; import marked from 'sentry/utils/marked'; import {useApiQuery} from 'sentry/utils/queryClient'; import useOrganization from 'sentry/utils/useOrganization'; import useRouter from 'sentry/utils/useRouter'; import {AiLoaderMessage} from 'sentry/views/issueDetails/openAIFixSuggestion/aiLoaderMessage'; import {useOpenAISuggestionLocalStorage} from 'sentry/views/issueDetails/openAIFixSuggestion/useOpenAISuggestionLocalStorage'; import {experimentalFeatureTooltipDesc} from 'sentry/views/issueDetails/openAIFixSuggestion/utils'; enum OpenAISatisfactoryLevel { HELPED = 'helped', PARTIALLY_HELPED = 'partially_helped', DID_NOT_HELP = 'did_not_help', } const openAIFeedback = { [OpenAISatisfactoryLevel.HELPED]: t('It helped me solve the issue'), [OpenAISatisfactoryLevel.PARTIALLY_HELPED]: t('It partially helped me solve the issue'), [OpenAISatisfactoryLevel.DID_NOT_HELP]: t('It did not help me solve the issue'), }; type Props = { eventID: string; projectSlug: string; }; export function OpenAIFixSuggestionPanel({eventID, projectSlug}: Props) { const user = ConfigStore.get('user'); const organization = useOrganization(); const router = useRouter(); const showSuggestedFix = router.location.query.showSuggestedFix === 'true'; const [individualConsent, setIndividualConsent] = useOpenAISuggestionLocalStorage(); const [expandedSuggestedFix, setExpandedSuggestedFix] = useState(showSuggestedFix); useEffect(() => { setExpandedSuggestedFix(!!router.location.query.showSuggestedFix); }, [router.location.query.showSuggestedFix]); const handleOpenAISuggestionFeedback = useCallback( (openAISatisfactoryLevel: OpenAISatisfactoryLevel) => { feedbackClient.captureEvent({ request: { url: window.location.href, // gives the full url (origin + pathname) }, tags: { featureName: 'open-ai-suggestion', }, user, level: 'info', message: `OpenAI Suggestion Feedback - ${openAIFeedback[openAISatisfactoryLevel]}`, }); addSuccessMessage('Thank you for your feedback!'); setExpandedSuggestedFix(false); }, [user] ); const { data, isLoading: dataIsLoading, isError: dataIsError, refetch: dataRefetch, error, } = useApiQuery<{suggestion: string}>( [ `/projects/${organization.slug}/${projectSlug}/events/${eventID}/ai-fix-suggest/`, {query: {consent: individualConsent ? 'yes' : undefined}}, ], { staleTime: Infinity, retry: false, enabled: showSuggestedFix, } ); let PolicyErrorState; if (error?.responseJSON?.restriction === 'subprocessor') { PolicyErrorState = ( } title={t('OpenAI Subprocessor Acknowledgment')} description={t( 'In order to use this feature, your organization needs to accept the OpenAI Subprocessor Acknowledgment.' )} action={ } /> ); } if (error?.responseJSON?.restriction === 'individual_consent') { const activeSuperUser = isActiveSuperuser(); PolicyErrorState = ( } title={t('We need your consent')} description={t( 'By using this feature, you agree that OpenAI is a subprocessor and may process the data that you’ve chosen to submit. Sentry makes no guarantees as to the accuracy of the feature’s AI-generated recommendations.' )} action={ } /> ); } if (!organization.features.includes('open-ai-suggestion')) { return null; } if (!showSuggestedFix) { return null; } return ( {t('Suggested Fix')}