Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -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 <Table key={resource.id} workspaceId={workspaceId} tableId={resource.id} embedded />
Expand Down Expand Up @@ -84,7 +88,7 @@ export function ResourceContent({ workspaceId, resource, previewMode }: Resource
default:
return null
}
}
})

interface ResourceActionsProps {
workspaceId: string
Expand Down Expand Up @@ -303,10 +307,12 @@ 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

Expand Down
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -34,7 +34,7 @@ interface MothershipViewProps {
className?: string
}

export function MothershipView({
export const MothershipView = memo(function MothershipView({
workspaceId,
chatId,
resources,
Expand Down Expand Up @@ -99,4 +99,4 @@ export function MothershipView({
</div>
</div>
)
}
})
1 change: 0 additions & 1 deletion apps/sim/app/workspace/[workspaceId]/home/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
21 changes: 16 additions & 5 deletions apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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?.()
}
}
Expand All @@ -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?.()
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Panel won't re-expand for active-but-collapsed resource

When !wasAdded and activeResourceIdRef.current === resource.id, neither setActiveResourceId nor onResourceEventRef.current?.() is called. This means if the user manually collapsed the resource panel while a resource was active, a subsequent resource_added event for that same resource will not re-expand the panel, even though the PR's goal is for the panel to be visible when the AI references that resource.

Before this PR, onResourceEventRef.current?.() was always fired on resource_added, so handleResourceEvent would re-expand the panel whenever it was collapsed. The new logic silently skips the expand when the resource is already "active" by ID, regardless of panel collapse state.

If the intent is only to avoid the rerender (not the expand), consider still firing the event when the panel is collapsed:

if (!wasAdded) {
  if (activeResourceIdRef.current !== resource.id) {
    setActiveResourceId(resource.id)
    onResourceEventRef.current?.()
  } else if (isResourceCollapsedRef?.current) {
    // Resource is active but panel was manually collapsed — re-expand
    onResourceEventRef.current?.()
  }
} else {
  onResourceEventRef.current?.()
}

(Note: this would require threading isResourceCollapsedRef into useChat or checking collapse state inside handleResourceEvent before deciding to skip.)


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)
Expand Down
Loading