Skip to content

Commit ee4f60c

Browse files
committed
fix(integrations): keep per-operation pagination values from leaking across operations and keep blank canvas custom field values
1 parent 3c8b19c commit ee4f60c

5 files changed

Lines changed: 89 additions & 15 deletions

File tree

‎apps/sim/blocks/blocks/airtable.test.ts‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,21 @@ describe('AirtableBlock typecast', () => {
105105
).toMatchObject({ recordIds: ['rec123'] })
106106
})
107107
})
108+
109+
describe('Airtable pagination offsets', () => {
110+
const mapParams = AirtableBlock.tools.config?.params
111+
if (!mapParams) throw new Error('Airtable block is missing its params mapper')
112+
113+
it('does not send a List Bases offset to List Records on the canvas', () => {
114+
const mapped = mapParams({ ...baseParams, operation: 'list', basesOffset: 'itrBases' })
115+
expect(mapped.offset).toBeUndefined()
116+
})
117+
118+
it('keeps the model offset on a List Records tool call', () => {
119+
const mapped = mapParams(
120+
{ ...baseParams, operation: 'list', offset: 'itrModel' },
121+
{ operation: 'list' }
122+
)
123+
expect(mapped.offset).toBe('itrModel')
124+
})
125+
})

‎apps/sim/blocks/blocks/airtable.ts‎

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { AirtableIcon } from '@/components/icons'
33
import { getScopesForService } from '@/lib/oauth/utils'
44
import type { BlockConfig, BlockMeta } from '@/blocks/types'
55
import { AuthMode, IntegrationType } from '@/blocks/types'
6+
import { toolCallArg } from '@/blocks/utils'
67
import { getTrigger } from '@/triggers'
78

