import {Fragment, useCallback, useMemo} from 'react';
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 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 PanelItem from 'sentry/components/panels/panelItem';
import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
import {Tag} from 'sentry/components/tag';
import {t, tct} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import type {UserIdentityConfig} from 'sentry/types';
import {UserIdentityCategory, UserIdentityStatus} from 'sentry/types';
import {setApiQueryData, useApiQuery, useQueryClient} from 'sentry/utils/queryClient';
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 EMPTY_ARRAY = [];
const IDENTITIES_ENDPOINT = '/users/me/user-identities/';
function 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);
}
const nameA = a.organization?.name ?? '';
const nameB = b.organization?.name ?? '';
return nameA.localeCompare(nameB);
}
interface IdentityItemProps {
identity: UserIdentityConfig;
onDisconnect: (identity: UserIdentityConfig) => void;
}
function IdentityItem({identity, onDisconnect}: IdentityItemProps) {
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}
)}
{identity.status === UserIdentityStatus.CAN_DISCONNECT ? (
onDisconnect(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.")}
}
>
) : (
)}
);
}
function AccountIdentities() {
const queryClient = useQueryClient();
const {
data: identities = EMPTY_ARRAY,
isLoading,
isError,
refetch,
} = useApiQuery([IDENTITIES_ENDPOINT], {
staleTime: 0,
});
const appIdentities = useMemo(
() =>
identities
.filter(identity => identity.category !== UserIdentityCategory.ORG_IDENTITY)
.sort(itemOrder),
[identities]
);
const orgIdentities = useMemo(
() =>
identities
.filter(identity => identity.category === UserIdentityCategory.ORG_IDENTITY)
.sort(itemOrder),
[identities]
);
const handleDisconnect = useCallback(
(identity: UserIdentityConfig) => {
disconnectIdentity(identity, () => {
setApiQueryData(queryClient, [IDENTITIES_ENDPOINT], oldData => {
if (!Array.isArray(oldData)) {
return oldData;
}
return oldData.filter(i => i.id !== identity.id);
});
});
},
[queryClient]
);
if (isLoading) {
return ;
}
if (isError) {
return ;
}
return (
{t('Application Identities')}
{!appIdentities.length ? (
{t(
'There are no application identities associated with your Sentry account'
)}
) : (
appIdentities.map(identity => (
))
)}
{t('Organization Identities')}
{!orgIdentities.length ? (
{t(
'There are no organization identities associated with your Sentry account'
)}
) : (
orgIdentities.map(identity => (
))
)}
);
}
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;