import {Fragment} from 'react'; import {RouteComponentProps} from 'react-router'; import styled from '@emotion/styled'; import moment from 'moment'; import {disconnectIdentity} from 'sentry/actionCreators/account'; import {Alert} from 'sentry/components/alert'; import {Button} from 'sentry/components/button'; import Confirm from 'sentry/components/confirm'; import DateTime from 'sentry/components/dateTime'; import EmptyMessage from 'sentry/components/emptyMessage'; import Panel from 'sentry/components/panels/panel'; import PanelBody from 'sentry/components/panels/panelBody'; import PanelHeader from 'sentry/components/panels/panelHeader'; import PanelItem from 'sentry/components/panels/panelItem'; import Tag from 'sentry/components/tag'; import {t, tct} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import {UserIdentityCategory, UserIdentityConfig, UserIdentityStatus} from 'sentry/types'; import DeprecatedAsyncView from 'sentry/views/deprecatedAsyncView'; import IdentityIcon from 'sentry/views/settings/components/identityIcon'; import SettingsPageHeader from 'sentry/views/settings/components/settingsPageHeader'; import TextBlock from 'sentry/views/settings/components/text/textBlock'; const ENDPOINT = '/users/me/user-identities/'; type Props = RouteComponentProps<{}, {}>; type State = { identities: UserIdentityConfig[] | null; } & DeprecatedAsyncView['state']; class AccountIdentities extends DeprecatedAsyncView { getDefaultState() { return { ...super.getDefaultState(), identities: [], }; } getEndpoints(): ReturnType { return [['identities', ENDPOINT]]; } getTitle() { return t('Identities'); } renderItem = (identity: UserIdentityConfig) => { return ( {identity.provider.name} {identity.dateAdded && } {identity.category === UserIdentityCategory.SOCIAL_IDENTITY && ( {t('Legacy')} )} {identity.category !== UserIdentityCategory.ORG_IDENTITY && ( {identity.isLogin ? t('Sign In') : t('Integration')} )} {identity.organization && ( {identity.organization.slug} )} {this.renderButton(identity)} ); }; renderButton(identity: UserIdentityConfig) { return identity.status === UserIdentityStatus.CAN_DISCONNECT ? ( this.handleDisconnect(identity)} priority="danger" confirmText={t('Disconnect')} message={ {tct('Disconnect Your [provider] Identity?', { provider: identity.provider.name, })} {identity.isLogin ? t( 'After disconnecting, you will need to use a password or another identity to sign in.' ) : t("This action can't be undone.")} } > ) : ( ); } handleDisconnect = (identity: UserIdentityConfig) => { disconnectIdentity(identity, () => this.reloadData()); }; itemOrder = (a: UserIdentityConfig, b: UserIdentityConfig) => { function categoryRank(c: UserIdentityConfig) { return [ UserIdentityCategory.GLOBAL_IDENTITY, UserIdentityCategory.SOCIAL_IDENTITY, UserIdentityCategory.ORG_IDENTITY, ].indexOf(c.category); } if (a.provider.name !== b.provider.name) { return a.provider.name < b.provider.name ? -1 : 1; } if (a.category !== b.category) { return categoryRank(a) - categoryRank(b); } if ((a.organization?.name ?? '') !== (b.organization?.name ?? '')) { return (a.organization?.name ?? '') < (b.organization?.name ?? '') ? -1 : 1; } return 0; }; renderBody() { const appIdentities = this.state.identities ?.filter(identity => identity.category !== UserIdentityCategory.ORG_IDENTITY) .sort(this.itemOrder); const orgIdentities = this.state.identities ?.filter(identity => identity.category === UserIdentityCategory.ORG_IDENTITY) .sort(this.itemOrder); return ( {t('Application Identities')} {!appIdentities?.length ? ( {t( 'There are no application identities associated with your Sentry account' )} ) : ( appIdentities.map(this.renderItem) )} {t('Organization Identities')} {!orgIdentities?.length ? ( {t( 'There are no organization identities associated with your Sentry account' )} ) : ( orgIdentities.map(this.renderItem) )} ); } } const IdentityPanelItem = styled(PanelItem)` align-items: center; justify-content: space-between; `; const InternalContainer = styled('div')` display: flex; flex-direction: row; justify-content: center; `; const IdentityText = styled('div')<{isSingleLine?: boolean}>` height: 36px; display: flex; flex-direction: column; justify-content: ${p => (p.isSingleLine ? 'center' : 'space-between')}; margin-left: ${space(1.5)}; `; const IdentityName = styled('div')` font-weight: bold; `; const IdentityDateTime = styled(DateTime)` font-size: ${p => p.theme.fontSizeRelativeSmall}; color: ${p => p.theme.subText}; `; const TagWrapper = styled('div')` display: flex; align-items: center; justify-content: flex-start; flex-grow: 1; margin-right: ${space(1)}; `; export default AccountIdentities;