Skip to main content
Glama

mcp-google-sheets

dynamic-dropdown-piece-property.tsx6.11 kB
import deepEqual from 'deep-equal'; import { t } from 'i18next'; import React, { useContext, useEffect, useRef, useState } from 'react'; import { useFormContext, useWatch } from 'react-hook-form'; import { useBuilderStateContext } from '@/app/builder/builder-hooks'; import { SearchableSelect } from '@/components/custom/searchable-select'; import { piecesHooks } from '@/features/pieces/lib/pieces-hooks'; import { DropdownState, PropertyType } from '@activepieces/pieces-framework'; import { FlowAction, isNil, FlowTrigger } from '@activepieces/shared'; import { MultiSelectPieceProperty } from '../../../components/custom/multi-select-piece-property'; import { DynamicPropertiesErrorBoundary } from './dynamic-piece-properties-error-boundary'; import { DynamicPropertiesContext } from './dynamic-properties-context'; type SelectPiecePropertyProps = { refreshers: string[]; propertyName: string; value?: unknown; multiple?: boolean; disabled: boolean; onChange: (value: unknown | undefined) => void; showDeselect?: boolean; shouldRefreshOnSearch?: boolean; }; const DynamicDropdownPiecePropertyImplementation = React.memo( (props: SelectPiecePropertyProps) => { const [flowVersion, readonly] = useBuilderStateContext((state) => [ state.flowVersion, state.readonly, ]); const form = useFormContext<FlowAction | FlowTrigger>(); const isFirstRender = useRef(true); const previousValues = useRef<undefined | unknown[]>(undefined); const firstDropdownState = useRef<DropdownState<unknown> | undefined>( undefined, ); const newRefreshers = [...props.refreshers, 'auth']; const [dropdownState, setDropdownState] = useState<DropdownState<unknown>>({ disabled: false, placeholder: t('Select an option'), options: [], }); const { propertyLoadingFinished, propertyLoadingStarted } = useContext( DynamicPropertiesContext, ); const { mutate, isPending, error } = piecesHooks.usePieceOptions< PropertyType.DROPDOWN | PropertyType.MULTI_SELECT_DROPDOWN >({ onMutate: () => { propertyLoadingStarted(props.propertyName); }, onError: (error) => { console.error(error); propertyLoadingFinished(props.propertyName); }, onSuccess: () => { propertyLoadingFinished(props.propertyName); }, }); if (error) { throw error; } /* eslint-disable react-hooks/rules-of-hooks */ const refresherValues = newRefreshers.map((refresher) => useWatch({ name: `settings.input.${refresher}` as const, control: form.control, }), ); /* eslint-enable react-hooks/rules-of-hooks */ const refresh = (term?: string) => { const input: Record<string, unknown> = {}; newRefreshers.forEach((refresher, index) => { input[refresher] = refresherValues[index]; }); const { settings } = form.getValues(); const actionOrTriggerName = settings.actionName ?? settings.triggerName; const { pieceName, pieceVersion } = settings; mutate( { request: { pieceName, pieceVersion, propertyName: props.propertyName, actionOrTriggerName: actionOrTriggerName, input, flowVersionId: flowVersion.id, flowId: flowVersion.flowId, searchValue: term, }, propertyType: PropertyType.DROPDOWN, }, { onSuccess: (response) => { if (!firstDropdownState.current) { firstDropdownState.current = response.options; } setDropdownState(response.options); }, }, ); }; useEffect(() => { if ( !isFirstRender.current && !deepEqual(previousValues.current, refresherValues) ) { props.onChange(null); } previousValues.current = refresherValues; isFirstRender.current = false; refresh(); }, refresherValues); const selectOptions = dropdownState.options.map((option) => ({ label: option.label, value: option.value, })); const isDisabled = dropdownState.disabled || props.disabled; return props.multiple ? ( <MultiSelectPieceProperty placeholder={dropdownState.placeholder ?? t('Select an option')} options={selectOptions} loading={isPending} onChange={(value) => props.onChange(value)} disabled={isDisabled} initialValues={props.value as unknown[]} showDeselect={ props.showDeselect && !isNil(props.value) && Array.isArray(props.value) && props.value.length > 0 && !isDisabled } showRefresh={!isPending && !readonly} onRefresh={refresh} refreshOnSearch={props.shouldRefreshOnSearch ? refresh : undefined} cachedOptions={firstDropdownState.current?.options ?? []} /> ) : ( <SearchableSelect options={selectOptions} disabled={dropdownState.disabled || props.disabled} loading={isPending} placeholder={dropdownState.placeholder ?? t('Select an option')} value={props.value} onChange={(value) => props.onChange(value)} showDeselect={ props.showDeselect && !isNil(props.value) && !props.disabled } onRefresh={refresh} showRefresh={!isPending && !readonly} refreshOnSearch={props.shouldRefreshOnSearch ? refresh : undefined} cachedOptions={firstDropdownState.current?.options ?? []} /> ); }, ); const DynamicDropdownPieceProperty = React.memo( (props: SelectPiecePropertyProps) => { return ( <DynamicPropertiesErrorBoundary> <DynamicDropdownPiecePropertyImplementation {...props} /> </DynamicPropertiesErrorBoundary> ); }, ); DynamicDropdownPieceProperty.displayName = 'DynamicDropdownPieceProperty'; DynamicDropdownPiecePropertyImplementation.displayName = 'DynamicDropdownPiecePropertyImplementation'; export { DynamicDropdownPieceProperty };

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