import {Fragment} from 'react'; import styled from '@emotion/styled'; import {addErrorMessage, addSuccessMessage} from 'sentry/actionCreators/indicator'; import {hasEveryAccess} from 'sentry/components/acl/access'; import {Button} from 'sentry/components/button'; import Confirm from 'sentry/components/confirm'; import EmptyMessage from 'sentry/components/emptyMessage'; import TextField from 'sentry/components/forms/fields/textField'; import ExternalLink from 'sentry/components/links/externalLink'; import LoadingError from 'sentry/components/loadingError'; import LoadingIndicator from 'sentry/components/loadingIndicator'; import Panel from 'sentry/components/panels/panel'; import PanelBody from 'sentry/components/panels/panelBody'; import PanelHeader from 'sentry/components/panels/panelHeader'; import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle'; import {Tooltip} from 'sentry/components/tooltip'; import {IconDelete} from 'sentry/icons'; import {t, tct} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import type {ExternalTeam, Integration} from 'sentry/types/integrations'; import type {Team} from 'sentry/types/organization'; import {useApiQuery} from 'sentry/utils/queryClient'; import {toTitleCase} from 'sentry/utils/string/toTitleCase'; import useApi from 'sentry/utils/useApi'; import useOrganization from 'sentry/utils/useOrganization'; import {useParams} from 'sentry/utils/useParams'; import {ProjectPermissionAlert} from 'sentry/views/settings/project/projectPermissionAlert'; const DOCS_LINK = 'https://docs.sentry.io/product/integrations/notification-incidents/slack/#team-notifications'; const NOTIFICATION_PROVIDERS = ['slack']; function TeamNotificationSettingsPanel({ team, integrations, onDelete, }: { integrations: Integration[]; onDelete: (externalTeam: ExternalTeam) => void; team: Team; }) { const organization = useOrganization(); const notificationIntegrations = integrations.filter(integration => NOTIFICATION_PROVIDERS.includes(integration.provider.key) ); if (!notificationIntegrations.length) { return ( {t('No Notification Integrations have been installed yet.')} ); } const externalTeams = (team.externalTeams ?? []).filter(externalTeam => NOTIFICATION_PROVIDERS.includes(externalTeam.provider) ); if (!externalTeams.length) { return ( {t('No teams have been linked yet.')} {tct('Head over to Slack and type [code] to get started. [link].', { code: /sentry link team, link: {t('Learn more')}, })} ); } const integrationsById = Object.fromEntries( notificationIntegrations.map(integration => [integration.id, integration]) ); const hasWriteAccess = hasEveryAccess(['team:write'], {organization, team}); return externalTeams.map(externalTeam => ( {toTitleCase(externalTeam.provider)}: {integrationsById[externalTeam.integrationId]!.name} {tct('Unlink this channel in Slack with [code]. [link].', { code: /sentry unlink team, link: {t('Learn more')}, })} } labelText={t('Unlink this channel in slack with `/slack unlink team`')} name="externalName" value={externalTeam.externalName} /> onDelete(externalTeam)} message={t('Are you sure you want to remove this Slack team link?')} > } disabled={!hasWriteAccess}> {t('Unlink')} )); } function TeamNotificationSettings() { const api = useApi(); const params = useParams<{teamId: string}>(); const organization = useOrganization(); const { data: team, isPending: isTeamPending, isError: isTeamError, refetch: refetchTeam, } = useApiQuery( [ `/teams/${organization.slug}/${params.teamId}/`, { query: {expand: ['externalTeams']}, }, ], { staleTime: 0, } ); const { data: integrations, isPending: isIntegrationsPending, isError: isIntegrationsError, refetch: refetchIntegrations, } = useApiQuery( [ `/organizations/${organization.slug}/integrations/`, { query: {includeConfig: '0'}, }, ], { staleTime: 0, } ); if (isTeamPending || isIntegrationsPending) { return ; } if (isTeamError || isIntegrationsError) { return ( { refetchTeam(); refetchIntegrations(); }} /> ); } const handleDelete = async (externalTeam: ExternalTeam) => { try { await api.requestPromise( `/teams/${organization.slug}/${team.slug}/external-teams/${externalTeam.id}/`, { method: 'DELETE', } ); addSuccessMessage(t('Deletion successful')); } catch { addErrorMessage(t('An error occurred')); } refetchTeam(); refetchIntegrations(); }; return ( {t('Notifications')} ); } export default TeamNotificationSettings; const NotDisabledText = styled('div')` color: ${p => p.theme.textColor}; line-height: ${space(2)}; `; const NotDisabledSubText = styled('div')` color: ${p => p.theme.subText}; font-size: ${p => p.theme.fontSizeRelativeSmall}; line-height: 1.4; margin-top: ${space(1)}; `; const FormFieldWrapper = styled('div')` display: flex; align-items: center; justify-content: flex-start; `; const StyledFormField = styled(TextField)` flex: 1; `; const DeleteButtonWrapper = styled('div')` margin-right: ${space(2)}; `;
/sentry link team
/sentry unlink team