Skip to main content
Glama

mcp-google-sheets

props.ts14.2 kB
import { Property, DynamicPropsValue } from '@activepieces/pieces-framework'; import { HttpMethod } from '@activepieces/pieces-common'; import { wufooApiCall } from './client'; interface WufooForm { Name: string; Hash: string; Url: string; } interface WufooFormField { ID: string; Title: string; Type: string; IsRequired: string; Instructions: string; ClassNames: string; DefaultVal: string; Page: string; IsSystem?: boolean; SubFields?: Array<{ ID: string; Label: string; DefaultVal: string; }>; Choices?: Array<{ Label: string; Score?: number; // For Likert fields }>; // For fields that allow "Other" option HasOtherField?: boolean; } interface WufooFormFieldsResponse { Fields: WufooFormField[]; } export const formIdentifier = Property.Dropdown({ displayName: 'Form Identifier (Name and Hash)', description: 'Select a Wufoo form to work with.', required: true, refreshers: [], options: async ({ auth }) => { const { apiKey, subdomain } = auth as { apiKey: string; subdomain: string }; if (!apiKey || !subdomain) { return { disabled: true, options: [], placeholder: 'Please connect your Wufoo account.', }; } let response: { Forms: WufooForm[] }; try { response = await wufooApiCall<{ Forms: WufooForm[] }>({ auth: { apiKey, subdomain }, method: HttpMethod.GET, resourceUri: '/forms.json', }); } catch (e) { return { disabled: true, options: [], placeholder: `Error fetching forms: ${(e as Error).message}`, }; } const forms = Array.isArray(response.Forms) ? response.Forms : []; if (forms.length === 0) { return { disabled: true, options: [], placeholder: 'No forms found in your account.', }; } return { disabled: false, options: forms.map((form) => ({ label: `${form.Name} (${form.Hash})`, value: form.Hash, })), }; }, }); export const dynamicFormFields = Property.DynamicProperties({ displayName: 'Form Fields', description: 'Fill out the form fields with the data you want to submit. Field types and validation are automatically configured based on your form structure.', required: true, refreshers: ['formIdentifier', 'format'], props: async ({ auth, formIdentifier, format }) => { if (!auth || !formIdentifier) { return {}; } const { apiKey, subdomain } = auth as { apiKey: string; subdomain: string }; const responseFormat = (format as unknown as string) || 'json'; try { const response = await wufooApiCall<WufooFormFieldsResponse | any>({ auth: { apiKey, subdomain }, method: HttpMethod.GET, resourceUri: `/forms/${formIdentifier}/fields.json`, }); let parsedResponse = response; if (typeof response === 'string' && response.includes('OUTPUT =')) { const match = response.match(/OUTPUT = ({.*?});/); if (match) { try { parsedResponse = JSON.parse(match[1]); } catch (e) { console.error('Error parsing Wufoo fields response:', e); parsedResponse = response; } } } let fields: WufooFormField[] = []; if (parsedResponse && typeof parsedResponse === 'object') { if ((parsedResponse as any).Fields && Array.isArray((parsedResponse as any).Fields)) { fields = (parsedResponse as any).Fields; } else if (responseFormat === 'json') { fields = (parsedResponse as WufooFormFieldsResponse).Fields || []; } else if (responseFormat === 'xml') { const fieldsContainer = parsedResponse.Fields || parsedResponse; if (Array.isArray(fieldsContainer)) { fields = fieldsContainer; } else if (fieldsContainer.Field) { if (Array.isArray(fieldsContainer.Field)) { fields = fieldsContainer.Field; } else { fields = [fieldsContainer.Field]; } } } } const props: DynamicPropsValue = {}; for (const field of fields) { // Skip system fields (marked with IsSystem: true) and common system field IDs if (field.IsSystem || ['EntryId', 'DateCreated', 'CreatedBy', 'LastUpdated', 'UpdatedBy', 'Status', 'PurchaseTotal', 'Currency', 'TransactionId', 'MerchantType', 'IP', 'LastPage', 'CompleteSubmission'].includes(field.ID)) { continue; } const fieldId = field.ID.startsWith('Field') ? field.ID : `Field${field.ID}`; const fieldTitle = field.Title || `Field ${field.ID}`; const fieldDescription = field.Instructions || `Enter value for ${fieldTitle}`; const isRequired = field.IsRequired === '1'; switch (field.Type) { case 'text': case 'email': case 'url': props[fieldId] = Property.ShortText({ displayName: fieldTitle, description: fieldDescription, required: isRequired, defaultValue: field.DefaultVal || undefined, }); break; case 'textarea': props[fieldId] = Property.LongText({ displayName: fieldTitle, description: fieldDescription, required: isRequired, defaultValue: field.DefaultVal || undefined, }); break; case 'number': case 'money': props[fieldId] = Property.Number({ displayName: fieldTitle, description: field.Type === 'money' ? `${fieldDescription} (Enter monetary amount)` : fieldDescription, required: isRequired, defaultValue: field.DefaultVal ? parseFloat(field.DefaultVal) : undefined, }); break; case 'date': props[fieldId] = Property.DateTime({ displayName: fieldTitle, description: `${fieldDescription} (Date will be converted to YYYYMMDD format for Wufoo)`, required: isRequired, }); break; case 'time': props[fieldId] = Property.ShortText({ displayName: fieldTitle, description: `${fieldDescription} (Enter time in HH:MM format)`, required: isRequired, defaultValue: field.DefaultVal || undefined, }); break; case 'phone': props[fieldId] = Property.ShortText({ displayName: fieldTitle, description: `${fieldDescription} (Phone number)`, required: isRequired, defaultValue: field.DefaultVal || undefined, }); break; case 'select': case 'radio': if (field.Choices && field.Choices.length > 0) { const options = field.Choices .filter(choice => choice.Label && choice.Label.trim() !== '') .map((choice) => ({ label: choice.Label, value: choice.Label, })); if (options.length > 0) { props[fieldId] = Property.StaticDropdown({ displayName: fieldTitle, description: field.HasOtherField ? `${fieldDescription} (Includes "Other" option)` : fieldDescription, required: isRequired, options: { disabled: false, options: options, }, }); } else { // Fallback to text input if no valid choices props[fieldId] = Property.ShortText({ displayName: fieldTitle, description: fieldDescription, required: isRequired, defaultValue: field.DefaultVal || undefined, }); } } else { props[fieldId] = Property.ShortText({ displayName: fieldTitle, description: fieldDescription, required: isRequired, defaultValue: field.DefaultVal || undefined, }); } break; case 'checkbox': if (field.SubFields && field.SubFields.length > 0) { // Handle checkbox fields with multiple options const options = field.SubFields.map((subField) => ({ label: subField.Label, value: subField.ID, })); props[fieldId] = Property.StaticMultiSelectDropdown({ displayName: fieldTitle, description: `${fieldDescription} (Select multiple options)`, required: isRequired, options: { disabled: false, options: options, }, }); } else { // Single checkbox props[fieldId] = Property.Checkbox({ displayName: fieldTitle, description: fieldDescription, required: isRequired, defaultValue: field.DefaultVal === '1' || field.DefaultVal === 'true', }); } break; case 'address': if (field.SubFields && field.SubFields.length > 0) { // Create individual fields for each address component for (const subField of field.SubFields) { props[subField.ID] = Property.ShortText({ displayName: `${fieldTitle} - ${subField.Label}`, description: `Enter ${subField.Label.toLowerCase()}`, required: isRequired && ['Street Address', 'City'].includes(subField.Label), defaultValue: subField.DefaultVal || undefined, }); } } else { // Fallback to single address field props[fieldId] = Property.LongText({ displayName: fieldTitle, description: `${fieldDescription} (Complete address)`, required: isRequired, defaultValue: field.DefaultVal || undefined, }); } break; case 'shortname': if (field.SubFields && field.SubFields.length > 0) { // Create individual fields for name components (First, Last, etc.) for (const subField of field.SubFields) { props[subField.ID] = Property.ShortText({ displayName: `${fieldTitle} - ${subField.Label}`, description: `Enter ${subField.Label.toLowerCase()} name`, required: isRequired, defaultValue: subField.DefaultVal || undefined, }); } } else { props[fieldId] = Property.ShortText({ displayName: fieldTitle, description: fieldDescription, required: isRequired, defaultValue: field.DefaultVal || undefined, }); } break; case 'likert': if (field.Choices && field.Choices.length > 0) { const options = field.Choices.map((choice) => ({ label: `${choice.Label}${choice.Score ? ` (Score: ${choice.Score})` : ''}`, value: choice.Label, })); if (field.SubFields && field.SubFields.length > 0) { // Create a dropdown for each Likert row for (const subField of field.SubFields) { props[subField.ID] = Property.StaticDropdown({ displayName: `${fieldTitle} - ${subField.Label}`, description: `Rate: ${subField.Label}`, required: isRequired, options: { disabled: false, options: options, }, }); } } else { props[fieldId] = Property.StaticDropdown({ displayName: fieldTitle, description: fieldDescription, required: isRequired, options: { disabled: false, options: options, }, }); } } else { // Fallback if no choices are provided props[fieldId] = Property.ShortText({ displayName: fieldTitle, description: `${fieldDescription} (Likert scale)`, required: isRequired, defaultValue: field.DefaultVal || undefined, }); } break; case 'rating': props[fieldId] = Property.Number({ displayName: fieldTitle, description: `${fieldDescription} (Rating scale)`, required: isRequired, defaultValue: field.DefaultVal ? parseFloat(field.DefaultVal) : undefined, }); break; case 'file': props[fieldId] = Property.File({ displayName: fieldTitle, description: `${fieldDescription} (File upload)`, required: isRequired, }); break; default: // For unknown field types, default to text input with field type in description props[fieldId] = Property.ShortText({ displayName: fieldTitle, description: `${fieldDescription} (Field type: ${field.Type})`, required: isRequired, defaultValue: field.DefaultVal || undefined, }); break; } } return props; } catch (error) { console.error(`Error fetching form fields in ${responseFormat} format:`, error); return {}; } }, });

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