From cf74f016624c42d2f6bbbcc899ddabb653d6974f Mon Sep 17 00:00:00 2001 From: waleed Date: Fri, 16 Jan 2026 19:44:43 -0800 Subject: [PATCH] fix(shift): fix shift select blue ring fading --- .../components/note-block/note-block.tsx | 7 ++++- .../components/subflows/subflow-node.tsx | 12 ++++---- .../workflow-block/workflow-block.tsx | 4 +-- .../w/[workflowId]/hooks/use-block-visual.ts | 12 ++++++-- .../w/[workflowId]/utils/block-ring-utils.ts | 28 +++++++++++++++---- 5 files changed, 48 insertions(+), 15 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/note-block/note-block.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/note-block/note-block.tsx index 31c64f908a..2cfa568165 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/note-block/note-block.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/note-block/note-block.tsx @@ -168,12 +168,17 @@ const NoteMarkdown = memo(function NoteMarkdown({ content }: { content: string } ) }) -export const NoteBlock = memo(function NoteBlock({ id, data }: NodeProps) { +export const NoteBlock = memo(function NoteBlock({ + id, + data, + selected, +}: NodeProps) { const { type, config, name } = data const { activeWorkflowId, isEnabled, handleClick, hasRing, ringStyles } = useBlockVisual({ blockId: id, data, + isSelected: selected, }) const storedValues = useSubBlockStore( useCallback( diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/subflows/subflow-node.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/subflows/subflow-node.tsx index 04e64907fa..3733301c44 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/subflows/subflow-node.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/subflows/subflow-node.tsx @@ -66,7 +66,7 @@ export interface SubflowNodeData { * @param props - Node properties containing data and id * @returns Rendered subflow node component */ -export const SubflowNodeComponent = memo(({ data, id }: NodeProps) => { +export const SubflowNodeComponent = memo(({ data, id, selected }: NodeProps) => { const { getNodes } = useReactFlow() const blockRef = useRef(null) const userPermissions = useUserPermissionsContext() @@ -134,13 +134,15 @@ export const SubflowNodeComponent = memo(({ data, id }: NodeProps {!isPreview && ( 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 4559467522..8c8897fbd3 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 @@ -208,7 +208,6 @@ const tryParseJson = (value: unknown): unknown => { export const getDisplayValue = (value: unknown): string => { if (value == null || value === '') return '-' - // Try parsing JSON strings first const parsedValue = tryParseJson(value) if (isMessagesArray(parsedValue)) { @@ -557,6 +556,7 @@ const SubBlockRow = ({ export const WorkflowBlock = memo(function WorkflowBlock({ id, data, + selected, }: NodeProps) { const { type, config, name, isPending } = data @@ -574,7 +574,7 @@ export const WorkflowBlock = memo(function WorkflowBlock({ hasRing, ringStyles, runPathStatus, - } = useBlockVisual({ blockId: id, data, isPending }) + } = useBlockVisual({ blockId: id, data, isPending, isSelected: selected }) const currentBlock = currentWorkflow.getBlockById(id) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-block-visual.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-block-visual.ts index 20246d97d2..33f83bdb94 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-block-visual.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-block-visual.ts @@ -17,6 +17,8 @@ interface UseBlockVisualProps { data: WorkflowBlockProps /** Whether the block is pending execution */ isPending?: boolean + /** Whether the block is selected (via shift-click or selection box) */ + isSelected?: boolean } /** @@ -28,7 +30,12 @@ interface UseBlockVisualProps { * @param props - The hook properties * @returns Visual state, click handler, and ring styling for the block */ -export function useBlockVisual({ blockId, data, isPending = false }: UseBlockVisualProps) { +export function useBlockVisual({ + blockId, + data, + isPending = false, + isSelected = false, +}: UseBlockVisualProps) { const isPreview = data.isPreview ?? false const isPreviewSelected = data.isPreviewSelected ?? false @@ -42,7 +49,6 @@ export function useBlockVisual({ blockId, data, isPending = false }: UseBlockVis isDeletedBlock, } = useBlockState(blockId, currentWorkflow, data) - // Check if the editor panel is open for this block const currentBlockId = usePanelEditorStore((state) => state.currentBlockId) const activeTab = usePanelStore((state) => state.activeTab) const isEditorOpen = !isPreview && currentBlockId === blockId && activeTab === 'editor' @@ -68,6 +74,7 @@ export function useBlockVisual({ blockId, data, isPending = false }: UseBlockVis diffStatus: isPreview ? undefined : diffStatus, runPathStatus, isPreviewSelection: isPreview && isPreviewSelected, + isSelected: isPreview ? false : isSelected, }), [ isExecuting, @@ -78,6 +85,7 @@ export function useBlockVisual({ blockId, data, isPending = false }: UseBlockVis runPathStatus, isPreview, isPreviewSelected, + isSelected, ] ) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/block-ring-utils.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/block-ring-utils.ts index 19eec88625..62c178337b 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/block-ring-utils.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/block-ring-utils.ts @@ -14,6 +14,8 @@ export interface BlockRingOptions { diffStatus: BlockDiffStatus runPathStatus: BlockRunPathStatus isPreviewSelection?: boolean + /** Whether the block is selected via shift-click or selection box (shows blue ring) */ + isSelected?: boolean } /** @@ -32,11 +34,13 @@ export function getBlockRingStyles(options: BlockRingOptions): { diffStatus, runPathStatus, isPreviewSelection, + isSelected, } = options const hasRing = isExecuting || isEditorOpen || + isSelected || isPending || diffStatus === 'new' || diffStatus === 'edited' || @@ -46,25 +50,37 @@ export function getBlockRingStyles(options: BlockRingOptions): { const ringClassName = cn( // Executing block: pulsing success ring with prominent thickness (highest priority) isExecuting && 'ring-[3.5px] ring-[var(--border-success)] animate-ring-pulse', - // Editor open or preview selection: static blue ring + // Editor open, selected, or preview selection: static blue ring !isExecuting && - (isEditorOpen || isPreviewSelection) && + (isEditorOpen || isSelected || isPreviewSelection) && 'ring-[1.75px] ring-[var(--brand-secondary)]', // Non-active states use standard ring utilities - !isExecuting && !isEditorOpen && !isPreviewSelection && hasRing && 'ring-[1.75px]', + !isExecuting && + !isEditorOpen && + !isSelected && + !isPreviewSelection && + hasRing && + 'ring-[1.75px]', // Pending state: warning ring - !isExecuting && !isEditorOpen && isPending && 'ring-[var(--warning)]', + !isExecuting && !isEditorOpen && !isSelected && isPending && 'ring-[var(--warning)]', // Deleted state (highest priority after active/pending) - !isExecuting && !isEditorOpen && !isPending && isDeletedBlock && 'ring-[var(--text-error)]', + !isExecuting && + !isEditorOpen && + !isSelected && + !isPending && + isDeletedBlock && + 'ring-[var(--text-error)]', // Diff states !isExecuting && !isEditorOpen && + !isSelected && !isPending && !isDeletedBlock && diffStatus === 'new' && 'ring-[var(--brand-tertiary-2)]', !isExecuting && !isEditorOpen && + !isSelected && !isPending && !isDeletedBlock && diffStatus === 'edited' && @@ -72,6 +88,7 @@ export function getBlockRingStyles(options: BlockRingOptions): { // Run path states (lowest priority - only show if no other states active) !isExecuting && !isEditorOpen && + !isSelected && !isPending && !isDeletedBlock && !diffStatus && @@ -79,6 +96,7 @@ export function getBlockRingStyles(options: BlockRingOptions): { 'ring-[var(--border-success)]', !isExecuting && !isEditorOpen && + !isSelected && !isPending && !isDeletedBlock && !diffStatus &&