Skip to main content
Glama

mcp-google-sheets

update-item.ts13.3 kB
import { createAction, Property } from '@activepieces/pieces-framework'; import { HttpMethod } from '@activepieces/pieces-common'; import { podioAuth } from '../../index'; import { podioApiCall, getAccessToken, silentProperty, hookProperty, dynamicAppProperty, dynamicItemProperty, formatFieldValues } from '../common'; export const updateItemAction = createAction({ auth: podioAuth, name: 'update_item', displayName: 'Update Item', description: 'Update an existing record in a Podio app with specified field values. Only provided fields will be updated.', props: { appId: dynamicAppProperty, itemId: dynamicItemProperty, appFields: Property.DynamicProperties({ displayName: 'App Fields', description: 'Configure values for the fields you want to update in the selected app', required: false, refreshers: ['appId'], props: async ({ auth, appId }) => { if (!auth || !appId) { return {}; } try { const accessToken = getAccessToken(auth as any); const app = await podioApiCall<any>({ method: HttpMethod.GET, accessToken, resourceUri: `/app/${appId}`, queryParams: { view: 'full' } }); const fields = app.fields || []; if (!fields || fields.length === 0) { return {}; } const fieldProperties: Record<string, any> = {}; for (const field of fields) { try { const fieldKey = `field_${field.field_id}`; const fieldConfig = field.config; const fieldType = field.type; const isRequired = false; const baseProps = { displayName: fieldConfig.label, description: fieldConfig.description || `Update value for ${fieldConfig.label}`, required: isRequired, }; switch (fieldType) { case 'text': fieldProperties[fieldKey] = Property.LongText({ ...baseProps, description: `${baseProps.description}. Supports plain text, markdown, or HTML.`, }); break; case 'number': fieldProperties[fieldKey] = Property.Number({ ...baseProps, description: `${baseProps.description}. Enter a numeric value.`, }); break; case 'money': fieldProperties[fieldKey] = Property.Object({ ...baseProps, description: `${baseProps.description}. Format: {"value": "amount", "currency": "USD"}`, }); break; case 'date': fieldProperties[fieldKey] = Property.Object({ ...baseProps, description: `${baseProps.description}. Format: {"start_date": "YYYY-MM-DD", "start_time": "HH:MM:SS", "end_date": "YYYY-MM-DD", "end_time": "HH:MM:SS"}`, }); break; case 'contact': fieldProperties[fieldKey] = Property.Number({ ...baseProps, description: `${baseProps.description}. Enter the Podio profile ID of the contact.`, }); break; case 'member': fieldProperties[fieldKey] = Property.Number({ ...baseProps, description: `${baseProps.description}. Enter the Podio user ID of the member.`, }); break; case 'app': fieldProperties[fieldKey] = Property.Number({ ...baseProps, description: `${baseProps.description}. Enter the ID of the item from the linked app.`, }); break; case 'category': case 'status': { let staticOptions: Array<{label: string, value: any}> = []; if (fieldConfig.settings?.options && Array.isArray(fieldConfig.settings.options)) { staticOptions = fieldConfig.settings.options.map((option: any) => ({ label: option.text || option.name || option.value || `Option ${option.id}`, value: option.id || option.value, })); } if (staticOptions.length > 0) { fieldProperties[fieldKey] = Property.StaticDropdown({ ...baseProps, options: { options: staticOptions, }, }); } else { fieldProperties[fieldKey] = Property.Number({ ...baseProps, description: `${baseProps.description}. Enter the ${fieldType} option ID manually.`, }); } break; } case 'email': fieldProperties[fieldKey] = Property.Object({ ...baseProps, description: `${baseProps.description}. Format: {"value": "email@example.com", "type": "work|home|other"}`, }); break; case 'phone': fieldProperties[fieldKey] = Property.Object({ ...baseProps, description: `${baseProps.description}. Format: {"value": "phone_number", "type": "mobile|work|home|main|work_fax|private_fax|other"}`, }); break; case 'location': fieldProperties[fieldKey] = Property.ShortText({ ...baseProps, description: `${baseProps.description}. Enter a location (address, coordinates, etc.)`, }); break; case 'image': case 'file': fieldProperties[fieldKey] = Property.Number({ ...baseProps, description: `${baseProps.description}. Enter the file ID of the uploaded ${fieldType}.`, }); break; case 'progress': fieldProperties[fieldKey] = Property.Number({ ...baseProps, description: `${baseProps.description}. Enter a value between 0 and 100.`, }); break; default: fieldProperties[fieldKey] = Property.ShortText({ ...baseProps, description: `${baseProps.description}. Field type: ${fieldType}`, }); } } catch (fieldError) { const fieldKey = `field_${field.field_id}`; fieldProperties[fieldKey] = Property.ShortText({ displayName: `${field.config?.label || 'Unknown Field'} (Fallback)`, description: `Field type "${field.type}" - Manual entry required. Original error: ${fieldError instanceof Error ? fieldError.message : 'Unknown error'}`, required: false, }); } } return fieldProperties; } catch (error) { return {}; } }, }), revision: Property.Number({ displayName: 'Revision', description: 'The revision of the item that is being updated. Optional for conflict detection.', required: false, }), externalId: Property.ShortText({ displayName: 'External ID', description: 'The new external_id of the item', required: false, }), legacyFields: Property.Object({ displayName: 'Legacy Fields (Advanced)', description: 'Manual field configuration using field_id or external_id as keys. Use this for advanced scenarios or when dynamic fields are not sufficient.', required: false, }), fileIds: Property.Array({ displayName: 'File IDs', description: 'The list of attachments', required: false, }), tags: Property.Array({ displayName: 'Tags', description: 'The list of tags', required: false, }), reminder: Property.Object({ displayName: 'Reminder', description: 'Optional reminder on this item. Format: {"remind_delta": minutes_before_due_date}', required: false, }), recurrence: Property.Object({ displayName: 'Recurrence', description: 'The recurrence for the task, if any. Format: {"name": "weekly|monthly|yearly", "config": {...}, "step": 1, "until": "date"}', required: false, }), linkedAccountId: Property.Number({ displayName: 'Linked Account ID', description: 'The linked account to use for meetings', required: false, }), ref: Property.Object({ displayName: 'Reference', description: 'The reference of the item. Format: {"type": "reference_type", "id": reference_id}', required: false, }), hook: hookProperty, silent: silentProperty, }, async run(context) { const accessToken = getAccessToken(context.auth); const { appId, itemId, appFields, revision, externalId, legacyFields, fileIds, tags, reminder, recurrence, linkedAccountId, ref, hook, silent } = context.propsValue; if (!appId) { throw new Error('App selection is required to update an item. Please select an app first.'); } if (!itemId) { throw new Error('Item selection is required to update an item. Please select an item from the dropdown.'); } let formattedFields: Record<string, any> = {}; if (appFields && Object.keys(appFields).length > 0) { try { const app = await podioApiCall<any>({ method: HttpMethod.GET, accessToken, resourceUri: `/app/${appId}`, queryParams: { view: 'full' } }); const fieldDefinitions = app.fields || []; formattedFields = formatFieldValues(fieldDefinitions, appFields); } catch (error) { throw new Error(`Failed to process app fields: ${error instanceof Error ? error.message : 'Unknown error'}`); } } if (legacyFields && typeof legacyFields === 'object' && Object.keys(legacyFields).length > 0) { formattedFields = { ...formattedFields, ...legacyFields }; } if (fileIds && !Array.isArray(fileIds)) { throw new Error('File IDs must be provided as an array of numbers.'); } if (tags && !Array.isArray(tags)) { throw new Error('Tags must be provided as an array of strings.'); } if (reminder && reminder['remind_delta'] !== undefined && typeof reminder['remind_delta'] !== 'number') { throw new Error('Reminder remind_delta must be a number representing minutes before due date.'); } if (linkedAccountId && typeof linkedAccountId !== 'number') { throw new Error('Linked Account ID must be a number.'); } if (ref && (!ref['type'] || !ref['id'])) { throw new Error('Reference must include both "type" and "id" properties.'); } const body: any = {}; if (revision !== undefined) { if (typeof revision !== 'number') { throw new Error('Revision must be a number.'); } body.revision = revision; } if (externalId && externalId.trim()) { body.external_id = externalId.trim(); } if (Object.keys(formattedFields).length > 0) { body.fields = formattedFields; } if (fileIds && Array.isArray(fileIds) && fileIds.length > 0) { body.file_ids = fileIds; } if (tags && Array.isArray(tags) && tags.length > 0) { body.tags = tags; } if (reminder && typeof reminder === 'object' && Object.keys(reminder).length > 0) { if (reminder['remind_delta'] && typeof reminder['remind_delta'] === 'number') { body.reminder = reminder; } } if (recurrence && typeof recurrence === 'object' && Object.keys(recurrence).length > 0) { if (recurrence['name'] && recurrence['config']) { body.recurrence = recurrence; } } if (linkedAccountId) { body.linked_account_id = linkedAccountId; } if (ref && typeof ref === 'object' && Object.keys(ref).length > 0) { if (ref['type'] && ref['id']) { body.ref = ref; } } const queryParams: any = {}; if (typeof hook === 'boolean') { queryParams.hook = hook.toString(); } if (typeof silent === 'boolean') { queryParams.silent = silent.toString(); } const response = await podioApiCall<{ revision: number; title: string; }>({ method: HttpMethod.PUT, accessToken, resourceUri: `/item/${itemId}`, body, queryParams, }); return response; }, });

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