Skip to content

Commit bef5d69

Browse files
authored
feat(core): add Airtable bubble (#169)
1 parent 3eebe61 commit bef5d69

13 files changed

Lines changed: 3354 additions & 1 deletion

File tree

9.94 KB
Loading

apps/bubble-studio/src/lib/integrations.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export const SERVICE_LOGOS: Readonly<Record<string, string>> = Object.freeze({
2828
'Follow Up Boss': '/integrations/FUB.png',
2929
'AGI Inc': '/integrations/agi-inc.svg',
3030
Telegram: '/integrations/telegram.svg',
31+
Airtable: '/integrations/airtable.png',
3132

3233
// AI models (also used as fallbacks for vendor names)
3334
GPT: '/integrations/gpt.svg',
@@ -67,6 +68,7 @@ export const INTEGRATIONS: IntegrationLogo[] = [
6768
{ name: 'ElevenLabs', file: SERVICE_LOGOS['ElevenLabs'] },
6869
{ name: 'Follow Up Boss', file: SERVICE_LOGOS['Follow Up Boss'] },
6970
{ name: 'Telegram', file: SERVICE_LOGOS['Telegram'] },
71+
{ name: 'Airtable', file: SERVICE_LOGOS['Airtable'] },
7072
];
7173

7274
// Scraping services (Apify actors and general web scraping)
@@ -125,6 +127,7 @@ const NAME_ALIASES: Readonly<Record<string, string>> = Object.freeze({
125127
agiinc: 'AGI Inc',
126128
agi: 'AGI Inc',
127129
telegram: 'Telegram',
130+
airtable: 'Airtable',
128131
'research-agent': 'Research Agent',
129132
'research-agent-tool': 'Research Agent',
130133
research: 'Research Agent',
@@ -219,6 +222,7 @@ export function findLogoForBubble(
219222
[/\bfollow\s*up\s*boss\b|\bfollowupboss\b|\bfub\b/, 'Follow Up Boss'],
220223
[/\bagi\s*inc\b|\bagi-inc\b|\bagiinc\b/, 'AGI Inc'],
221224
[/\btelegram\b/, 'Telegram'],
225+
[/\bairtable\b/, 'Airtable'],
222226
[/\bopenai\b|\bgpt\b/, 'GPT'],
223227
[/\banthropic\b|\bclaude\b/, 'Claude'],
224228
[/\bgemini\b/, 'Gemini'],
@@ -284,6 +288,7 @@ export function findDocsUrlForBubble(bubble: MinimalBubble): string | null {
284288
githubbubble: 'github-bubble',
285289
followupbossbubble: 'followupboss-bubble',
286290
telegrambubble: 'telegram-bubble',
291+
airtablebubble: 'airtable-bubble',
287292
}
288293
);
289294

@@ -327,6 +332,7 @@ export function findDocsUrlForBubble(bubble: MinimalBubble): string | null {
327332
followupboss: 'followupboss-bubble',
328333
fub: 'followupboss-bubble',
329334
telegram: 'telegram-bubble',
335+
airtable: 'airtable-bubble',
330336
});
331337

332338
// Known tool docs keyed by bubbleName variants

apps/bubble-studio/src/pages/CredentialsPage.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,14 @@ const CREDENTIAL_TYPE_CONFIG: Record<CredentialType, CredentialConfig> = {
218218
namePlaceholder: 'My Telegram Bot Token',
219219
credentialConfigurations: {},
220220
},
221+
[CredentialType.AIRTABLE_CRED]: {
222+
label: 'Airtable',
223+
description:
224+
'Personal Access Token for Airtable API (manage bases, tables, records)',
225+
placeholder: 'pat...',
226+
namePlaceholder: 'My Airtable Token',
227+
credentialConfigurations: {},
228+
},
221229
} as const satisfies Record<CredentialType, CredentialConfig>;
222230

223231
// Helper to extract error message from API error
@@ -264,6 +272,7 @@ const getServiceNameForCredentialType = (
264272
[CredentialType.FUB_CRED]: 'Follow Up Boss',
265273
[CredentialType.GITHUB_TOKEN]: 'GitHub',
266274
[CredentialType.ELEVENLABS_API_KEY]: 'ElevenLabs',
275+
[CredentialType.AIRTABLE_CRED]: 'Airtable',
267276
};
268277

269278
return typeToServiceMap[credentialType] || credentialType;

apps/bubblelab-api/src/services/credential-validator.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export class CredentialValidator {
2323
configurations?: Record<string, unknown>
2424
): Promise<CredentialValidationResult> {
2525
// Skip validation if explicitly requested
26+
// Skip Airtable validation because PATs have varying scopes and require specific base/table access
2627
if (skipValidation || credentialType === CredentialType.FIRECRAWL_API_KEY) {
2728
return { isValid: true };
2829
}
@@ -184,6 +185,11 @@ export class CredentialValidator {
184185
message: 'Hello, how are you?',
185186
};
186187
break;
188+
case CredentialType.AIRTABLE_CRED:
189+
baseParams.operation = 'list_records';
190+
baseParams.baseId = 'test-base-id';
191+
baseParams.tableIdOrName = 'test-table';
192+
break;
187193
default:
188194
break;
189195
}

0 commit comments

Comments
 (0)