89
/** Canonical account pair — an advanced-mode card only fills `manualCredential`. */
@@ -187,11 +188,19 @@ export const AirtableBlock: BlockConfig = {
187188
mode: 'advanced',
188189
},
189190
{
190-
id: 'offset',
191+
id: 'recordsOffset',
191192
title: 'Offset',
192193
type: 'short-input',
193194
placeholder: 'Pagination offset from a previous response',
194-
condition: { field: 'operation', value: ['listBases', 'list'] },
195+
condition: { field: 'operation', value: 'list' },
196+
mode: 'advanced',
197+
},
198+
{
199+
id: 'basesOffset',
200+
title: 'Offset',
201+
type: 'short-input',
202+
placeholder: 'Pagination offset from a previous response',
203+
condition: { field: 'operation', value: 'listBases' },
195204
mode: 'advanced',
196205
},
197206
{
@@ -407,9 +416,18 @@ Return ONLY the valid JSON array of record ID strings - no explanations, no mark
407416
throw new Error(`Invalid Airtable operation: ${params.operation}`)
408417
}
409418
},
410-
params: (params) => {
411-
const { oauthCredential, records, fields, fieldsToMergeOn, recordIds, typecast, ...rest } =
412-
params
419+
params: (params, context) => {
420+
const {
421+
oauthCredential,
422+
records,
423+
fields,
424+
fieldsToMergeOn,
425+
recordIds,
426+
typecast,
427+
recordsOffset,
428+
basesOffset,
429+
...rest
430+
} = params
413431
let parsedRecords: unknown
414432
let parsedFields: unknown
415433
let parsedFieldsToMergeOn: unknown
@@ -452,6 +470,16 @@ Return ONLY the valid JSON array of record ID strings - no explanations, no mark
452470
typecast != null ? { typecast: typecast === true || typecast === 'true' } : {}
453471

454472
switch (params.operation) {
473+
case 'list':
474+
return {
475+
...baseParams,
476+
offset: recordsOffset || toolCallArg(context, rest.offset) || undefined,
477+
}
478+
case 'listBases':
479+
return {
480+
...baseParams,
481+
offset: basesOffset || toolCallArg(context, rest.offset) || undefined,
482+
}
455483
case 'create':
456484
case 'updateMultiple':
457485
return { ...baseParams, records: parsedRecords, ...typecastParams }
@@ -483,7 +511,14 @@ Return ONLY the valid JSON array of record ID strings - no explanations, no mark
483511
filterFormula: { type: 'string', description: 'Filter formula expression' }, // Optional for list
484512
view: { type: 'string', description: 'View name or ID to list records from' },
485513
pageSize: { type: 'number', description: 'Records per page (max 100)' },
486-
offset: { type: 'string', description: 'Pagination offset from a previous response' },
514+
recordsOffset: {
515+
type: 'string',
516+
description: 'Pagination offset from a previous List Records response',
517+
},
518+
basesOffset: {
519+
type: 'string',
520+
description: 'Pagination offset from a previous List Bases response',
521+
},
487522
records: { type: 'json', description: 'Record data array' }, // Required for create/updateMultiple/upsert
488523
fields: { type: 'json', description: 'Field data object' }, // Required for update single
489524
fieldsToMergeOn: { type: 'json', description: 'Field names to match records on' }, // Required for upsert

‎apps/sim/blocks/blocks/clickup.ts‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ import { ClickUpIcon } from '@/components/icons'
22
import { getScopesForService } from '@/lib/oauth/utils'
33
import type { BlockConfig, BlockMeta } from '@/blocks/types'
44
import { AuthMode, IntegrationType } from '@/blocks/types'
5-
import { normalizeFileInput, parseOptionalBooleanInput, toolCallArg } from '@/blocks/utils'
5+
import {
6+
isToolCall,
7+
normalizeFileInput,
8+
parseOptionalBooleanInput,
9+
toolCallArg,
10+
} from '@/blocks/utils'
611
import { getTrigger } from '@/triggers'
712

813
const TIMESTAMP_WAND_PROMPT = `Generate a Unix timestamp in milliseconds based on the user's description.
@@ -1730,9 +1735,9 @@ Return ONLY the value (plain string, number, or JSON) - no explanations, no extr
17301735
taskId: params.taskId,
17311736
fieldId: params.fieldId,
17321737
value:
1733-
params.fieldValue !== undefined && params.fieldValue !== ''
1734-
? parseCustomFieldValue(params.fieldValue)
1735-
: toolCallArg(context, params.value),
1738+
isToolCall(context) && (params.fieldValue === undefined || params.fieldValue === '')
1739+
? params.value
1740+
: parseCustomFieldValue(params.fieldValue),
17361741
}
17371742
case 'remove_custom_field_value':
17381743
return {

‎apps/sim/blocks/blocks/monday.ts‎

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { MondayIcon } from '@/components/icons'
22
import { getScopesForService } from '@/lib/oauth/utils'
33
import type { BlockConfig, BlockMeta } from '@/blocks/types'
44
import { AuthMode, IntegrationType } from '@/blocks/types'
5+
import { toolCallArg } from '@/blocks/utils'
56
import { getTrigger } from '@/triggers'
67

78
const BOARD_OPS = [
@@ -468,13 +469,21 @@ export const MondayBlock: BlockConfig = {
468469
mode: 'advanced',
469470
condition: { field: 'operation', value: 'list_boards' },
470471
},
472+
{
473+
id: 'getItemsCursor',
474+
title: 'Cursor',
475+
type: 'short-input',
476+
placeholder: 'Pagination cursor from previous response',
477+
mode: 'advanced',
478+
condition: { field: 'operation', value: 'get_items' },
479+
},
471480
{
472481
id: 'cursor',
473482
title: 'Cursor',
474483
type: 'short-input',
475484
placeholder: 'Pagination cursor from previous response',
476485
mode: 'advanced',
477-
condition: { field: 'operation', value: ['get_items', 'search_items'] },
486+
condition: { field: 'operation', value: 'search_items' },
478487
},
479488
...getTrigger('monday_item_created').subBlocks,
480489
...getTrigger('monday_column_changed').subBlocks,
@@ -512,7 +521,7 @@ export const MondayBlock: BlockConfig = {
512521
const op = typeof params.operation === 'string' ? params.operation.trim() : 'list_boards'
513522
return `monday_${op}`
514523
},
515-
params: (params) => {
524+
params: (params, context) => {
516525
const baseParams: Record<string, unknown> = {
517526
oauthCredential: params.oauthCredential,
518527
}
@@ -535,7 +544,7 @@ export const MondayBlock: BlockConfig = {
535544
boardId: params.boardId,
536545
groupId: params.groupId || undefined,
537546
limit: params.limit ? Number(params.limit) : undefined,
538-
cursor: params.cursor || undefined,
547+
cursor: params.getItemsCursor || toolCallArg(context, params.cursor) || undefined,
539548
}
540549
case 'search_items':
541550
return {
@@ -663,7 +672,8 @@ export const MondayBlock: BlockConfig = {
663672
groupColor: { type: 'string', description: 'Group color hex code' },
664673
limit: { type: 'number', description: 'Maximum number of results' },
665674
page: { type: 'number', description: 'Page number for pagination' },
666-
cursor: { type: 'string', description: 'Pagination cursor for get items or search' },
675+
getItemsCursor: { type: 'string', description: 'Pagination cursor for get items' },
676+
cursor: { type: 'string', description: 'Pagination cursor for search items' },
667677
},
668678
outputs: {
669679
boards: {

‎apps/sim/tools/notion/utils.ts‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,14 @@ const NOTION_MAX_ARRAY_ELEMENTS = 100
7676
* surrogate pair is never split across two objects.
7777
*/
7878
export function toNotionRichText(
79-
content: string
79+
value: unknown
8080
): Array<{ type: 'text'; text: { content: string } }> {
81+
const content =
82+
typeof value === 'string'
83+
? value
84+
: value !== null && typeof value === 'object'
85+
? JSON.stringify(value)
86+
: String(value ?? '')
8187
const chunks: string[] = []
8288
let index = 0
8389
while (index < content.length) {

0 commit comments

Comments
 (0)