Skip to content

Commit 75fa2ff

Browse files
committed
improvement(salesforce): preserve picklist values and clear stale metadata on field type change
- custom field update now unions provided picklist values with the field's existing values instead of replacing the whole valueSet (no data loss) - when fieldType changes on update, drop the prior type's type-specific metadata (length/precision/scale/visibleLines/valueSet/defaultValue/unique/ externalId) and backfill the new type's required defaults
1 parent 5ea0e0c commit 75fa2ff

3 files changed

Lines changed: 48 additions & 4 deletions

File tree

apps/docs/content/docs/en/integrations/salesforce.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1089,7 +1089,7 @@ Update an existing custom field on a Salesforce object using the Tooling API
10891089
| `defaultValue` | string | No | Default value; for Checkbox fields use true or false |
10901090
| `description` | string | No | Internal description of the field |
10911091
| `inlineHelpText` | string | No | Help text shown next to the field in the UI |
1092-
| `picklistValues` | string | No | Comma-separated values for Picklist or MultiselectPicklist fields |
1092+
| `picklistValues` | string | No | Comma-separated values to add to a Picklist or MultiselectPicklist field \(existing values are kept\) |
10931093

10941094
#### Output
10951095

apps/sim/tools/salesforce/update_custom_field.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@ export const salesforceUpdateCustomFieldTool: ToolConfig<
126126
type: 'string',
127127
required: false,
128128
visibility: 'user-or-llm',
129-
description: 'Comma-separated values for Picklist or MultiselectPicklist fields',
129+
description:
130+
'Comma-separated values to add to a Picklist or MultiselectPicklist field (existing values are kept)',
130131
},
131132
},
132133

apps/sim/tools/salesforce/utils.ts

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,15 +172,44 @@ function applyProvidedFieldMetadata(
172172

173173
const picklistValues = parseDelimitedList(params.picklistValues)
174174
if (picklistValues.length > 0) {
175+
// Union with any existing values so an update adds new options without
176+
// dropping the field's current values (or their default flags).
177+
const existingValues: Array<Record<string, any>> = Array.isArray(
178+
target.valueSet?.valueSetDefinition?.value
179+
)
180+
? target.valueSet.valueSetDefinition.value
181+
: []
182+
const existingFullNames = new Set(existingValues.map((entry) => entry.fullName))
183+
const additions = picklistValues
184+
.filter((value) => !existingFullNames.has(value))
185+
.map((value) => ({ fullName: value, default: false, label: value }))
175186
target.valueSet = {
187+
...(target.valueSet ?? {}),
176188
valueSetDefinition: {
177-
sorted: false,
178-
value: picklistValues.map((value) => ({ fullName: value, default: false, label: value })),
189+
...(target.valueSet?.valueSetDefinition ?? {}),
190+
sorted: target.valueSet?.valueSetDefinition?.sorted ?? false,
191+
value: [...existingValues, ...additions],
179192
},
180193
}
181194
}
182195
}
183196

197+
/**
198+
* Type-specific metadata keys that do not carry across a field type change and
199+
* must be dropped when the type changes, so stale dimensions (e.g. a Text
200+
* `length` on a Checkbox) are not sent back to Salesforce.
201+
*/
202+
const TYPE_SPECIFIC_METADATA_KEYS = [
203+
'length',
204+
'precision',
205+
'scale',
206+
'visibleLines',
207+
'valueSet',
208+
'defaultValue',
209+
'unique',
210+
'externalId',
211+
] as const
212+
184213
/**
185214
* Applies type-specific defaults required by Salesforce when the caller did not
186215
* supply them, so common field types work out of the box on create.
@@ -255,7 +284,21 @@ export function mergeCustomFieldMetadata(
255284
params: CustomFieldMetadataInput
256285
): Record<string, any> {
257286
const metadata: Record<string, any> = { ...(existing ?? {}) }
287+
288+
const newType = params.fieldType?.trim()
289+
const typeChanged = Boolean(newType && existing?.type && newType !== existing.type)
290+
if (typeChanged) {
291+
// Changing the type invalidates the previous type's dimensions; drop them so
292+
// the PATCH does not carry stale metadata. Type-agnostic properties (label,
293+
// description, help text, required) are preserved.
294+
for (const key of TYPE_SPECIFIC_METADATA_KEYS) delete metadata[key]
295+
}
296+
258297
applyProvidedFieldMetadata(metadata, params)
298+
299+
// Backfill any properties the new type requires that the caller didn't supply.
300+
if (typeChanged) applyFieldTypeDefaults(metadata)
301+
259302
return metadata
260303
}
261304

0 commit comments

Comments
 (0)