diff --git a/static/app/utils/useSeerOnboardingCheck.tsx b/static/app/utils/useSeerOnboardingCheck.tsx new file mode 100644 index 00000000000000..e9bd07732137b5 --- /dev/null +++ b/static/app/utils/useSeerOnboardingCheck.tsx @@ -0,0 +1,20 @@ +import {useApiQuery} from 'sentry/utils/queryClient'; +import useOrganization from 'sentry/utils/useOrganization'; + +interface SeerOnboardingCheckResponse { + hasSupportedScmIntegration: boolean; + isAutofixEnabled: boolean; + isCodeReviewEnabled: boolean; + isSeerConfigured: boolean; +} + +export function useSeerOnboardingCheck() { + const organization = useOrganization(); + + return useApiQuery( + [`/organizations/${organization.slug}/seer/onboarding-check/`], + { + staleTime: 0, + } + ); +} diff --git a/static/gsApp/views/seerAutomation/components/seerSettingsPageWrapper.tsx b/static/gsApp/views/seerAutomation/components/seerSettingsPageWrapper.tsx index 149c274683f7d3..bf20b18e9cce11 100644 --- a/static/gsApp/views/seerAutomation/components/seerSettingsPageWrapper.tsx +++ b/static/gsApp/views/seerAutomation/components/seerSettingsPageWrapper.tsx @@ -14,6 +14,7 @@ import {useNavigate} from 'sentry/utils/useNavigate'; import useOrganization from 'sentry/utils/useOrganization'; import SettingsPageHeader from 'sentry/views/settings/components/settingsPageHeader'; +import SeerWizardSetupBanner from 'getsentry/views/seerAutomation/components/seerWizardSetupBanner'; import SettingsPageTabs from 'getsentry/views/seerAutomation/components/settingsPageTabs'; import useCanWriteSettings from 'getsentry/views/seerAutomation/components/useCanWriteSettings'; @@ -72,6 +73,8 @@ export default function SeerSettingsPageWrapper({children}: Props) { /> + + {canWrite ? null : ( diff --git a/static/gsApp/views/seerAutomation/components/seerWizardSetupBanner.tsx b/static/gsApp/views/seerAutomation/components/seerWizardSetupBanner.tsx new file mode 100644 index 00000000000000..65b194cbb7b187 --- /dev/null +++ b/static/gsApp/views/seerAutomation/components/seerWizardSetupBanner.tsx @@ -0,0 +1,69 @@ +import {ThemeProvider} from '@emotion/react'; +import styled from '@emotion/styled'; + +import seerConfigMainBg from 'sentry-images/spot/seer-config-main-bg.svg'; + +import {LinkButton} from '@sentry/scraps/button/linkButton'; +import {Container} from '@sentry/scraps/layout/container'; +import {Flex} from '@sentry/scraps/layout/flex'; +import {Grid} from '@sentry/scraps/layout/grid'; +import {Stack} from '@sentry/scraps/layout/stack'; +import {Heading} from '@sentry/scraps/text/heading'; +import {Text} from '@sentry/scraps/text/text'; + +import {IconSeer} from 'sentry/icons'; +import {t} from 'sentry/locale'; +import ConfigStore from 'sentry/stores/configStore'; +import {useLegacyStore} from 'sentry/stores/useLegacyStore'; +// eslint-disable-next-line no-restricted-imports +import {darkTheme, lightTheme} from 'sentry/utils/theme/theme'; +import useOrganization from 'sentry/utils/useOrganization'; +import {useSeerOnboardingCheck} from 'sentry/utils/useSeerOnboardingCheck'; + +export default function SeerWizardSetupBanner() { + const organization = useOrganization(); + const config = useLegacyStore(ConfigStore); + const invertedTheme = config.theme === 'dark' ? lightTheme : darkTheme; + + const {data, isFetched, isError} = useSeerOnboardingCheck(); + + if (!isFetched || isError) { + return null; + } + + if (data?.isSeerConfigured) { + return null; + } + + return ( + + + + + + {t('Meet Seer')} + {t('Get the most out of Sentry; use our wizard to set up Seer.')} + + + } + > + {t('Set Up Seer')} + + + + + + + ); +} + +const ImageContainer = styled('div')` + background-image: url(${seerConfigMainBg}); + background-size: cover; + background-position: center; + background-repeat: no-repeat; + border-radius: ${p => p.theme.radius.lg} 0 0 ${p => p.theme.radius.lg}; +`;