mirror of
https://github.com/lingble/twenty.git
synced 2025-10-30 12:22:29 +00:00
fix(sso): improve enterprise key var management (#8152)
Resolve https://github.com/twentyhq/twenty/issues/8070 --------- Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import { gql } from '@apollo/client';
|
|
||||||
import * as Apollo from '@apollo/client';
|
import * as Apollo from '@apollo/client';
|
||||||
|
import { gql } from '@apollo/client';
|
||||||
export type Maybe<T> = T | null;
|
export type Maybe<T> = T | null;
|
||||||
export type InputMaybe<T> = Maybe<T>;
|
export type InputMaybe<T> = Maybe<T>;
|
||||||
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
|
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
|
||||||
@@ -1283,6 +1283,7 @@ export type Workspace = {
|
|||||||
displayName?: Maybe<Scalars['String']>;
|
displayName?: Maybe<Scalars['String']>;
|
||||||
domainName?: Maybe<Scalars['String']>;
|
domainName?: Maybe<Scalars['String']>;
|
||||||
featureFlags?: Maybe<Array<FeatureFlag>>;
|
featureFlags?: Maybe<Array<FeatureFlag>>;
|
||||||
|
hasValidEntrepriseKey: Scalars['Boolean'];
|
||||||
id: Scalars['UUID'];
|
id: Scalars['UUID'];
|
||||||
inviteHash?: Maybe<Scalars['String']>;
|
inviteHash?: Maybe<Scalars['String']>;
|
||||||
isPublicInviteLinkEnabled: Scalars['Boolean'];
|
isPublicInviteLinkEnabled: Scalars['Boolean'];
|
||||||
@@ -1688,7 +1689,7 @@ export type ImpersonateMutationVariables = Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, analyticsTinybirdJwt?: string | null, onboardingStatus?: OnboardingStatus | null, userVars: any, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, metadataVersion: number, workspaceMembersCount?: number | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } };
|
export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, analyticsTinybirdJwt?: string | null, onboardingStatus?: OnboardingStatus | null, userVars: any, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, hasValidEntrepriseKey: boolean, metadataVersion: number, workspaceMembersCount?: number | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } };
|
||||||
|
|
||||||
export type RenewTokenMutationVariables = Exact<{
|
export type RenewTokenMutationVariables = Exact<{
|
||||||
appToken: Scalars['String'];
|
appToken: Scalars['String'];
|
||||||
@@ -1721,7 +1722,7 @@ export type VerifyMutationVariables = Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, analyticsTinybirdJwt?: string | null, onboardingStatus?: OnboardingStatus | null, userVars: any, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, metadataVersion: number, workspaceMembersCount?: number | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } };
|
export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, analyticsTinybirdJwt?: string | null, onboardingStatus?: OnboardingStatus | null, userVars: any, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, hasValidEntrepriseKey: boolean, metadataVersion: number, workspaceMembersCount?: number | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } };
|
||||||
|
|
||||||
export type CheckUserExistsQueryVariables = Exact<{
|
export type CheckUserExistsQueryVariables = Exact<{
|
||||||
email: Scalars['String'];
|
email: Scalars['String'];
|
||||||
@@ -1808,7 +1809,7 @@ export type ListSsoIdentityProvidersByWorkspaceIdQueryVariables = Exact<{ [key:
|
|||||||
|
|
||||||
export type ListSsoIdentityProvidersByWorkspaceIdQuery = { __typename?: 'Query', listSSOIdentityProvidersByWorkspaceId: Array<{ __typename?: 'FindAvailableSSOIDPOutput', type: IdpType, id: string, name: string, issuer: string, status: SsoIdentityProviderStatus }> };
|
export type ListSsoIdentityProvidersByWorkspaceIdQuery = { __typename?: 'Query', listSSOIdentityProvidersByWorkspaceId: Array<{ __typename?: 'FindAvailableSSOIDPOutput', type: IdpType, id: string, name: string, issuer: string, status: SsoIdentityProviderStatus }> };
|
||||||
|
|
||||||
export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, analyticsTinybirdJwt?: string | null, onboardingStatus?: OnboardingStatus | null, userVars: any, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, metadataVersion: number, workspaceMembersCount?: number | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> };
|
export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, analyticsTinybirdJwt?: string | null, onboardingStatus?: OnboardingStatus | null, userVars: any, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, hasValidEntrepriseKey: boolean, metadataVersion: number, workspaceMembersCount?: number | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> };
|
||||||
|
|
||||||
export type DeleteUserAccountMutationVariables = Exact<{ [key: string]: never; }>;
|
export type DeleteUserAccountMutationVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
@@ -1825,7 +1826,7 @@ export type UploadProfilePictureMutation = { __typename?: 'Mutation', uploadProf
|
|||||||
export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>;
|
export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, analyticsTinybirdJwt?: string | null, onboardingStatus?: OnboardingStatus | null, userVars: any, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, metadataVersion: number, workspaceMembersCount?: number | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> } };
|
export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, analyticsTinybirdJwt?: string | null, onboardingStatus?: OnboardingStatus | null, userVars: any, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, hasValidEntrepriseKey: boolean, metadataVersion: number, workspaceMembersCount?: number | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> } };
|
||||||
|
|
||||||
export type ActivateWorkflowVersionMutationVariables = Exact<{
|
export type ActivateWorkflowVersionMutationVariables = Exact<{
|
||||||
workflowVersionId: Scalars['String'];
|
workflowVersionId: Scalars['String'];
|
||||||
@@ -2062,6 +2063,7 @@ export const UserQueryFragmentFragmentDoc = gql`
|
|||||||
allowImpersonation
|
allowImpersonation
|
||||||
activationStatus
|
activationStatus
|
||||||
isPublicInviteLinkEnabled
|
isPublicInviteLinkEnabled
|
||||||
|
hasValidEntrepriseKey
|
||||||
featureFlags {
|
featureFlags {
|
||||||
id
|
id
|
||||||
key
|
key
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export type CurrentWorkspace = Pick<
|
|||||||
| 'currentBillingSubscription'
|
| 'currentBillingSubscription'
|
||||||
| 'workspaceMembersCount'
|
| 'workspaceMembersCount'
|
||||||
| 'isPublicInviteLinkEnabled'
|
| 'isPublicInviteLinkEnabled'
|
||||||
|
| 'hasValidEntrepriseKey'
|
||||||
| 'metadataVersion'
|
| 'metadataVersion'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ const Wrapper = getJestMetadataAndApolloMocksWrapper({
|
|||||||
featureFlags: [],
|
featureFlags: [],
|
||||||
allowImpersonation: false,
|
allowImpersonation: false,
|
||||||
activationStatus: WorkspaceActivationStatus.Active,
|
activationStatus: WorkspaceActivationStatus.Active,
|
||||||
|
hasValidEntrepriseKey: false,
|
||||||
metadataVersion: 1,
|
metadataVersion: 1,
|
||||||
isPublicInviteLinkEnabled: false,
|
isPublicInviteLinkEnabled: false,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,61 +1,40 @@
|
|||||||
/* @license Enterprise */
|
/* @license Enterprise */
|
||||||
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
|
|
||||||
import { SettingsSSOIdentitiesProvidersListEmptyStateCard } from '@/settings/security/components/SettingsSSOIdentitiesProvidersListEmptyStateCard';
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
import { SettingsSSOIdentityProviderRowRightContainer } from '@/settings/security/components/SettingsSSOIdentityProviderRowRightContainer';
|
import { SettingsCard } from '@/settings/components/SettingsCard';
|
||||||
|
import { SettingsSSOIdentitiesProvidersListCardWrapper } from '@/settings/security/components/SettingsSSOIdentitiesProvidersListCardWrapper';
|
||||||
import { SSOIdentitiesProvidersState } from '@/settings/security/states/SSOIdentitiesProviders.state';
|
import { SSOIdentitiesProvidersState } from '@/settings/security/states/SSOIdentitiesProviders.state';
|
||||||
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
import styled from '@emotion/styled';
|
||||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { useRecoilState } from 'recoil';
|
import { IconKey } from 'twenty-ui';
|
||||||
import { useListSsoIdentityProvidersByWorkspaceIdQuery } from '~/generated/graphql';
|
|
||||||
import { SettingsListCard } from '../../components/SettingsListCard';
|
const StyledLink = styled(Link)<{ isDisabled: boolean }>`
|
||||||
import { guessSSOIdentityProviderIconByUrl } from '../utils/guessSSOIdentityProviderIconByUrl';
|
pointer-events: ${({ isDisabled }) => (isDisabled ? 'none' : 'auto')};
|
||||||
|
text-decoration: none;
|
||||||
|
`;
|
||||||
|
|
||||||
export const SettingsSSOIdentitiesProvidersListCard = () => {
|
export const SettingsSSOIdentitiesProvidersListCard = () => {
|
||||||
const navigate = useNavigate();
|
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||||
const { enqueueSnackBar } = useSnackBar();
|
|
||||||
|
|
||||||
const [SSOIdentitiesProviders, setSSOIdentitiesProviders] = useRecoilState(
|
const SSOIdentitiesProviders = useRecoilValue(SSOIdentitiesProvidersState);
|
||||||
SSOIdentitiesProvidersState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { loading } = useListSsoIdentityProvidersByWorkspaceIdQuery({
|
return !SSOIdentitiesProviders.length ? (
|
||||||
onCompleted: (data) => {
|
<StyledLink
|
||||||
setSSOIdentitiesProviders(
|
to={getSettingsPagePath(SettingsPath.NewSSOIdentityProvider)}
|
||||||
data?.listSSOIdentityProvidersByWorkspaceId ?? [],
|
isDisabled={currentWorkspace?.hasValidEntrepriseKey !== true}
|
||||||
);
|
>
|
||||||
},
|
<SettingsCard
|
||||||
onError: (error: Error) => {
|
title="Add SSO Identity Provider"
|
||||||
enqueueSnackBar(error.message, {
|
disabled={currentWorkspace?.hasValidEntrepriseKey !== true}
|
||||||
variant: SnackBarVariant.Error,
|
Icon={<IconKey />}
|
||||||
});
|
/>
|
||||||
},
|
</StyledLink>
|
||||||
});
|
|
||||||
|
|
||||||
return !SSOIdentitiesProviders.length && !loading ? (
|
|
||||||
<SettingsSSOIdentitiesProvidersListEmptyStateCard />
|
|
||||||
) : (
|
) : (
|
||||||
<SettingsListCard
|
<SettingsSSOIdentitiesProvidersListCardWrapper />
|
||||||
items={SSOIdentitiesProviders}
|
|
||||||
getItemLabel={(SSOIdentityProvider) =>
|
|
||||||
`${SSOIdentityProvider.name} - ${SSOIdentityProvider.type}`
|
|
||||||
}
|
|
||||||
isLoading={loading}
|
|
||||||
RowIconFn={(SSOIdentityProvider) =>
|
|
||||||
guessSSOIdentityProviderIconByUrl(SSOIdentityProvider.issuer)
|
|
||||||
}
|
|
||||||
RowRightComponent={({ item: SSOIdp }) => (
|
|
||||||
<SettingsSSOIdentityProviderRowRightContainer SSOIdp={SSOIdp} />
|
|
||||||
)}
|
|
||||||
hasFooter
|
|
||||||
footerButtonLabel="Add SSO Identity Provider"
|
|
||||||
onFooterButtonClick={() =>
|
|
||||||
navigate(getSettingsPagePath(SettingsPath.NewSSOIdentityProvider))
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/* @license Enterprise */
|
||||||
|
|
||||||
|
import { guessSSOIdentityProviderIconByUrl } from '@/settings/security/utils/guessSSOIdentityProviderIconByUrl';
|
||||||
|
import { SettingsSSOIdentityProviderRowRightContainer } from '@/settings/security/components/SettingsSSOIdentityProviderRowRightContainer';
|
||||||
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
|
import { SettingsListCard } from '@/settings/components/SettingsListCard';
|
||||||
|
import { useListSsoIdentityProvidersByWorkspaceIdQuery } from '~/generated/graphql';
|
||||||
|
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
||||||
|
import { SSOIdentitiesProvidersState } from '@/settings/security/states/SSOIdentitiesProviders.state';
|
||||||
|
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||||
|
import { useRecoilState } from 'recoil';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
|
export const SettingsSSOIdentitiesProvidersListCardWrapper = () => {
|
||||||
|
const { enqueueSnackBar } = useSnackBar();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const [SSOIdentitiesProviders, setSSOIdentitiesProviders] = useRecoilState(
|
||||||
|
SSOIdentitiesProvidersState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { loading } = useListSsoIdentityProvidersByWorkspaceIdQuery({
|
||||||
|
onCompleted: (data) => {
|
||||||
|
setSSOIdentitiesProviders(
|
||||||
|
data?.listSSOIdentityProvidersByWorkspaceId ?? [],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onError: (error: Error) => {
|
||||||
|
enqueueSnackBar(error.message, {
|
||||||
|
variant: SnackBarVariant.Error,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SettingsListCard
|
||||||
|
items={SSOIdentitiesProviders}
|
||||||
|
getItemLabel={(SSOIdentityProvider) =>
|
||||||
|
`${SSOIdentityProvider.name} - ${SSOIdentityProvider.type}`
|
||||||
|
}
|
||||||
|
isLoading={loading}
|
||||||
|
RowIconFn={(SSOIdentityProvider) =>
|
||||||
|
guessSSOIdentityProviderIconByUrl(SSOIdentityProvider.issuer)
|
||||||
|
}
|
||||||
|
RowRightComponent={({ item: SSOIdp }) => (
|
||||||
|
<SettingsSSOIdentityProviderRowRightContainer SSOIdp={SSOIdp} />
|
||||||
|
)}
|
||||||
|
hasFooter
|
||||||
|
footerButtonLabel="Add SSO Identity Provider"
|
||||||
|
onFooterButtonClick={() =>
|
||||||
|
navigate(getSettingsPagePath(SettingsPath.NewSSOIdentityProvider))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
/* @license Enterprise */
|
|
||||||
|
|
||||||
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
|
||||||
import styled from '@emotion/styled';
|
|
||||||
import { Button, Card, CardContent, CardHeader, IconKey } from 'twenty-ui';
|
|
||||||
|
|
||||||
const StyledHeader = styled(CardHeader)`
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
height: ${({ theme }) => theme.spacing(6)};
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledBody = styled(CardContent)`
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const SettingsSSOIdentitiesProvidersListEmptyStateCard = () => {
|
|
||||||
return (
|
|
||||||
<Card>
|
|
||||||
<StyledHeader>{'No SSO Identity Providers Configured'}</StyledHeader>
|
|
||||||
<StyledBody>
|
|
||||||
<Button
|
|
||||||
Icon={IconKey}
|
|
||||||
title="Add SSO Identity Provider"
|
|
||||||
variant="secondary"
|
|
||||||
to={getSettingsPagePath(SettingsPath.NewSSOIdentityProvider)}
|
|
||||||
/>
|
|
||||||
</StyledBody>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -25,6 +25,7 @@ export const USER_QUERY_FRAGMENT = gql`
|
|||||||
allowImpersonation
|
allowImpersonation
|
||||||
activationStatus
|
activationStatus
|
||||||
isPublicInviteLinkEnabled
|
isPublicInviteLinkEnabled
|
||||||
|
hasValidEntrepriseKey
|
||||||
featureFlags {
|
featureFlags {
|
||||||
id
|
id
|
||||||
key
|
key
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { H2Title, Section } from 'twenty-ui';
|
import { H2Title, Section, IconLock, Tag } from 'twenty-ui';
|
||||||
|
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
import { SettingsReadDocumentationButton } from '@/settings/developers/components/SettingsReadDocumentationButton';
|
import { SettingsReadDocumentationButton } from '@/settings/developers/components/SettingsReadDocumentationButton';
|
||||||
@@ -23,7 +23,18 @@ export const SettingsSecurity = () => {
|
|||||||
>
|
>
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
<Section>
|
<Section>
|
||||||
<H2Title title="SSO" description="Configure an SSO connection" />
|
<H2Title
|
||||||
|
title="SSO"
|
||||||
|
description="Configure an SSO connection"
|
||||||
|
addornment={
|
||||||
|
<Tag
|
||||||
|
text={'Enterprise'}
|
||||||
|
color={'transparent'}
|
||||||
|
Icon={IconLock}
|
||||||
|
variant={'border'}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<SettingsSSOIdentitiesProvidersListCard />
|
<SettingsSSOIdentitiesProvidersListCard />
|
||||||
</Section>
|
</Section>
|
||||||
<Section>
|
<Section>
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ export const mockDefaultWorkspace: Workspace = {
|
|||||||
isPublicInviteLinkEnabled: true,
|
isPublicInviteLinkEnabled: true,
|
||||||
allowImpersonation: true,
|
allowImpersonation: true,
|
||||||
activationStatus: WorkspaceActivationStatus.Active,
|
activationStatus: WorkspaceActivationStatus.Active,
|
||||||
|
hasValidEntrepriseKey: false,
|
||||||
featureFlags: [
|
featureFlags: [
|
||||||
{
|
{
|
||||||
id: '1492de61-5018-4368-8923-4f1eeaf988c4',
|
id: '1492de61-5018-4368-8923-4f1eeaf988c4',
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorat
|
|||||||
import { DemoEnvGuard } from 'src/engine/guards/demo.env.guard';
|
import { DemoEnvGuard } from 'src/engine/guards/demo.env.guard';
|
||||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||||
import { streamToBuffer } from 'src/utils/stream-to-buffer';
|
import { streamToBuffer } from 'src/utils/stream-to-buffer';
|
||||||
|
import { isDefined } from 'src/utils/is-defined';
|
||||||
|
|
||||||
const getHMACKey = (email?: string, key?: string | null) => {
|
const getHMACKey = (email?: string, key?: string | null) => {
|
||||||
if (!email || !key) return null;
|
if (!email || !key) return null;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.
|
|||||||
|
|
||||||
import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
|
import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
|
||||||
import { BillingSubscriptionService } from 'src/engine/core-modules/billing/services/billing-subscription.service';
|
import { BillingSubscriptionService } from 'src/engine/core-modules/billing/services/billing-subscription.service';
|
||||||
|
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||||
import { FileUploadService } from 'src/engine/core-modules/file/file-upload/services/file-upload.service';
|
import { FileUploadService } from 'src/engine/core-modules/file/file-upload/services/file-upload.service';
|
||||||
import { FileService } from 'src/engine/core-modules/file/services/file.service';
|
import { FileService } from 'src/engine/core-modules/file/services/file.service';
|
||||||
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
|
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
|
||||||
@@ -26,6 +27,7 @@ import { DemoEnvGuard } from 'src/engine/guards/demo.env.guard';
|
|||||||
import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
|
import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
|
||||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||||
import { assert } from 'src/utils/assert';
|
import { assert } from 'src/utils/assert';
|
||||||
|
import { isDefined } from 'src/utils/is-defined';
|
||||||
import { streamToBuffer } from 'src/utils/stream-to-buffer';
|
import { streamToBuffer } from 'src/utils/stream-to-buffer';
|
||||||
|
|
||||||
import { Workspace } from './workspace.entity';
|
import { Workspace } from './workspace.entity';
|
||||||
@@ -38,6 +40,7 @@ export class WorkspaceResolver {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly workspaceService: WorkspaceService,
|
private readonly workspaceService: WorkspaceService,
|
||||||
private readonly userWorkspaceService: UserWorkspaceService,
|
private readonly userWorkspaceService: UserWorkspaceService,
|
||||||
|
private readonly environmentService: EnvironmentService,
|
||||||
private readonly fileUploadService: FileUploadService,
|
private readonly fileUploadService: FileUploadService,
|
||||||
private readonly fileService: FileService,
|
private readonly fileService: FileService,
|
||||||
private readonly billingSubscriptionService: BillingSubscriptionService,
|
private readonly billingSubscriptionService: BillingSubscriptionService,
|
||||||
@@ -136,4 +139,9 @@ export class WorkspaceResolver {
|
|||||||
|
|
||||||
return workspace.logo ?? '';
|
return workspace.logo ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ResolveField(() => Boolean)
|
||||||
|
hasValidEntrepriseKey(): boolean {
|
||||||
|
return isDefined(this.environmentService.get('ENTERPRISE_KEY'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,9 @@ const StyledTag = styled.h3<{
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding: 0 ${spacing2};
|
padding: 0 ${spacing2};
|
||||||
border: ${({ variant, theme }) =>
|
border: ${({ variant, theme }) =>
|
||||||
variant === 'outline' ? `1px dashed ${theme.border.color.strong}` : ''};
|
variant === 'outline' || variant === 'border'
|
||||||
|
? `1px ${variant === 'border' ? 'solid' : 'dash'} ${theme.border.color.strong}`
|
||||||
|
: ''};
|
||||||
|
|
||||||
gap: ${spacing1};
|
gap: ${spacing1};
|
||||||
|
|
||||||
@@ -65,7 +67,7 @@ const StyledIconContainer = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
type TagWeight = 'regular' | 'medium';
|
type TagWeight = 'regular' | 'medium';
|
||||||
type TagVariant = 'solid' | 'outline';
|
type TagVariant = 'solid' | 'outline' | 'border';
|
||||||
export type TagColor = ThemeColor | 'transparent';
|
export type TagColor = ThemeColor | 'transparent';
|
||||||
|
|
||||||
type TagProps = {
|
type TagProps = {
|
||||||
|
|||||||
Reference in New Issue
Block a user