Skip to content

Commit 8bd75de

Browse files
authored
fix(notes): fix notes, tighten spacing, update deprecated zustand function, update use mention data to ignore block positon (#2002)
1 parent ad2a375 commit 8bd75de

File tree

5 files changed

+94
-52
lines changed

5 files changed

+94
-52
lines changed

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

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,33 +35,47 @@ const NoteMarkdown = memo(function NoteMarkdown({ content }: { content: string }
3535
<ReactMarkdown
3636
remarkPlugins={[remarkGfm]}
3737
components={{
38-
p: ({ children }) => <p className='mb-0 text-[#E5E5E5] text-sm'>{children}</p>,
38+
p: ({ children }) => (
39+
<p className='!mt-0 !-mb-4 text-[#E5E5E5] text-sm leading-tight'>{children}</p>
40+
),
3941
h1: ({ children }) => (
40-
<h1 className='mt-0 mb-[-2px] font-semibold text-[#E5E5E5] text-lg'>{children}</h1>
42+
<h1 className='!mt-0 !-mb-4 font-semibold text-[#E5E5E5] text-lg leading-tight'>
43+
{children}
44+
</h1>
4145
),
4246
h2: ({ children }) => (
43-
<h2 className='mt-0 mb-[-2px] font-semibold text-[#E5E5E5] text-base'>{children}</h2>
47+
<h2 className='!mt-0 !-mb-4 font-semibold text-[#E5E5E5] text-base leading-tight'>
48+
{children}
49+
</h2>
4450
),
4551
h3: ({ children }) => (
46-
<h3 className='mt-0 mb-[-2px] font-semibold text-[#E5E5E5] text-sm'>{children}</h3>
52+
<h3 className='!mt-0 !-mb-4 font-semibold text-[#E5E5E5] text-sm leading-tight'>
53+
{children}
54+
</h3>
4755
),
4856
h4: ({ children }) => (
49-
<h4 className='mt-0 mb-[-2px] font-semibold text-[#E5E5E5] text-xs'>{children}</h4>
57+
<h4 className='!mt-0 !-mb-4 font-semibold text-[#E5E5E5] text-xs leading-tight'>
58+
{children}
59+
</h4>
5060
),
5161
ul: ({ children }) => (
52-
<ul className='-mt-[2px] mb-0 list-disc pl-4 text-[#E5E5E5] text-sm'>{children}</ul>
62+
<ul className='!-mt-4 !-mb-4 [&_li>ul]:!mt-0 [&_li>ul]:!mb-0 [&_li>ol]:!mt-0 [&_li>ol]:!mb-0 list-disc pl-4 text-[#E5E5E5] text-sm leading-tight'>
63+
{children}
64+
</ul>
5365
),
5466
ol: ({ children }) => (
55-
<ol className='-mt-[2px] mb-0 list-decimal pl-4 text-[#E5E5E5] text-sm'>{children}</ol>
67+
<ol className='!-mt-4 !-mb-4 [&_li>ul]:!mt-0 [&_li>ul]:!mb-0 [&_li>ol]:!mt-0 [&_li>ol]:!mb-0 list-decimal pl-4 text-[#E5E5E5] text-sm leading-tight'>
68+
{children}
69+
</ol>
5670
),
57-
li: ({ children }) => <li className='mb-0'>{children}</li>,
71+
li: ({ children }) => <li className='!mb-0 leading-tight'>{children}</li>,
5872
code: ({ inline, children }: any) =>
5973
inline ? (
60-
<code className='rounded bg-[var(--divider)] px-1 py-0.5 text-[#F59E0B] text-xs'>
74+
<code className='break-words rounded bg-[var(--divider)] px-1 py-0.5 text-[#F59E0B] text-xs'>
6175
{children}
6276
</code>
6377
) : (
64-
<code className='block rounded bg-[#1A1A1A] p-2 text-[#E5E5E5] text-xs'>
78+
<code className='block whitespace-pre-wrap break-words rounded bg-[#1A1A1A] p-2 text-[#E5E5E5] text-xs'>
6579
{children}
6680
</code>
6781
),
@@ -78,7 +92,7 @@ const NoteMarkdown = memo(function NoteMarkdown({ content }: { content: string }
7892
strong: ({ children }) => <strong className='font-semibold text-white'>{children}</strong>,
7993
em: ({ children }) => <em className='text-[#B8B8B8]'>{children}</em>,
8094
blockquote: ({ children }) => (
81-
<blockquote className='m-0 border-[#F59E0B] border-l-2 pl-3 text-[#B8B8B8] italic'>
95+
<blockquote className='!mt-0 !-mb-4 border-[#F59E0B] border-l-2 pl-3 text-[#B8B8B8] italic'>
8296
{children}
8397
</blockquote>
8498
),
@@ -187,9 +201,7 @@ export const NoteBlock = memo(function NoteBlock({ id, data }: NodeProps<NoteBlo
187201
) : showMarkdown ? (
188202
<NoteMarkdown content={content} />
189203
) : (
190-
<p className='whitespace-pre-wrap text-[#E5E5E5] text-sm leading-relaxed'>
191-
{content}
192-
</p>
204+
<p className='whitespace-pre-wrap text-[#E5E5E5] text-sm leading-snug'>{content}</p>
193205
)}
194206
</div>
195207
</div>

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/copilot/components/user-input/hooks/use-mention-data.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use client'
22

33
import { useCallback, useEffect, useState } from 'react'
4+
import { shallow } from 'zustand/shallow'
45
import { createLogger } from '@/lib/logs/console/logger'
56
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
67
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
@@ -109,7 +110,11 @@ export function useMentionData(props: UseMentionDataProps) {
109110
const [workflowBlocks, setWorkflowBlocks] = useState<WorkflowBlockItem[]>([])
110111
const [isLoadingWorkflowBlocks, setIsLoadingWorkflowBlocks] = useState(false)
111112

112-
const workflowStoreBlocks = useWorkflowStore((state) => state.blocks)
113+
// Only subscribe to block keys to avoid re-rendering on position updates
114+
const blockKeys = useWorkflowStore(
115+
useCallback((state) => Object.keys(state.blocks), []),
116+
shallow
117+
)
113118

114119
// Use workflow registry as source of truth for workflows
115120
const registryWorkflows = useWorkflowRegistry((state) => state.workflows)
@@ -139,15 +144,19 @@ export function useMentionData(props: UseMentionDataProps) {
139144

140145
/**
141146
* Syncs workflow blocks from store
147+
* Only re-runs when blocks are added/removed (not on position updates)
142148
*/
143149
useEffect(() => {
144150
const syncWorkflowBlocks = async () => {
145-
if (!workflowId || !workflowStoreBlocks || Object.keys(workflowStoreBlocks).length === 0) {
151+
if (!workflowId || blockKeys.length === 0) {
146152
setWorkflowBlocks([])
147153
return
148154
}
149155

150156
try {
157+
// Fetch current blocks from store
158+
const workflowStoreBlocks = useWorkflowStore.getState().blocks
159+
151160
const { registry: blockRegistry } = await import('@/blocks/registry')
152161
const mapped = Object.values(workflowStoreBlocks).map((b: any) => {
153162
const reg = (blockRegistry as any)[b.type]
@@ -169,7 +178,7 @@ export function useMentionData(props: UseMentionDataProps) {
169178
}
170179

171180
syncWorkflowBlocks()
172-
}, [workflowStoreBlocks, workflowId])
181+
}, [blockKeys, workflowId])
173182

174183
/**
175184
* Ensures past chats are loaded
@@ -323,10 +332,10 @@ export function useMentionData(props: UseMentionDataProps) {
323332
if (!workflowId) return
324333
logger.debug('ensureWorkflowBlocksLoaded called', {
325334
workflowId,
326-
storeBlocksCount: Object.keys(workflowStoreBlocks || {}).length,
335+
storeBlocksCount: blockKeys.length,
327336
workflowBlocksCount: workflowBlocks.length,
328337
})
329-
}, [workflowId, workflowStoreBlocks, workflowBlocks.length])
338+
}, [workflowId, blockKeys.length, workflowBlocks.length])
330339

331340
return {
332341
// State

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,9 +210,14 @@ export function Editor() {
210210
/>
211211
) : (
212212
<h2
213-
className='min-w-0 flex-1 cursor-pointer truncate pr-[8px] font-medium text-[14px] text-[var(--white)] dark:text-[var(--white)]'
213+
className='min-w-0 flex-1 cursor-pointer select-none truncate pr-[8px] font-medium text-[14px] text-[var(--white)] dark:text-[var(--white)]'
214214
title={title}
215215
onDoubleClick={handleStartRename}
216+
onMouseDown={(e) => {
217+
if (e.detail === 2) {
218+
e.preventDefault()
219+
}
220+
}}
216221
>
217222
{title}
218223
</h2>

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-node-utilities.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const DEFAULT_CONTAINER_HEIGHT = 300
1111
* Hook providing utilities for node position, hierarchy, and dimension calculations
1212
*/
1313
export function useNodeUtilities(blocks: Record<string, any>) {
14-
const { getNodes, project } = useReactFlow()
14+
const { getNodes } = useReactFlow()
1515

1616
/**
1717
* Check if a block is a container type (loop, parallel, or subflow)

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

Lines changed: 47 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ const WorkflowContent = React.memo(() => {
110110
// Hooks
111111
const params = useParams()
112112
const router = useRouter()
113-
const { project, getNodes, fitView } = useReactFlow()
113+
const { screenToFlowPosition, getNodes, fitView } = useReactFlow()
114114
const { emitCursorUpdate } = useSocket()
115115

116116
// Get workspace ID from the params
@@ -170,7 +170,7 @@ const WorkflowContent = React.memo(() => {
170170
// Get diff analysis for edge reconstruction
171171
const { diffAnalysis, isShowingDiff, isDiffReady } = useWorkflowDiffStore()
172172

173-
// Reconstruct deleted edges when viewing original workflow and filter trigger edges
173+
// Reconstruct deleted edges when viewing original workflow and filter out invalid edges
174174
const edgesForDisplay = useMemo(() => {
175175
let edgesToFilter = edges
176176

@@ -237,7 +237,21 @@ const WorkflowContent = React.memo(() => {
237237
// Combine existing edges with reconstructed deleted edges
238238
edgesToFilter = [...edges, ...reconstructedEdges]
239239
}
240-
return edgesToFilter
240+
241+
// Filter out edges that connect to/from annotation-only blocks (note blocks)
242+
// These blocks don't have handles and shouldn't have connections
243+
return edgesToFilter.filter((edge) => {
244+
const sourceBlock = blocks[edge.source]
245+
const targetBlock = blocks[edge.target]
246+
247+
// Remove edge if either source or target is an annotation-only block
248+
if (!sourceBlock || !targetBlock) return false
249+
if (isAnnotationOnlyBlock(sourceBlock.type) || isAnnotationOnlyBlock(targetBlock.type)) {
250+
return false
251+
}
252+
253+
return true
254+
})
241255
}, [edges, isShowingDiff, isDiffReady, diffAnalysis, blocks])
242256

243257
// User permissions - get current user's specific permissions from context
@@ -680,7 +694,11 @@ const WorkflowContent = React.memo(() => {
680694
// Auto-connect logic for blocks inside containers
681695
const isAutoConnectEnabled = useGeneralStore.getState().isAutoConnectEnabled
682696
let autoConnectEdge
683-
if (isAutoConnectEnabled && data.type !== 'starter') {
697+
if (
698+
isAutoConnectEnabled &&
699+
data.type !== 'starter' &&
700+
!isAnnotationOnlyBlock(data.type)
701+
) {
684702
if (existingChildBlocks.length > 0) {
685703
// Connect to the nearest existing child block within the container
686704
const closestBlock = existingChildBlocks
@@ -694,7 +712,7 @@ const WorkflowContent = React.memo(() => {
694712
.sort((a, b) => a.distance - b.distance)[0]?.block
695713

696714
if (closestBlock) {
697-
// Don't create edges into trigger blocks
715+
// Don't create edges into trigger blocks or annotation blocks
698716
const targetBlockConfig = getBlock(data.type)
699717
const isTargetTrigger =
700718
data.enableTriggerMode === true || targetBlockConfig?.category === 'triggers'
@@ -769,10 +787,14 @@ const WorkflowContent = React.memo(() => {
769787
// Regular auto-connect logic
770788
const isAutoConnectEnabled = useGeneralStore.getState().isAutoConnectEnabled
771789
let autoConnectEdge
772-
if (isAutoConnectEnabled && data.type !== 'starter') {
790+
if (
791+
isAutoConnectEnabled &&
792+
data.type !== 'starter' &&
793+
!isAnnotationOnlyBlock(data.type)
794+
) {
773795
const closestBlock = findClosestOutput(position)
774796
if (closestBlock) {
775-
// Don't create edges into trigger blocks
797+
// Don't create edges into trigger blocks or annotation blocks
776798
const targetBlockConfig = getBlock(data.type)
777799
const isTargetTrigger =
778800
data.enableTriggerMode === true || targetBlockConfig?.category === 'triggers'
@@ -842,7 +864,7 @@ const WorkflowContent = React.memo(() => {
842864
const baseName = type === 'loop' ? 'Loop' : 'Parallel'
843865
const name = getUniqueBlockName(baseName, blocks)
844866

845-
const centerPosition = project({
867+
const centerPosition = screenToFlowPosition({
846868
x: window.innerWidth / 2,
847869
y: window.innerHeight / 2,
848870
})
@@ -891,7 +913,7 @@ const WorkflowContent = React.memo(() => {
891913
}
892914

893915
// Calculate the center position of the viewport
894-
const centerPosition = project({
916+
const centerPosition = screenToFlowPosition({
895917
x: window.innerWidth / 2,
896918
y: window.innerHeight / 2,
897919
})
@@ -906,11 +928,11 @@ const WorkflowContent = React.memo(() => {
906928
// Auto-connect logic
907929
const isAutoConnectEnabled = useGeneralStore.getState().isAutoConnectEnabled
908930
let autoConnectEdge
909-
if (isAutoConnectEnabled && type !== 'starter') {
931+
if (isAutoConnectEnabled && type !== 'starter' && !isAnnotationOnlyBlock(type)) {
910932
const closestBlock = findClosestOutput(centerPosition)
911933
logger.info('Closest block found:', closestBlock)
912934
if (closestBlock) {
913-
// Don't create edges into trigger blocks
935+
// Don't create edges into trigger blocks or annotation blocks
914936
const targetBlockConfig = blockConfig
915937
const isTargetTrigger = enableTriggerMode || targetBlockConfig?.category === 'triggers'
916938

@@ -977,7 +999,7 @@ const WorkflowContent = React.memo(() => {
977999
)
9781000
}
9791001
}, [
980-
project,
1002+
screenToFlowPosition,
9811003
blocks,
9821004
addBlock,
9831005
addEdge,
@@ -1014,7 +1036,7 @@ const WorkflowContent = React.memo(() => {
10141036
}
10151037

10161038
const bounds = canvasElement.getBoundingClientRect()
1017-
const position = project({
1039+
const position = screenToFlowPosition({
10181040
x: detail.clientX - bounds.left,
10191041
y: detail.clientY - bounds.top,
10201042
})
@@ -1041,7 +1063,7 @@ const WorkflowContent = React.memo(() => {
10411063
'toolbar-drop-on-empty-workflow-overlay',
10421064
handleOverlayToolbarDrop as EventListener
10431065
)
1044-
}, [project, handleToolbarDrop])
1066+
}, [screenToFlowPosition, handleToolbarDrop])
10451067

10461068
/**
10471069
* Recenter canvas when diff appears
@@ -1090,7 +1112,7 @@ const WorkflowContent = React.memo(() => {
10901112
if (!data?.type) return
10911113

10921114
const reactFlowBounds = event.currentTarget.getBoundingClientRect()
1093-
const position = project({
1115+
const position = screenToFlowPosition({
10941116
x: event.clientX - reactFlowBounds.left,
10951117
y: event.clientY - reactFlowBounds.top,
10961118
})
@@ -1106,22 +1128,22 @@ const WorkflowContent = React.memo(() => {
11061128
logger.error('Error dropping block on ReactFlow canvas:', { err })
11071129
}
11081130
},
1109-
[project, handleToolbarDrop]
1131+
[screenToFlowPosition, handleToolbarDrop]
11101132
)
11111133

11121134
const handleCanvasPointerMove = useCallback(
11131135
(event: React.PointerEvent<Element>) => {
11141136
const target = event.currentTarget as HTMLElement
11151137
const bounds = target.getBoundingClientRect()
11161138

1117-
const position = project({
1139+
const position = screenToFlowPosition({
11181140
x: event.clientX - bounds.left,
11191141
y: event.clientY - bounds.top,
11201142
})
11211143

11221144
emitCursorUpdate(position)
11231145
},
1124-
[project, emitCursorUpdate]
1146+
[screenToFlowPosition, emitCursorUpdate]
11251147
)
11261148

11271149
const handleCanvasPointerLeave = useCallback(() => {
@@ -1144,7 +1166,7 @@ const WorkflowContent = React.memo(() => {
11441166

11451167
try {
11461168
const reactFlowBounds = event.currentTarget.getBoundingClientRect()
1147-
const position = project({
1169+
const position = screenToFlowPosition({
11481170
x: event.clientX - reactFlowBounds.left,
11491171
y: event.clientY - reactFlowBounds.top,
11501172
})
@@ -1188,7 +1210,7 @@ const WorkflowContent = React.memo(() => {
11881210
logger.error('Error in onDragOver', { err })
11891211
}
11901212
},
1191-
[project, isPointInLoopNode, getNodes]
1213+
[screenToFlowPosition, isPointInLoopNode, getNodes]
11921214
)
11931215

11941216
// Initialize workflow when it exists in registry and isn't active
@@ -1584,8 +1606,8 @@ const WorkflowContent = React.memo(() => {
15841606
// Store currently dragged node ID
15851607
setDraggedNodeId(node.id)
15861608

1587-
// Emit collaborative position update during drag for smooth real-time movement
1588-
collaborativeUpdateBlockPosition(node.id, node.position, false)
1609+
// Note: We don't emit position updates during drag to avoid flooding socket events.
1610+
// The final position is sent in onNodeDragStop for collaborative updates.
15891611

15901612
// Get the current parent ID of the node being dragged
15911613
const currentParentId = blocks[node.id]?.data?.parentId || null
@@ -1721,14 +1743,7 @@ const WorkflowContent = React.memo(() => {
17211743
}
17221744
}
17231745
},
1724-
[
1725-
getNodes,
1726-
potentialParentId,
1727-
blocks,
1728-
getNodeAbsolutePosition,
1729-
getNodeDepth,
1730-
collaborativeUpdateBlockPosition,
1731-
]
1746+
[getNodes, potentialParentId, blocks, getNodeAbsolutePosition, getNodeDepth]
17321747
)
17331748

17341749
// Add in a nodeDrag start event to set the dragStartParentId
@@ -1855,7 +1870,8 @@ const WorkflowContent = React.memo(() => {
18551870

18561871
// Auto-connect when moving an existing block into a container
18571872
const isAutoConnectEnabled = useGeneralStore.getState().isAutoConnectEnabled
1858-
if (isAutoConnectEnabled) {
1873+
// Don't auto-connect annotation blocks (like note blocks)
1874+
if (isAutoConnectEnabled && !isAnnotationOnlyBlock(node.data?.type)) {
18591875
// Existing children in the target container (excluding the moved node)
18601876
const existingChildBlocks = Object.values(blocks).filter(
18611877
(b) => b.data?.parentId === potentialParentId && b.id !== node.id

0 commit comments

Comments
 (0)