From 15429244f1a09d071c669fbae0ce00193f2b9086 Mon Sep 17 00:00:00 2001 From: Theodore Li Date: Sat, 14 Mar 2026 17:54:18 -0700 Subject: [PATCH 1/4] Improve rerendering of resource view --- .../resource-content/resource-content.tsx | 21 ++++++++++++------- .../mothership-view/mothership-view.tsx | 6 +++--- .../app/workspace/[workspaceId]/home/home.tsx | 1 - .../[workspaceId]/home/hooks/use-chat.ts | 21 ++++++++++++++----- 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/resource-content.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/resource-content.tsx index 0e10017624..76d30cec39 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/resource-content.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/resource-content.tsx @@ -1,6 +1,6 @@ 'use client' -import { lazy, Suspense, useCallback, useEffect, useMemo } from 'react' +import { lazy, memo, Suspense, useCallback, useEffect, useMemo } from 'react' import { createLogger } from '@sim/logger' import { Square } from 'lucide-react' import { useRouter } from 'next/navigation' @@ -51,7 +51,11 @@ interface ResourceContentProps { * Handles table, file, and workflow resource types with appropriate * embedded rendering for each. */ -export function ResourceContent({ workspaceId, resource, previewMode }: ResourceContentProps) { +export const ResourceContent = memo(function ResourceContent({ + workspaceId, + resource, + previewMode, +}: ResourceContentProps) { switch (resource.type) { case 'table': return @@ -84,7 +88,7 @@ export function ResourceContent({ workspaceId, resource, previewMode }: Resource default: return null } -} +}) interface ResourceActionsProps { workspaceId: string @@ -303,10 +307,13 @@ interface EmbeddedWorkflowProps { function EmbeddedWorkflow({ workspaceId, workflowId }: EmbeddedWorkflowProps) { const workflowExists = useWorkflowRegistry((state) => Boolean(state.workflows[workflowId])) - const hydrationPhase = useWorkflowRegistry((state) => state.hydration.phase) - const hydrationWorkflowId = useWorkflowRegistry((state) => state.hydration.workflowId) - const isMetadataLoaded = hydrationPhase !== 'idle' && hydrationPhase !== 'metadata-loading' - const hasLoadError = hydrationPhase === 'error' && hydrationWorkflowId === workflowId + const isMetadataLoaded = useWorkflowRegistry( + (state) => state.hydration.phase !== 'idle' && state.hydration.phase !== 'metadata-loading' + ) + const hasLoadError = useWorkflowRegistry( + (state) => + state.hydration.phase === 'error' && state.hydration.workflowId === workflowId + ) if (!isMetadataLoaded) return LOADING_SKELETON diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/mothership-view.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/mothership-view.tsx index 2df4c44602..44c423e76e 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/mothership-view.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/mothership-view.tsx @@ -1,6 +1,6 @@ 'use client' -import { useCallback, useEffect, useState } from 'react' +import { memo, useCallback, useEffect, useState } from 'react' import { cn } from '@/lib/core/utils/cn' import { getFileExtension } from '@/lib/uploads/utils/file-utils' import type { PreviewMode } from '@/app/workspace/[workspaceId]/files/components/file-viewer' @@ -34,7 +34,7 @@ interface MothershipViewProps { className?: string } -export function MothershipView({ +export const MothershipView = memo(function MothershipView({ workspaceId, chatId, resources, @@ -99,4 +99,4 @@ export function MothershipView({ ) -} +}) diff --git a/apps/sim/app/workspace/[workspaceId]/home/home.tsx b/apps/sim/app/workspace/[workspaceId]/home/home.tsx index 64ef65819f..522b9ee783 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/home.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/home.tsx @@ -167,7 +167,6 @@ export function Home({ chatId }: HomeProps = {}) { const handleResourceEvent = useCallback(() => { if (isResourceCollapsedRef.current) { - /** Auto-collapse sidebar to give resource panel maximum width for immersive experience */ const { isCollapsed, toggleCollapsed } = useSidebarStore.getState() if (!isCollapsed) toggleCollapsed() setIsResourceCollapsed(false) diff --git a/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts b/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts index a3b9e0e146..2cd955baa0 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts @@ -545,6 +545,7 @@ export function useChat( break } case 'tool_result': { + console.log('[tool_result] received', parsed) const id = parsed.toolCallId || getPayloadData(parsed)?.id if (!id) break const idx = toolMap.get(id) @@ -582,8 +583,7 @@ export function useChat( readArgs?.path as string | undefined, tc.result.output ) - if (resource) { - addResource(resource) + if (resource && addResource(resource)) { onResourceEventRef.current?.() } } @@ -594,12 +594,23 @@ export function useChat( case 'resource_added': { const resource = parsed.resource if (resource?.type && resource?.id) { - addResource(resource) + const wasAdded = addResource(resource) invalidateResourceQueries(queryClient, workspaceId, resource.type, resource.id) - onResourceEventRef.current?.() + if (!wasAdded) { + if (activeResourceIdRef.current !== resource.id) { + setActiveResourceId(resource.id) + onResourceEventRef.current?.() + } + } else { + onResourceEventRef.current?.() + } + if (resource.type === 'workflow') { - if (ensureWorkflowInRegistry(resource.id, resource.title, workspaceId)) { + if ( + wasAdded && + ensureWorkflowInRegistry(resource.id, resource.title, workspaceId) + ) { useWorkflowRegistry.getState().setActiveWorkflow(resource.id) } else { useWorkflowRegistry.getState().loadWorkflowState(resource.id) From 20a626573d03fa46a02162652534d2a79467cf1c Mon Sep 17 00:00:00 2001 From: Theodore Li Date: Sat, 14 Mar 2026 18:07:02 -0700 Subject: [PATCH 2/4] Lint fix --- .../components/resource-content/resource-content.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/resource-content.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/resource-content.tsx index 76d30cec39..f920cec221 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/resource-content.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/resource-content.tsx @@ -311,8 +311,7 @@ function EmbeddedWorkflow({ workspaceId, workflowId }: EmbeddedWorkflowProps) { (state) => state.hydration.phase !== 'idle' && state.hydration.phase !== 'metadata-loading' ) const hasLoadError = useWorkflowRegistry( - (state) => - state.hydration.phase === 'error' && state.hydration.workflowId === workflowId + (state) => state.hydration.phase === 'error' && state.hydration.workflowId === workflowId ) if (!isMetadataLoaded) return LOADING_SKELETON From 5e95d33705c069053eef010217cf1ff5ff74a6bb Mon Sep 17 00:00:00 2001 From: Theodore Li Date: Sat, 14 Mar 2026 18:08:23 -0700 Subject: [PATCH 3/4] Remove console log --- apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts b/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts index 2cd955baa0..0803d539d3 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts @@ -545,7 +545,6 @@ export function useChat( break } case 'tool_result': { - console.log('[tool_result] received', parsed) const id = parsed.toolCallId || getPayloadData(parsed)?.id if (!id) break const idx = toolMap.get(id) From 74fe25cacca5cdb268c3c6768e615bd8c65a02c9 Mon Sep 17 00:00:00 2001 From: Theodore Li Date: Sat, 14 Mar 2026 18:53:16 -0700 Subject: [PATCH 4/4] Fix panel logic --- .../[workspaceId]/home/hooks/use-chat.ts | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts b/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts index 0803d539d3..e6aed24417 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts @@ -596,20 +596,18 @@ export function useChat( const wasAdded = addResource(resource) invalidateResourceQueries(queryClient, workspaceId, resource.type, resource.id) - if (!wasAdded) { - if (activeResourceIdRef.current !== resource.id) { - setActiveResourceId(resource.id) - onResourceEventRef.current?.() - } - } else { - onResourceEventRef.current?.() + if (!wasAdded && activeResourceIdRef.current !== resource.id) { + setActiveResourceId(resource.id) } + onResourceEventRef.current?.() if (resource.type === 'workflow') { - if ( - wasAdded && - ensureWorkflowInRegistry(resource.id, resource.title, workspaceId) - ) { + const wasRegistered = ensureWorkflowInRegistry( + resource.id, + resource.title, + workspaceId + ) + if (wasAdded && wasRegistered) { useWorkflowRegistry.getState().setActiveWorkflow(resource.id) } else { useWorkflowRegistry.getState().loadWorkflowState(resource.id)