import {Fragment, useMemo} from 'react'; import styled from '@emotion/styled'; import HighlightTopRightPattern from 'sentry-images/pattern/highlight-top-right.svg'; import {LinkButton} from 'sentry/components/button'; import {CompactSelect} from 'sentry/components/compactSelect'; import IdBadge from 'sentry/components/idBadge'; import {SdkDocumentation} from 'sentry/components/onboarding/gettingStartedDoc/sdkDocumentation'; import useCurrentProjectState from 'sentry/components/onboarding/gettingStartedDoc/utils/useCurrentProjectState'; import SidebarPanel from 'sentry/components/sidebar/sidebarPanel'; import type {CommonSidebarProps} from 'sentry/components/sidebar/types'; import {SidebarPanelKey} from 'sentry/components/sidebar/types'; import { customMetricOnboardingPlatforms, customMetricPlatforms, } from 'sentry/data/platformCategories'; import platforms from 'sentry/data/platforms'; import {t, tct} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import type {SelectValue} from 'sentry/types/core'; import type {Project} from 'sentry/types/project'; import {METRICS_DOCS_URL} from 'sentry/utils/metrics/constants'; import useOrganization from 'sentry/utils/useOrganization'; function MetricsOnboardingSidebar(props: CommonSidebarProps) { const {currentPanel, collapsed, hidePanel, orientation} = props; const organization = useOrganization(); const isActive = currentPanel === SidebarPanelKey.METRICS_ONBOARDING; const hasProjectAccess = organization.access.includes('project:read'); const { projects, allProjects, currentProject, setCurrentProject, supportedProjects, unsupportedProjects, hasDocs, } = useCurrentProjectState({ currentPanel, targetPanel: SidebarPanelKey.METRICS_ONBOARDING, onboardingPlatforms: customMetricOnboardingPlatforms, allPlatforms: customMetricPlatforms, }); const projectSelectOptions = useMemo(() => { const supportedProjectItems: SelectValue[] = supportedProjects .sort((aProject, bProject) => { // if we're comparing two projects w/ or w/o custom metrics alphabetical sort if (aProject.hasCustomMetrics === bProject.hasCustomMetrics) { return aProject.slug.localeCompare(bProject.slug); } // otherwise sort by whether or not they have custom metrics return aProject.hasCustomMetrics ? 1 : -1; }) .map(project => { return { value: project.id, textValue: project.id, label: ( ), }; }); const unsupportedProjectItems: SelectValue[] = unsupportedProjects.map( project => { return { value: project.id, textValue: project.id, label: ( ), disabled: true, }; } ); return [ { label: t('Supported'), options: supportedProjectItems, }, { label: t('Unsupported'), options: unsupportedProjectItems, }, ]; }, [supportedProjects, unsupportedProjects]); const selectedProject = currentProject ?? projects[0] ?? allProjects[0]; if (!isActive || !hasProjectAccess || !selectedProject) { return null; } return ( {t('Getting Started with custom metrics')}
{ // we need to stop bubbling the CompactSelect click event // failing to do so will cause the sidebar panel to close // the event.target will be unmounted by the time the panel listener // receives the event and assume the click was outside the panel e.stopPropagation(); }} > ) : ( t('Select a project') ) } value={currentProject?.id} onChange={opt => setCurrentProject(allProjects.find(p => p.id === opt.value)) } triggerProps={{'aria-label': currentProject?.slug}} options={projectSelectOptions} position="bottom-end" />
); } function OnboardingContent({ currentProject, hasDocs, }: { currentProject: Project; hasDocs: boolean; }) { const organization = useOrganization(); const currentPlatform = currentProject.platform ? platforms.find(p => p.id === currentProject.platform) : undefined; const supportsCustomMetrics = currentProject.platform && customMetricPlatforms.includes(currentProject.platform); if (!supportsCustomMetrics) { return (
{tct('Custom metrics aren’t available for your [platform] project.', { platform: currentPlatform?.name || currentProject.slug, })}
{t('Go to Sentry Documentation')}
); } if (!hasDocs || !currentPlatform) { return (
{tct( 'Fiddlesticks. This checklist isn’t available for your [project] project yet, but for now, go to Sentry docs for installation details.', {project: currentProject.slug} )}
{t('Read Docs')}
); } return ( {tct( `Adding custom metrics to your [platform] project is simple. Make sure you've got these basics down.`, {platform: currentPlatform?.name || currentProject.slug} )} ); } const IntroText = styled('div')` padding-top: ${space(3)}; `; const StyledSidebarPanel = styled(SidebarPanel)` width: 600px; max-width: 100%; `; const TopRightBackgroundImage = styled('img')` position: absolute; top: 0; right: 0; width: 60%; user-select: none; `; const TaskList = styled('div')` display: grid; grid-auto-flow: row; grid-template-columns: 100%; gap: ${space(1)}; margin: 50px ${space(4)} ${space(4)} ${space(4)}; `; const Heading = styled('div')` display: flex; color: ${p => p.theme.activeText}; font-size: ${p => p.theme.fontSizeExtraSmall}; text-transform: uppercase; font-weight: ${p => p.theme.fontWeightBold}; line-height: 1; margin-top: ${space(3)}; `; const StyledIdBadge = styled(IdBadge)` overflow: hidden; white-space: nowrap; flex-shrink: 1; `; const HeaderActions = styled('div')` display: flex; flex-direction: row; justify-content: space-between; gap: ${space(3)}; `; const FallbackContentWrapper = styled('div')` padding: ${space(2)} 0px; display: flex; flex-direction: column; gap: ${space(2)}; `; export default MetricsOnboardingSidebar;