Skip to main content
Glama

mcp-google-sheets

oauth2-connection-settings.tsx14.8 kB
import { t } from 'i18next'; import { useEffect, useState } from 'react'; import { useFormContext } from 'react-hook-form'; import { Button } from '@/components/ui/button'; import { FormControl, FormField, FormItem, FormLabel, FormMessage, } from '@/components/ui/form'; import { Input } from '@/components/ui/input'; import { SkeletonList } from '@/components/ui/skeleton'; import { flagsHooks } from '@/hooks/flags-hooks'; import { platformHooks } from '@/hooks/platform-hooks'; import { oauth2Utils } from '@/lib/oauth2-utils'; import { OAuth2Property, OAuth2Props, PieceMetadataModel, PieceMetadataModelSummary, PropertyType, } from '@activepieces/pieces-framework'; import { resolveValueFromProps, ApEdition, ApFlagId, AppConnectionType, AppConnectionWithoutSensitiveData, BOTH_CLIENT_CREDENTIALS_AND_AUTHORIZATION_CODE, OAuth2GrantType, UpsertCloudOAuth2Request, UpsertOAuth2Request, UpsertPlatformOAuth2Request, isNil, } from '@activepieces/shared'; import { oauthAppsQueries, PieceToClientIdMap, } from '../../features/connections/lib/oauth-apps-hooks'; import { formUtils } from '../../features/pieces/lib/form-utils'; import { AutoPropertiesFormComponent } from '../builder/piece-properties/auto-properties-form'; type OAuth2ConnectionSettingsProps = { piece: PieceMetadataModelSummary | PieceMetadataModel; authProperty: OAuth2Property<OAuth2Props>; reconnectConnection: AppConnectionWithoutSensitiveData | null; }; const getOAuth2TypeAndApp = ( pieceToClientIdMap: PieceToClientIdMap, reconnectConnection: AppConnectionWithoutSensitiveData | null, pieceName: string, ) => { const platformApp = pieceToClientIdMap[`${pieceName}-${AppConnectionType.PLATFORM_OAUTH2}`] ?? null; const cloudApp = pieceToClientIdMap[`${pieceName}-${AppConnectionType.CLOUD_OAUTH2}`]; if ( reconnectConnection && reconnectConnection.type === AppConnectionType.OAUTH2 ) { return { type: AppConnectionType.OAUTH2 as OAuth2Type, app: null, }; } if (platformApp) { return { type: AppConnectionType.PLATFORM_OAUTH2 as OAuth2Type, app: platformApp, }; } if (cloudApp) { return { type: AppConnectionType.CLOUD_OAUTH2 as OAuth2Type, app: cloudApp, }; } return { type: AppConnectionType.OAUTH2 as OAuth2Type, app: null, }; }; const OAuth2ConnectionSettings = (props: OAuth2ConnectionSettingsProps) => { const { platform } = platformHooks.useCurrentPlatform(); const { data: edition } = flagsHooks.useFlag<ApEdition>(ApFlagId.EDITION); const { data: pieceToClientIdMap, isPending: loadingPieceToClientIdMap } = oauthAppsQueries.usePieceToClientIdMap(platform.cloudAuthEnabled, edition!); if (loadingPieceToClientIdMap || isNil(pieceToClientIdMap)) { return <SkeletonList numberOfItems={2} className="h-7"></SkeletonList>; } return ( <OAuth2ConnectionSettingsImplementation pieceToClientIdMap={pieceToClientIdMap} {...props} /> ); }; type OAuth2Type = | AppConnectionType.CLOUD_OAUTH2 | AppConnectionType.OAUTH2 | AppConnectionType.PLATFORM_OAUTH2; const OAuth2ConnectionSettingsImplementation = ({ authProperty, piece, reconnectConnection, pieceToClientIdMap, }: OAuth2ConnectionSettingsProps & { pieceToClientIdMap: PieceToClientIdMap; }) => { const [currentOAuth2Type, setOAuth2Type] = useState<OAuth2Type>( getOAuth2TypeAndApp(pieceToClientIdMap, reconnectConnection, piece.name) .type, ); const [grantType, setGrantType] = useState<OAuth2GrantType>( authProperty.grantType === BOTH_CLIENT_CREDENTIALS_AND_AUTHORIZATION_CODE ? OAuth2GrantType.AUTHORIZATION_CODE : authProperty.grantType ?? OAuth2GrantType.AUTHORIZATION_CODE, ); return ( <OAuth2ConnectionSettingsForm key={`${currentOAuth2Type}-${grantType}`} predefinedApp={ getOAuth2TypeAndApp(pieceToClientIdMap, reconnectConnection, piece.name) .app } authProperty={authProperty} currentOAuth2Type={currentOAuth2Type} currentGrantType={grantType} isNewConnection={isNil(reconnectConnection)} piece={piece} setOAuth2Type={setOAuth2Type} setGrantType={setGrantType} resetOAuth2Type={() => setOAuth2Type( getOAuth2TypeAndApp( pieceToClientIdMap, reconnectConnection, piece.name, ).type, ) } /> ); }; const doesPieceAllowSwitchingGrantType = ( piece: PieceMetadataModelSummary | PieceMetadataModel, ) => { return ( piece.auth?.type === PropertyType.OAUTH2 && piece.auth.grantType === BOTH_CLIENT_CREDENTIALS_AND_AUTHORIZATION_CODE ); }; type OAuth2ConnectionSettingsFormParams = { predefinedApp: { clientId: string; type: OAuth2Type; } | null; authProperty: OAuth2Property<OAuth2Props>; currentOAuth2Type: OAuth2Type; currentGrantType: OAuth2GrantType; isNewConnection: boolean; piece: PieceMetadataModelSummary | PieceMetadataModel; setOAuth2Type: (oauth2Type: OAuth2Type) => void; setGrantType: (grantType: OAuth2GrantType) => void; resetOAuth2Type: () => void; }; const OAuth2ConnectionSettingsForm = ({ predefinedApp, authProperty, currentOAuth2Type, currentGrantType, isNewConnection, piece, setOAuth2Type, setGrantType, resetOAuth2Type, }: OAuth2ConnectionSettingsFormParams) => { const { data: thirdPartyUrl } = flagsHooks.useFlag<string>( ApFlagId.THIRD_PARTY_AUTH_PROVIDER_REDIRECT_URL, ); const [readyToConnect, setReadyToConnect] = useState(false); const redirectUrl = currentOAuth2Type === AppConnectionType.CLOUD_OAUTH2 ? 'https://secrets.activepieces.com/redirect' : thirdPartyUrl; const form = useFormContext<{ request: | UpsertCloudOAuth2Request | UpsertOAuth2Request | UpsertPlatformOAuth2Request; }>(); const hasCode = form.getValues().request.value.code; useEffect(() => { form.setValue( 'request.value.redirect_url', redirectUrl ?? 'no_redirect_url_found', { shouldValidate: true, }, ); const defaultValuesForProps = Object.fromEntries( Object.entries( formUtils.getDefaultValueForStep({ props: authProperty.props ?? {}, existingInput: {}, }), ).map(([key, value]) => [key, value === undefined ? '' : value]), ); form.setValue('request.value.props', defaultValuesForProps, { shouldValidate: true, }); form.setValue( 'request.value.client_secret', currentOAuth2Type === AppConnectionType.OAUTH2 ? '' : 'FAKE_SECRET', { shouldValidate: true }, ); form.setValue( 'request.value.client_id', currentOAuth2Type === AppConnectionType.OAUTH2 ? '' : predefinedApp?.clientId ?? '', { shouldValidate: true }, ); form.setValue('request.value.grant_type', currentGrantType, { shouldValidate: true, }); form.setValue( 'request.value.code', currentGrantType === OAuth2GrantType.CLIENT_CREDENTIALS ? 'FAKE_CODE' : '', { shouldValidate: true }, ); form.setValue('request.value.code_challenge', '', { shouldValidate: true }); form.setValue('request.value.type', currentOAuth2Type, { shouldValidate: true, }); form.setValue('request.type', currentOAuth2Type, { shouldValidate: true }); }, []); form.watch((values) => { const baseCriteria = !isNil(redirectUrl) && !isNil(values.request?.value?.client_id); const clientSecret = (values.request as UpsertOAuth2Request)?.value ?.client_secret; const hasClientSecret = !isNil(clientSecret); const propsValues = values.request?.value?.props ?? {}; const arePropsValid = authProperty.props ? Object.keys(authProperty.props).reduce((acc, key) => { return ( acc && ((!isNil(propsValues[key]) && propsValues[key] !== '') || !authProperty.props?.[key]?.required) ); }, true) : true; setReadyToConnect( baseCriteria && (currentOAuth2Type !== AppConnectionType.OAUTH2 || hasClientSecret) && arePropsValid, ); }); const [refresh, setRefresh] = useState(0); const openPopup = async ( redirectUrl: string, clientId: string, props: Record<string, string> | undefined, ) => { const scope = resolveValueFromProps(props, authProperty.scope.join(' ')); const authUrl = resolveValueFromProps(props, authProperty.authUrl); const { code, codeChallenge } = await oauth2Utils.openOAuth2Popup({ authUrl, clientId, redirectUrl, scope, prompt: authProperty.prompt, pkce: authProperty.pkce ?? false, pkceMethod: authProperty.pkceMethod ?? 'plain', extraParams: authProperty.extra ?? {}, }); form.setValue('request.value.code', code, { shouldValidate: true }); form.setValue('request.value.code_challenge', codeChallenge, { shouldValidate: true, }); setRefresh(refresh + 1); }; return ( <div className="flex flex-col gap-4"> {currentOAuth2Type === AppConnectionType.OAUTH2 && authProperty.grantType !== OAuth2GrantType.CLIENT_CREDENTIALS && ( <div className="flex flex-col gap-2"> <FormLabel>{t('Redirect URL')}</FormLabel> <FormControl> <Input disabled type="text" value={redirectUrl ?? ''} /> </FormControl> <FormMessage /> </div> )} {currentOAuth2Type === AppConnectionType.OAUTH2 && ( <> <FormField name="request.value.client_id" control={form.control} render={({ field }) => ( <FormItem className="flex flex-col"> <FormLabel>{t('Client ID')}</FormLabel> <FormControl> <Input {...field} type="text" placeholder={t('Client ID')} /> </FormControl> <FormMessage /> </FormItem> )} ></FormField> <FormField name="request.value.client_secret" control={form.control} render={({ field }) => ( <FormItem className="flex flex-col"> <FormLabel>{t('Client Secret')}</FormLabel> <FormControl> <Input {...field} type="password" placeholder={t('Client Secret')} /> </FormControl> <FormMessage /> </FormItem> )} ></FormField> </> )} {authProperty.props && ( <AutoPropertiesFormComponent prefixValue="request.value.props" props={authProperty.props} useMentionTextInput={false} allowDynamicValues={false} /> )} {currentGrantType !== OAuth2GrantType.CLIENT_CREDENTIALS && ( <div className="border border-solid p-2 rounded-lg gap-2 flex text-center items-center justify-center h-full"> <div className="rounded-full border border-solid p-1 flex items-center justify-center"> <img src={piece.logoUrl} className="w-5 h-5"></img> </div> <div className="text-sm">{piece.displayName}</div> <div className="flex-grow"></div> {!hasCode && ( <Button size={'sm'} variant={'basic'} disabled={!readyToConnect} type="button" onClick={async () => openPopup( redirectUrl!, form.getValues().request.value.client_id, form.getValues().request.value.props, ) } > {t('Connect')} </Button> )} {hasCode && ( <Button size={'sm'} variant={'basic'} className="text-destructive" onClick={() => { form.setValue('request.value.code', '', { shouldValidate: true, }); form.setValue('request.value.code_challenge', '', { shouldValidate: true, }); }} > {t('Disconnect')} </Button> )} </div> )} {isNewConnection && currentOAuth2Type !== AppConnectionType.OAUTH2 && currentGrantType !== OAuth2GrantType.CLIENT_CREDENTIALS && ( <div> <Button size="sm" variant={'link'} className="text-xs" type="button" onClick={() => setOAuth2Type(AppConnectionType.OAUTH2)} > {t('I would like to use my own App Credentials')} </Button> </div> )} {currentOAuth2Type === AppConnectionType.OAUTH2 && isNewConnection && predefinedApp && currentGrantType !== OAuth2GrantType.CLIENT_CREDENTIALS && ( <div> <Button size="sm" variant={'link'} className="text-xs" type="button" onClick={() => setOAuth2Type(predefinedApp.type)} > {t('I would like to use predefined App Credentials')} </Button> </div> )} {doesPieceAllowSwitchingGrantType(piece) && ( <> {currentGrantType == OAuth2GrantType.AUTHORIZATION_CODE && ( <div> <Button size="sm" variant={'link'} className="text-xs" type="button" onClick={() => { setGrantType(OAuth2GrantType.CLIENT_CREDENTIALS); setOAuth2Type(AppConnectionType.OAUTH2); }} > {t('I would like to use Client Credentials')} </Button> </div> )} {currentGrantType === OAuth2GrantType.CLIENT_CREDENTIALS && ( <div> <Button size="sm" variant={'link'} type="button" className="text-xs" onClick={() => { setGrantType(OAuth2GrantType.AUTHORIZATION_CODE); resetOAuth2Type(); }} > {t('I would like to use Authorization Code')} </Button> </div> )} </> )} </div> ); }; OAuth2ConnectionSettings.displayName = 'OAuth2ConnectionSettings'; export { OAuth2ConnectionSettings };

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/activepieces/activepieces'

If you have feedback or need assistance with the MCP directory API, please join our Discord server