Fix issue with credential selector, remove bigquery and ad support

This commit is contained in:
Theodore Li
2026-04-01 15:36:26 -07:00
parent 8f0efca279
commit f7b5055dfa
7 changed files with 45 additions and 10 deletions

View File

@@ -10,6 +10,8 @@ import { FAQ } from '@/components/ui/faq'
Google service accounts with domain-wide delegation let your workflows access Google APIs on behalf of users in your Google Workspace domain — without requiring each user to complete an OAuth consent flow. This is ideal for automated workflows that need to send emails, read spreadsheets, or manage files across your organization.
For example, you could build a workflow that iterates through a list of employees, impersonates each one to read their Google Docs, and uploads the contents to a shared knowledge base — all without requiring any of those users to sign in.
## Prerequisites
Before adding a service account to Sim, you need to configure it in the Google Cloud Console and Google Workspace Admin Console.
@@ -120,13 +122,11 @@ The table below lists every Google service that supports service account authent
<tr><td>Google Forms</td><td>Google Forms API, Google Drive API</td><td><code>{'https://www.googleapis.com/auth/drive'}</code><br/><code>{'https://www.googleapis.com/auth/forms.body'}</code><br/><code>{'https://www.googleapis.com/auth/forms.responses.readonly'}</code></td></tr>
<tr><td>Google Calendar</td><td>Google Calendar API</td><td><code>{'https://www.googleapis.com/auth/calendar'}</code></td></tr>
<tr><td>Google Contacts</td><td>People API</td><td><code>{'https://www.googleapis.com/auth/contacts'}</code></td></tr>
<tr><td>Google Ads</td><td>Google Ads API</td><td><code>{'https://www.googleapis.com/auth/adwords'}</code></td></tr>
<tr><td>BigQuery</td><td>BigQuery API</td><td><code>{'https://www.googleapis.com/auth/bigquery'}</code></td></tr>
<tr><td>Google Tasks</td><td>Tasks API</td><td><code>{'https://www.googleapis.com/auth/tasks'}</code></td></tr>
<tr><td>Google Vault</td><td>Vault API, Cloud Storage API</td><td><code>{'https://www.googleapis.com/auth/ediscovery'}</code><br/><code>{'https://www.googleapis.com/auth/devstorage.read_only'}</code></td></tr>
<tr><td>Google Groups</td><td>Admin SDK API</td><td><code>{'https://www.googleapis.com/auth/admin.directory.group'}</code><br/><code>{'https://www.googleapis.com/auth/admin.directory.group.member'}</code></td></tr>
<tr><td>Google Meet</td><td>Google Meet API</td><td><code>{'https://www.googleapis.com/auth/meetings.space.created'}</code><br/><code>{'https://www.googleapis.com/auth/meetings.space.readonly'}</code></td></tr>
<tr><td>Vertex AI</td><td>Vertex AI API</td><td><code>{'https://www.googleapis.com/auth/cloud-platform'}</code></td></tr>
</tbody>
</table>

View File

@@ -39,7 +39,8 @@ function toCredentialResponse(
displayName: string,
providerId: string,
updatedAt: Date,
scope: string | null
scope: string | null,
credentialType: 'oauth' | 'service_account' = 'oauth'
) {
const storedScope = scope?.trim()
// Some providers (e.g. Box) don't return scopes in their token response,
@@ -55,6 +56,7 @@ function toCredentialResponse(
id,
name: displayName,
provider: providerId,
type: credentialType,
lastUsed: updatedAt.toISOString(),
isDefault: featureType === 'default',
scopes,
@@ -197,7 +199,8 @@ export async function GET(request: NextRequest) {
platformCredential.displayName,
platformCredential.providerId || 'google-service-account',
platformCredential.updatedAt,
null
null,
'service_account'
),
],
},
@@ -322,7 +325,8 @@ export async function GET(request: NextRequest) {
sa.displayName,
sa.providerId || saProviderId,
sa.updatedAt,
null
null,
'service_account'
)
)
}

View File

@@ -98,8 +98,10 @@ export function CredentialSelector({
)
const provider = effectiveProviderId
const isTriggerMode = subBlock.mode === 'trigger'
const {
data: credentials = [],
data: rawCredentials = [],
isFetching: credentialsLoading,
refetch: refetchCredentials,
} = useOAuthCredentials(effectiveProviderId, {
@@ -108,13 +110,21 @@ export function CredentialSelector({
workflowId: activeWorkflowId || undefined,
})
const credentials = useMemo(
() =>
isTriggerMode
? rawCredentials.filter((cred) => cred.type !== 'service_account')
: rawCredentials,
[rawCredentials, isTriggerMode]
)
const selectedCredential = useMemo(
() => credentials.find((cred) => cred.id === selectedId),
[credentials, selectedId]
)
const isServiceAccount = useMemo(
() => selectedCredential?.provider?.endsWith('-service-account') ?? false,
() => selectedCredential?.type === 'service_account',
[selectedCredential]
)

View File

@@ -100,6 +100,12 @@ export function useEditorSubblockLayout(
const effectiveAdvanced = displayAdvancedMode
const canonicalModeOverrides = blockData?.canonicalModes
// Expose canonical mode overrides to condition functions so they can
// react to basic/advanced credential toggles (e.g. SERVICE_ACCOUNT_SUBBLOCKS).
if (canonicalModeOverrides) {
rawValues.__canonicalModes = canonicalModeOverrides
}
const visibleSubBlocks = (config.subBlocks || []).filter((block) => {
if (block.hidden) return false

View File

@@ -20,13 +20,29 @@ export const SERVICE_ACCOUNT_SUBBLOCKS: SubBlockConfig[] = [
title: 'Is Service Account',
type: 'short-input',
hidden: true,
mode: 'both',
},
{
id: 'impersonateUserEmail',
title: 'Impersonated Account',
type: 'short-input',
placeholder: 'Email to impersonate (for service accounts)',
condition: { field: 'isServiceAccount', value: 'true' },
paramVisibility: 'user-only',
condition: (values) => {
// In tool-input context (agent tools), __canonicalModes and isServiceAccount
// are absent — always show so users can configure impersonation.
const hasBlockEditorContext =
values?.__canonicalModes !== undefined || values?.isServiceAccount !== undefined
if (!hasBlockEditorContext) {
return { field: 'isServiceAccount', value: 'does-not-match', not: true }
}
const modes = values.__canonicalModes as Record<string, string> | undefined
if (modes?.oauthCredential === 'advanced') {
return { field: 'isServiceAccount', value: 'does-not-match', not: true }
}
return { field: 'isServiceAccount', value: 'true' }
},
mode: 'both',
},
]

View File

@@ -168,7 +168,6 @@ export const OAUTH_PROVIDERS: Record<string, OAuthProviderConfig> = {
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/adwords',
],
serviceAccountProviderId: 'google-service-account',
},
'google-bigquery': {
name: 'Google BigQuery',
@@ -258,7 +257,6 @@ export const OAUTH_PROVIDERS: Record<string, OAuthProviderConfig> = {
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/cloud-platform',
],
serviceAccountProviderId: 'google-service-account',
},
},
defaultService: 'gmail',

View File

@@ -136,6 +136,7 @@ export interface Credential {
id: string
name: string
provider: OAuthProvider
type?: 'oauth' | 'service_account'
serviceId?: string
lastUsed?: string
isDefault?: boolean