import styled from '@emotion/styled'; import startCase from 'lodash/startCase'; import {Alert} from 'sentry/components/alert'; import {Button} from 'sentry/components/button'; import Link from 'sentry/components/links/link'; import PanelItem from 'sentry/components/panels/panelItem'; import {t} from 'sentry/locale'; import PluginIcon from 'sentry/plugins/components/pluginIcon'; import {space} from 'sentry/styles/space'; import type { IntegrationInstallationStatus, Organization, PluginWithProjectList, SentryApp, } from 'sentry/types'; import { convertIntegrationTypeToSnakeCase, trackIntegrationAnalytics, } from 'sentry/utils/integrationUtil'; import AlertContainer from './integrationAlertContainer'; import IntegrationStatus from './integrationStatus'; import PluginDeprecationAlert from './pluginDeprecationAlert'; type Props = { categories: string[]; configurations: number; displayName: string; organization: Organization; publishStatus: 'unpublished' | 'published' | 'internal'; slug: string; type: 'plugin' | 'firstParty' | 'sentryApp' | 'docIntegration'; /** * If provided, render an alert message with this text. */ alertText?: string; customAlert?: React.ReactNode; customIcon?: React.ReactNode; plugin?: PluginWithProjectList; /** * If `alertText` was provided, this text overrides the "Resolve now" message * in the alert. */ resolveText?: string; status?: IntegrationInstallationStatus; }; const urlMap = { plugin: 'plugins', firstParty: 'integrations', sentryApp: 'sentry-apps', docIntegration: 'document-integrations', }; function IntegrationRow(props: Props) { const { organization, type, slug, displayName, status, publishStatus, configurations, categories, alertText, resolveText, plugin, customAlert, customIcon, } = props; const baseUrl = publishStatus === 'internal' ? `/settings/${organization.slug}/developer-settings/${slug}/` : `/settings/${organization.slug}/${urlMap[type]}/${slug}/`; const renderDetails = () => { if (type === 'sentryApp') { return publishStatus !== 'published' && ; } // TODO: Use proper translations return configurations > 0 ? ( {`${configurations} Configuration${ configurations > 1 ? 's' : '' }`} ) : null; }; const renderStatus = () => { // status should be undefined for document integrations if (status) { return ; } return {t('Learn More')}; }; return ( {customIcon ?? } {displayName} {renderStatus()} {renderDetails()} {categories?.map(category => ( ))} {alertText && ( trackIntegrationAnalytics('integrations.resolve_now_clicked', { integration_type: convertIntegrationTypeToSnakeCase(type), integration: slug, organization, }) } > {resolveText || t('Resolve Now')} } > {alertText} )} {customAlert} {plugin?.deprecationDate && ( )} ); } const PluginDeprecationAlertWrapper = styled('div')` padding: 0px ${space(3)} 0px 68px; `; const PanelRow = styled(PanelItem)` flex-direction: column; `; const FlexContainer = styled('div')` display: flex; align-items: center; padding: ${space(2)}; `; const TitleContainer = styled('div')` flex: 1; padding: 0 16px; white-space: nowrap; `; const TagsContainer = styled('div')` flex: 3; text-align: right; padding: 0 ${space(2)}; `; const IntegrationName = styled(Link)` font-weight: bold; `; const IntegrationDetails = styled('div')` display: flex; align-items: center; font-size: ${p => p.theme.fontSizeSmall}; `; const StyledLink = styled(Link)` color: ${p => p.theme.gray300}; &:before { content: '|'; color: ${p => p.theme.gray200}; margin-right: ${space(0.75)}; } `; const LearnMore = styled(Link)` color: ${p => p.theme.gray300}; `; type PublishStatusProps = {status: SentryApp['status']; theme?: any}; const PublishStatus = styled(({status, ...props}: PublishStatusProps) => (
{status}
))` color: ${(props: PublishStatusProps) => props.status === 'published' ? props.theme.success : props.theme.gray300}; font-weight: light; margin-right: ${space(0.75)}; text-transform: capitalize; &:before { content: '|'; color: ${p => p.theme.gray200}; margin-right: ${space(0.75)}; font-weight: normal; } `; // TODO(Priscila): Replace this component with the Tag component const CategoryTag = styled( ({ priority: _priority, category, ...p }: { category: string; priority: boolean; theme?: any; }) =>
{category}
)` display: inline-block; padding: 1px 10px; background: ${p => (p.priority ? p.theme.purple200 : p.theme.gray100)}; border-radius: 20px; font-size: ${space(1.5)}; margin: ${space(0.25)} ${space(0.5)}; line-height: ${space(3)}; text-align: center; color: ${p => (p.priority ? p.theme.white : p.theme.gray500)}; `; const ResolveNowButton = styled(Button)` color: ${p => p.theme.subText}; float: right; `; export default IntegrationRow;