diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/editor/components/sub-block/components/credential-selector/credential-selector.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/editor/components/sub-block/components/credential-selector/credential-selector.tsx index 7575d08aa0..29d8ee05a9 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/editor/components/sub-block/components/credential-selector/credential-selector.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/editor/components/sub-block/components/credential-selector/credential-selector.tsx @@ -128,14 +128,36 @@ export function CredentialSelector({ .setDisplayNames('credentials', effectiveProviderId, credentialMap) } - // Do not auto-select or reset. We only show what's persisted. + // Check if the currently selected credential still exists + const selectedCredentialStillExists = (creds || []).some( + (cred: Credential) => cred.id === selectedId + ) + const shouldClearPersistedSelection = + !isPreview && selectedId && !selectedCredentialStillExists && !foreignMetaFound + + if (shouldClearPersistedSelection) { + logger.info('Clearing invalid credential selection - credential was disconnected', { + selectedId, + provider: effectiveProviderId, + }) + + // Clear via setStoreValue to trigger cascade + setStoreValue('') + setSelectedId('') + + if (effectiveProviderId) { + useDisplayNamesStore + .getState() + .removeDisplayName('credentials', effectiveProviderId, selectedId) + } + } } } catch (error) { logger.error('Error fetching credentials:', { error }) } finally { setIsLoading(false) } - }, [effectiveProviderId, selectedId, activeWorkflowId]) + }, [effectiveProviderId, selectedId, activeWorkflowId, isPreview, setStoreValue]) // Fetch credentials on initial mount and whenever the subblock value changes externally useEffect(() => { @@ -204,6 +226,24 @@ export function CredentialSelector({ } }, [fetchCredentials]) + // Listen for credential disconnection events from settings modal + useEffect(() => { + const handleCredentialDisconnected = (event: Event) => { + const customEvent = event as CustomEvent + const { providerId } = customEvent.detail + // Re-fetch if this disconnection affects our provider + if (providerId && (providerId === effectiveProviderId || providerId.startsWith(provider))) { + fetchCredentials() + } + } + + window.addEventListener('credential-disconnected', handleCredentialDisconnected) + + return () => { + window.removeEventListener('credential-disconnected', handleCredentialDisconnected) + } + }, [fetchCredentials, effectiveProviderId, provider]) + // Handle popover open to fetch fresh credentials const handleOpenChange = (isOpen: boolean) => { setOpen(isOpen) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/editor/components/sub-block/components/file-selector/components/google-drive-picker.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/editor/components/sub-block/components/file-selector/components/google-drive-picker.tsx index e8ce75e172..9d0c6384fd 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/editor/components/sub-block/components/file-selector/components/google-drive-picker.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/editor/components/sub-block/components/file-selector/components/google-drive-picker.tsx @@ -150,6 +150,14 @@ export function GoogleDrivePicker({ if (data.file) { setSelectedFile(data.file) onFileInfoChange?.(data.file) + + // Cache the file name + if (selectedCredentialId && data.file.id && data.file.name) { + useDisplayNamesStore.getState().setDisplayNames('files', selectedCredentialId, { + [data.file.id]: data.file.name, + }) + } + return data.file } } else { @@ -335,6 +343,13 @@ export function GoogleDrivePicker({ setSelectedFile(fileInfo) onChange(file.id, fileInfo) onFileInfoChange?.(fileInfo) + + // Cache the selected file name + if (selectedCredentialId) { + useDisplayNamesStore + .getState() + .setDisplayNames('files', selectedCredentialId, { [file.id]: file.name }) + } } } }, diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/editor/components/sub-block/sub-block.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/editor/components/sub-block/sub-block.tsx index efc7efc0f6..cbd6b053a6 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/editor/components/sub-block/sub-block.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/editor/components/sub-block/sub-block.tsx @@ -3,6 +3,7 @@ import { AlertTriangle } from 'lucide-react' import { Label, Tooltip } from '@/components/emcn/components' import { cn } from '@/lib/utils' import type { FieldDiffStatus } from '@/lib/workflows/diff/types' +import { useDependsOnGate } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/editor/components/sub-block/hooks/use-depends-on-gate' import type { SubBlockConfig } from '@/blocks/types' import { ChannelSelectorInput, @@ -157,7 +158,15 @@ function SubBlockComponent({ | string[] | null | undefined - const isDisabled = disabled || isPreview + + // Use dependsOn gating to compute final disabled state + const { finalDisabled: gatedDisabled } = useDependsOnGate(blockId, config, { + disabled, + isPreview, + previewContextValues: subBlockValues, + }) + + const isDisabled = gatedDisabled /** * Selects and renders the appropriate input component for the current sub-block `config.type`. diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block.tsx index e3fc10454e..741c82f842 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block.tsx @@ -12,7 +12,7 @@ import { BLOCK_DIMENSIONS, useBlockDimensions, } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-block-dimensions' -import type { SubBlockConfig } from '@/blocks/types' +import { SELECTOR_TYPES_HYDRATION_REQUIRED, type SubBlockConfig } from '@/blocks/types' import { useCollaborativeWorkflow } from '@/hooks/use-collaborative-workflow' import { useCredentialDisplay } from '@/hooks/use-credential-display' import { useDisplayName } from '@/hooks/use-display-name' @@ -237,7 +237,10 @@ const SubBlockRow = ({ const isPasswordField = subBlock?.password === true const maskedValue = isPasswordField && value && value !== '-' ? '•••' : null - const displayValue = maskedValue || credentialName || dropdownLabel || genericDisplayName || value + + const isSelectorType = subBlock?.type && SELECTOR_TYPES_HYDRATION_REQUIRED.includes(subBlock.type) + const hydratedName = credentialName || dropdownLabel || genericDisplayName + const displayValue = maskedValue || hydratedName || (isSelectorType && value ? '-' : value) return (