From 9a69d54521a905c3040f992eb3f7fdc5d0da4e12 Mon Sep 17 00:00:00 2001 From: liangfung Date: Mon, 20 Jan 2025 14:49:17 +0800 Subject: [PATCH] update --- .../sso/components/ldap-credential-form.tsx | 16 ++++- .../sso/components/oauth-credential-form.tsx | 62 +++++++++++++++---- .../sso/components/sso-type-radio.tsx | 2 +- .../components/oauth-credential-detail.tsx | 5 +- .../components/ldap-credential-detail.tsx | 1 + .../sso/new/component/new-page.tsx | 40 +++++++----- 6 files changed, 92 insertions(+), 34 deletions(-) diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/sso/components/ldap-credential-form.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/sso/components/ldap-credential-form.tsx index eca1bafb668d..ee205bb82727 100644 --- a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/sso/components/ldap-credential-form.tsx +++ b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/sso/components/ldap-credential-form.tsx @@ -90,13 +90,18 @@ interface LDAPFormProps extends React.HTMLAttributes { isNew?: boolean defaultValues?: Partial | undefined onSuccess?: (formValues: LDAPFormValues) => void + existed?: boolean } +const providerExistedError = + 'LDAP provider already exists and cannot be created again.' + export function LDAPCredentialForm({ className, isNew, defaultValues, onSuccess, + existed, ...props }: LDAPFormProps) { const router = useRouter() @@ -157,7 +162,7 @@ export function LDAPCredentialForm({ .then(res => !!res?.data?.ldapCredential) if (hasExistingProvider) { form.setError('root', { - message: 'Provider already exists.' + message: providerExistedError }) return } @@ -205,8 +210,13 @@ export function LDAPCredentialForm({ return (
+ {existed && ( +
+ {providerExistedError} +
+ )} @@ -381,7 +391,7 @@ export function LDAPCredentialForm({ name="skipTlsVerify" render={({ field }) => ( - Connection security + Connection security
+const updateFormSchema = defaultFormSchema.extend({ + clientSecret: z.string().optional() +}) + +const providerExistedError = + 'Provider already exists. Please choose another one' interface OAuthCredentialFormProps extends React.HTMLAttributes { isNew?: boolean - provider: OAuthProvider - defaultValues?: Partial | undefined - onSuccess?: (formValues: OAuthCredentialFormValues) => void + defaultProvider: OAuthProvider + defaultValues?: Partial> | undefined + onSuccess?: (formValues: z.infer) => void + /** + * for creation, if there are existed providers, show a error message + */ + existedProviders?: OAuthProvider[] } export default function OAuthCredentialForm({ className, isNew, - provider, + defaultProvider, defaultValues, onSuccess, + existedProviders, ...props }: OAuthCredentialFormProps) { const router = useRouter() @@ -96,14 +106,26 @@ export default function OAuthCredentialForm({ const formatedDefaultValues = React.useMemo(() => { return { ...(defaultValues || {}), - provider + provider: defaultProvider || OAuthProvider.Github } }, []) const [deleteAlertVisible, setDeleteAlertVisible] = React.useState(false) const [isDeleting, setIsDeleting] = React.useState(false) - const form = useForm({ + const formSchema = React.useMemo(() => { + if (!isNew) return updateFormSchema + + return defaultFormSchema.extend({ + provider: z + .nativeEnum(OAuthProvider) + .refine(v => !existedProviders?.includes(v), { + message: providerExistedError + }) + }) + }, [isNew, existedProviders]) + + const form = useForm>({ resolver: zodResolver(formSchema), defaultValues: formatedDefaultValues }) @@ -125,16 +147,32 @@ export default function OAuthCredentialForm({ form }) + const provider = form.watch('provider') + + React.useEffect(() => { + if (!isNew) { + return + } + + if (provider && existedProviders?.includes(provider)) { + form.setError('provider', { + message: providerExistedError + }) + } else { + form.clearErrors('provider') + } + }, [provider, isNew, existedProviders]) + const deleteOAuthCredential = useMutation(deleteOauthCredentialMutation) - const onSubmit = async (values: OAuthCredentialFormValues) => { + const onSubmit = async (values: z.infer) => { if (isNew) { const hasExistingProvider = await client .query(oauthCredential, { provider: values.provider }) .then(res => !!res?.data?.oauthCredential) if (hasExistingProvider) { form.setError('provider', { - message: 'Provider already exists. Please choose another one' + message: providerExistedError }) return } diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/sso/components/sso-type-radio.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/sso/components/sso-type-radio.tsx index ec60c197d7a4..6a0f338abb51 100644 --- a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/sso/components/sso-type-radio.tsx +++ b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/sso/components/sso-type-radio.tsx @@ -17,7 +17,7 @@ export function SSOTypeRadio({ readonly }: SSOTypeRadioProps) { return ( -
+
= ({ >
diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/sso/detail/ldap/components/ldap-credential-detail.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/sso/detail/ldap/components/ldap-credential-detail.tsx index 04a05718c610..5a978ae1403b 100644 --- a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/sso/detail/ldap/components/ldap-credential-detail.tsx +++ b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/sso/detail/ldap/components/ldap-credential-detail.tsx @@ -44,6 +44,7 @@ export const LdapCredentialDetail: React.FC<
diff --git a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/sso/new/component/new-page.tsx b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/sso/new/component/new-page.tsx index b7e7b288a34d..68a87c8401bf 100644 --- a/ee/tabby-ui/app/(dashboard)/settings/(integrations)/sso/new/component/new-page.tsx +++ b/ee/tabby-ui/app/(dashboard)/settings/(integrations)/sso/new/component/new-page.tsx @@ -2,18 +2,18 @@ import { useState } from 'react' import { useRouter } from 'next/navigation' +import { compact } from 'lodash-es' +import { useQuery } from 'urql' import { OAuthProvider } from '@/lib/gql/generates/graphql' +import { ldapCredentialQuery, oauthCredential } from '@/lib/tabby/query' import { SSOType } from '@/lib/types' +import LoadingWrapper from '@/components/loading-wrapper' +import { ListSkeleton } from '@/components/skeleton' import { LDAPCredentialForm } from '../../components/ldap-credential-form' import OAuthCredentialForm from '../../components/oauth-credential-form' import { SSOTypeRadio } from '../../components/sso-type-radio' -import { useQuery } from 'urql' -import { ldapCredentialQuery, oauthCredential } from '@/lib/tabby/query' -import LoadingWrapper from '@/components/loading-wrapper' -import { ListSkeleton } from '@/components/skeleton' -import { compact } from 'lodash-es' export function NewPage() { const [type, setType] = useState('oauth') @@ -35,30 +35,38 @@ export function NewPage() { query: ldapCredentialQuery }) - const fetching = fetchingGithub || fetchingGoogle || fetchingGitlab || fetchingLdap - const isOauthAvaliable = compact([githubData?.oauthCredential, googleData?.oauthCredential, gitlabData?.oauthCredential]).length < 3 - const isLdapAvaliable = !ldapData?.ldapCredential + const fetchingProviders = + fetchingGithub || fetchingGoogle || fetchingGitlab || fetchingLdap + + const isLdapExisted = !!ldapData?.ldapCredential + const existedProviders = compact([ + githubData?.oauthCredential && OAuthProvider.Github, + googleData?.oauthCredential && OAuthProvider.Google, + gitlabData?.oauthCredential && OAuthProvider.Gitlab + ]) const onCreateSuccess = () => { router.replace('/settings/sso') } return ( - } - > + }>
{type === 'oauth' ? ( - + ) : ( { - router.replace('/settings/sso') - }} + onSuccess={onCreateSuccess} + existed={isLdapExisted} /> )}