Skip to content

Commit 8e0b2dc

Browse files
feat(blocks): surface deprecated block and model warnings on canvas
1 parent 58c87b2 commit 8e0b2dc

41 files changed

Lines changed: 295 additions & 5 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/panel.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -458,10 +458,11 @@ export const Panel = memo(function Panel() {
458458

459459
useEffect(() => {
460460
const handler = (e: Event) => {
461-
const message = (e as CustomEvent<MothershipSendMessageDetail>).detail?.message
462-
if (!message) return
461+
const detail = (e as CustomEvent<MothershipSendMessageDetail>).detail
462+
if (!detail?.message) return
463+
e.preventDefault()
463464
setActiveTab('copilot')
464-
copilotSendMessage(message)
465+
copilotSendMessage(detail.message, undefined, detail.contexts)
465466
}
466467
window.addEventListener(MOTHERSHIP_SEND_MESSAGE_EVENT, handler)
467468
return () => window.removeEventListener(MOTHERSHIP_SEND_MESSAGE_EVENT, handler)

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block.tsx

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@ import { createLogger } from '@sim/logger'
33
import { SubBlockRowView, WorkflowBlockView } from '@sim/workflow-renderer'
44
import { isEqual } from 'es-toolkit'
55
import { useParams } from 'next/navigation'
6+
import { usePostHog } from 'posthog-js/react'
67
import { type NodeProps, useUpdateNodeInternals } from 'reactflow'
78
import { useStoreWithEqualityFn } from 'zustand/traditional'
89
import { getBaseUrl } from '@/lib/core/utils/urls'
910
import { createMcpToolId } from '@/lib/mcp/shared'
11+
import { sendMothershipMessage } from '@/lib/mothership/events'
1012
import { getProviderIdFromServiceId } from '@/lib/oauth'
13+
import { captureEvent } from '@/lib/posthog/client'
1114
import { calculateWorkflowBlockDimensions } from '@/lib/workflows/blocks/deterministic-dimensions'
1215
import { getConditionRows, getRouterRows } from '@/lib/workflows/dynamic-handle-topology'
1316
import {
@@ -45,6 +48,7 @@ import {
4548
import { useBlockVisual } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks'
4649
import { useBlockDimensions } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-block-dimensions'
4750
import { useCustomBlockOverlayVersion } from '@/blocks/custom/client-overlay'
51+
import { getBlock } from '@/blocks/registry'
4852
import { SELECTOR_TYPES_HYDRATION_REQUIRED, type SubBlockConfig } from '@/blocks/types'
4953
import { getDependsOnFields } from '@/blocks/utils'
5054
import { useKnowledgeBase } from '@/hooks/kb/use-knowledge'
@@ -58,6 +62,7 @@ import { useTablesList } from '@/hooks/queries/tables'
5862
import { useWorkflowMap } from '@/hooks/queries/workflows'
5963
import { useReactiveConditions } from '@/hooks/use-reactive-conditions'
6064
import { useSelectorDisplayName } from '@/hooks/use-selector-display-name'
65+
import { getModelReplacement, isModelDeprecated } from '@/providers/models'
6166
import { useVariablesStore } from '@/stores/variables/store'
6267
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
6368
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
@@ -479,6 +484,55 @@ export const WorkflowBlock = memo(function WorkflowBlock({
479484
),
480485
isEqual
481486
)
487+
488+
const posthog = usePostHog()
489+
490+
const deprecation = useMemo(() => {
491+
if (currentWorkflow.isDiffMode) return null
492+
493+
const replacedBy = config.deprecated?.replacedBy
494+
if (replacedBy) {
495+
const target = getBlock(replacedBy)
496+
if (!target) return null
497+
const hasModel = config.subBlocks?.some((sub) => sub.id === 'model')
498+
return {
499+
kind: 'block' as const,
500+
tooltip: 'This block is deprecated. Click to upgrade',
501+
prompt: `The "${name}" block is deprecated. Migrate it to the current ${target.name} block: change the block type, then set the new block's required inputs as a separate edit (inputs are validated against the old type when sent in the same edit), or delete it and re-add ${target.name} and rewire the connections.${hasModel ? ' Also pick a current, non-deprecated model.' : ''}`,
502+
}
503+
}
504+
505+
const model = blockSubBlockValues.model
506+
if (typeof model === 'string' && isModelDeprecated(model)) {
507+
if (!getModelReplacement(model)) return null
508+
return {
509+
kind: 'model' as const,
510+
tooltip: `${model} is deprecated. Click to upgrade`,
511+
prompt: `The "${name}" block uses the deprecated model "${model}". Switch it to the latest equivalent model.`,
512+
}
513+
}
514+
515+
return null
516+
}, [
517+
config.deprecated,
518+
config.subBlocks,
519+
name,
520+
blockSubBlockValues.model,
521+
currentWorkflow.isDiffMode,
522+
])
523+
524+
const onFixDeprecation = useCallback(() => {
525+
if (!deprecation) return
526+
captureEvent(posthog, 'deprecated_block_fix_clicked', {
527+
block_type: type,
528+
workflow_id: currentWorkflowId,
529+
kind: deprecation.kind,
530+
})
531+
sendMothershipMessage(deprecation.prompt, [
532+
{ kind: 'workflow_block', workflowId: currentWorkflowId, blockId: id, label: name },
533+
])
534+
}, [deprecation, posthog, type, currentWorkflowId, id, name])
535+
482536
const canonicalIndex = useMemo(() => buildCanonicalIndex(config.subBlocks), [config.subBlocks])
483537
const canonicalModeOverrides = currentStoreBlock?.data?.canonicalModes
484538

@@ -798,6 +852,9 @@ export const WorkflowBlock = memo(function WorkflowBlock({
798852
deployChildWorkflow({ workflowId: childWorkflowId })
799853
}
800854
}}
855+
deprecationTooltip={deprecation?.tooltip}
856+
canFixDeprecation={canEditWorkflow}
857+
onFixDeprecation={onFixDeprecation}
801858
shouldShowScheduleBadge={shouldShowScheduleBadge}
802859
scheduleIsDisabled={Boolean(scheduleInfo?.isDisabled)}
803860
onReactivateSchedule={() => {

apps/sim/blocks/blocks/api_trigger.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const ApiTriggerBlock: BlockConfig = {
1515
`,
1616
category: 'triggers',
1717
hideFromToolbar: true,
18+
deprecated: { replacedBy: 'start_trigger' },
1819
bgColor: '#2F55FF',
1920
icon: ApiIcon,
2021
subBlocks: [

apps/sim/blocks/blocks/chat_trigger.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export const ChatTriggerBlock: BlockConfig = {
1616
`,
1717
category: 'triggers',
1818
hideFromToolbar: true,
19+
deprecated: { replacedBy: 'start_trigger' },
1920
bgColor: '#6F3DFA',
2021
icon: ChatTriggerIcon,
2122
subBlocks: [],

apps/sim/blocks/blocks/confluence.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export const ConfluenceBlock: BlockConfig<ConfluenceResponse> = {
1212
name: 'Confluence (Legacy)',
1313
description: 'Interact with Confluence',
1414
hideFromToolbar: true,
15+
deprecated: { replacedBy: 'confluence_v2' },
1516
authMode: AuthMode.OAuth,
1617
longDescription:
1718
'Integrate Confluence into the workflow. Can read, create, update, delete pages, manage comments, attachments, labels, and search content.',
@@ -360,6 +361,7 @@ export const ConfluenceBlock: BlockConfig<ConfluenceResponse> = {
360361

361362
export const ConfluenceV2Block: BlockConfig<ConfluenceResponse> = {
362363
...ConfluenceBlock,
364+
deprecated: undefined,
363365
type: 'confluence_v2',
364366
name: 'Confluence',
365367
hideFromToolbar: false,

apps/sim/blocks/blocks/cursor.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export const CursorBlock: BlockConfig<CursorResponse> = {
1717
icon: CursorIcon,
1818
authMode: AuthMode.ApiKey,
1919
hideFromToolbar: true,
20+
deprecated: { replacedBy: 'cursor_v2' },
2021
subBlocks: [
2122
{
2223
id: 'operation',
@@ -223,6 +224,7 @@ export const CursorBlock: BlockConfig<CursorResponse> = {
223224

224225
export const CursorV2Block: BlockConfig<CursorResponse> = {
225226
...CursorBlock,
227+
deprecated: undefined,
226228
type: 'cursor_v2',
227229
name: 'Cursor',
228230
description: 'Launch and manage Cursor cloud agents to work on GitHub repositories',

apps/sim/blocks/blocks/extend.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export const ExtendBlock: BlockConfig<ExtendParserOutput> = {
1414
name: 'Extend',
1515
description: 'Parse and extract content from documents',
1616
hideFromToolbar: true,
17+
deprecated: { replacedBy: 'extend_v2' },
1718
authMode: AuthMode.ApiKey,
1819
longDescription:
1920
'Integrate Extend AI into the workflow. Parse and extract structured content from documents including PDFs, images, and Office files.',
@@ -165,6 +166,7 @@ const extendV2SubBlocks = (ExtendBlock.subBlocks || []).flatMap((subBlock) => {
165166

166167
export const ExtendV2Block: BlockConfig<ExtendParserOutput> = {
167168
...ExtendBlock,
169+
deprecated: undefined,
168170
type: 'extend_v2',
169171
name: 'Extend',
170172
hideFromToolbar: false,

apps/sim/blocks/blocks/file.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ export const FileBlock: BlockConfig<FileParserOutput> = {
7878
bgColor: '#40916C',
7979
icon: DocumentIcon,
8080
hideFromToolbar: true,
81+
deprecated: { replacedBy: 'file_v5' },
8182
subBlocks: [
8283
{
8384
id: 'inputMethod',
@@ -185,6 +186,7 @@ export const FileV2Block: BlockConfig<FileParserOutput> = {
185186
name: 'File (Legacy)',
186187
description: 'Read and parse multiple files',
187188
hideFromToolbar: true,
189+
deprecated: { replacedBy: 'file_v5' },
188190
subBlocks: [
189191
{
190192
id: 'file',
@@ -278,6 +280,7 @@ export const FileV3Block: BlockConfig<FileParserV3Output> = {
278280
bgColor: '#40916C',
279281
icon: DocumentIcon,
280282
hideFromToolbar: true,
283+
deprecated: { replacedBy: 'file_v5' },
281284
subBlocks: [
282285
{
283286
id: 'operation',
@@ -568,6 +571,7 @@ export const FileV4Block: BlockConfig<FileParserV3Output> = {
568571
longDescription:
569572
'Read workspace files by picker or canonical ID, fetch and parse files from URLs with optional headers, write new workspace files, or append content to existing files.',
570573
hideFromToolbar: true,
574+
deprecated: { replacedBy: 'file_v5' },
571575
bestPractices: `
572576
- Use Read when you need an existing workspace file object by picker selection or canonical file ID.
573577
- Use Fetch for external file URLs. Add headers for authenticated downloads, for example Slack private file URLs require an Authorization Bearer token.
@@ -820,6 +824,7 @@ export const FileV4Block: BlockConfig<FileParserV3Output> = {
820824

821825
export const FileV5Block: BlockConfig<FileParserV3Output> = {
822826
...FileV4Block,
827+
deprecated: undefined,
823828
type: 'file_v5',
824829
name: 'File',
825830
description:

apps/sim/blocks/blocks/fireflies.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export const FirefliesBlock: BlockConfig<FirefliesResponse> = {
1111
name: 'Fireflies (Legacy)',
1212
description: 'Interact with Fireflies.ai meeting transcripts and recordings',
1313
hideFromToolbar: true,
14+
deprecated: { replacedBy: 'fireflies_v2' },
1415
authMode: AuthMode.ApiKey,
1516
triggerAllowed: true,
1617
longDescription:
@@ -646,6 +647,7 @@ const firefliesV2Inputs = FirefliesBlock.inputs
646647

647648
export const FirefliesV2Block: BlockConfig<FirefliesResponse> = {
648649
...FirefliesBlock,
650+
deprecated: undefined,
649651
type: 'fireflies_v2',
650652
name: 'Fireflies',
651653
description: 'Interact with Fireflies.ai meeting transcripts and recordings',

apps/sim/blocks/blocks/github.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export const GitHubBlock: BlockConfig<GitHubResponse> = {
2020
icon: GithubIcon,
2121
triggerAllowed: true,
2222
hideFromToolbar: true,
23+
deprecated: { replacedBy: 'github_v2' },
2324
subBlocks: [
2425
{
2526
id: 'operation',
@@ -2102,6 +2103,7 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
21022103

21032104
export const GitHubV2Block: BlockConfig<GitHubResponse> = {
21042105
...GitHubBlock,
2106+
deprecated: undefined,
21052107
type: 'github_v2',
21062108
name: 'GitHub',
21072109
hideFromToolbar: false,

0 commit comments

Comments
 (0)