From 4e9b4532d0f3995239d7eafff2a53f18eb732cf9 Mon Sep 17 00:00:00 2001 From: Adithya Krishna Date: Tue, 24 Mar 2026 22:42:22 +0530 Subject: [PATCH 1/4] chore: fix conflicts --- apps/sim/app/(landing)/blog/[slug]/page.tsx | 2 - .../app/(landing)/blog/authors/[id]/page.tsx | 1 - apps/sim/app/(landing)/blog/post-grid.tsx | 1 - .../voice-interface/voice-interface.tsx | 10 +++- .../templates/components/template-card.tsx | 12 +++-- .../workflows-list/workflows-list.tsx | 2 +- .../logs/components/dashboard/dashboard.tsx | 10 +++- .../components/logs-toolbar/logs-toolbar.tsx | 21 ++++++++- .../app/workspace/[workspaceId]/logs/logs.tsx | 46 ++++++++++++++++++- .../templates/components/template-card.tsx | 12 +++-- .../w/[workflowId]/components/chat/chat.tsx | 24 +++++++++- .../output-select/output-select.tsx | 10 +++- .../components/command-list/command-list.tsx | 3 +- .../variables-input/variables-input.tsx | 2 +- .../toolbar/hooks/use-toolbar-resize.ts | 8 +++- .../panel/hooks/use-panel-resize.ts | 9 +++- .../components/variables/variables.tsx | 19 ++++++-- .../workflow-controls/workflow-controls.tsx | 5 +- .../hooks/use-workflow-execution.ts | 24 ++++++++-- .../workflow-list/workflow-list.tsx | 10 +++- .../components/sidebar/hooks/use-drag-drop.ts | 3 +- .../sidebar/hooks/use-folder-selection.ts | 11 ++++- .../sidebar/hooks/use-sidebar-resize.ts | 9 +++- .../sidebar/hooks/use-workflow-selection.ts | 10 +++- .../[workspaceId]/w/hooks/use-can-delete.ts | 4 +- .../w/hooks/use-delete-selection.ts | 3 +- .../w/hooks/use-delete-workflow.ts | 3 +- .../w/hooks/use-export-folder.ts | 4 +- .../app/workspace/[workspaceId]/w/page.tsx | 3 +- .../workspace/providers/socket-provider.tsx | 5 +- apps/sim/hooks/queries/a2a/agents.ts | 33 +++++++------ apps/sim/hooks/queries/credential-sets.ts | 4 +- apps/sim/hooks/queries/deployments.ts | 7 ++- apps/sim/hooks/queries/kb/knowledge.ts | 8 ++-- apps/sim/hooks/queries/notifications.ts | 3 +- apps/sim/hooks/queries/schedules.ts | 4 +- apps/sim/hooks/queries/workflows.ts | 1 + apps/sim/lib/auth/auth.ts | 5 +- apps/sim/lib/blog/mdx.tsx | 1 - apps/sim/lib/og/capture-preview.ts | 2 +- .../lib/workflows/operations/import-export.ts | 10 +++- apps/sim/next.config.ts | 19 ++++++++ 42 files changed, 311 insertions(+), 72 deletions(-) diff --git a/apps/sim/app/(landing)/blog/[slug]/page.tsx b/apps/sim/app/(landing)/blog/[slug]/page.tsx index d5ed263e2b5..859b093f311 100644 --- a/apps/sim/app/(landing)/blog/[slug]/page.tsx +++ b/apps/sim/app/(landing)/blog/[slug]/page.tsx @@ -60,7 +60,6 @@ export default async function Page({ params }: { params: Promise<{ slug: string sizes='(max-width: 768px) 100vw, 450px' priority itemProp='image' - unoptimized /> @@ -144,7 +143,6 @@ export default async function Page({ params }: { params: Promise<{ slug: string className='h-[160px] w-full object-cover' sizes='(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw' loading='lazy' - unoptimized />
diff --git a/apps/sim/app/(landing)/blog/authors/[id]/page.tsx b/apps/sim/app/(landing)/blog/authors/[id]/page.tsx index 9cb330c396e..6d5bdd0becc 100644 --- a/apps/sim/app/(landing)/blog/authors/[id]/page.tsx +++ b/apps/sim/app/(landing)/blog/authors/[id]/page.tsx @@ -64,7 +64,6 @@ export default async function AuthorPage({ params }: { params: Promise<{ id: str width={600} height={315} className='h-[160px] w-full object-cover transition-transform group-hover:scale-[1.02]' - unoptimized />
diff --git a/apps/sim/app/(landing)/blog/post-grid.tsx b/apps/sim/app/(landing)/blog/post-grid.tsx index e9889dd9b3c..3077b7eef07 100644 --- a/apps/sim/app/(landing)/blog/post-grid.tsx +++ b/apps/sim/app/(landing)/blog/post-grid.tsx @@ -32,7 +32,6 @@ export function PostGrid({ posts }: { posts: Post[] }) { src={p.ogImage} alt={p.title} sizes='(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 33vw' - unoptimized priority={index < 6} loading={index < 6 ? undefined : 'lazy'} fill diff --git a/apps/sim/app/chat/components/voice-interface/voice-interface.tsx b/apps/sim/app/chat/components/voice-interface/voice-interface.tsx index 9c9cc265395..fa9fd90984b 100644 --- a/apps/sim/app/chat/components/voice-interface/voice-interface.tsx +++ b/apps/sim/app/chat/components/voice-interface/voice-interface.tsx @@ -3,9 +3,17 @@ import { type RefObject, useCallback, useEffect, useRef, useState } from 'react' import { createLogger } from '@sim/logger' import { Mic, MicOff, Phone } from 'lucide-react' +import dynamic from 'next/dynamic' import { Button } from '@/components/ui/button' import { cn } from '@/lib/core/utils/cn' -import { ParticlesVisualization } from '@/app/chat/components/voice-interface/components/particles' + +const ParticlesVisualization = dynamic( + () => + import('@/app/chat/components/voice-interface/components/particles').then( + (mod) => mod.ParticlesVisualization + ), + { ssr: false } +) const logger = createLogger('VoiceInterface') diff --git a/apps/sim/app/templates/components/template-card.tsx b/apps/sim/app/templates/components/template-card.tsx index 79445802be9..dd8e3d26129 100644 --- a/apps/sim/app/templates/components/template-card.tsx +++ b/apps/sim/app/templates/components/template-card.tsx @@ -1,6 +1,7 @@ import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react' import { createLogger } from '@sim/logger' import { Star, User } from 'lucide-react' +import Image from 'next/image' import { useParams, useRouter } from 'next/navigation' import { VerifiedBadge } from '@/components/ui/verified-badge' import { cn } from '@/lib/core/utils/cn' @@ -281,9 +282,14 @@ function TemplateCardInner({
{authorImageUrl ? ( -
- {author} -
+ {author} ) : (
diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/components/workflows-list/workflows-list.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/components/workflows-list/workflows-list.tsx index 1da98f6bcf3..3709b3db9ab 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/components/workflows-list/workflows-list.tsx +++ b/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/components/workflows-list/workflows-list.tsx @@ -36,7 +36,7 @@ function WorkflowsListInner({ searchQuery: string segmentDurationMs: number }) { - const { workflows } = useWorkflowRegistry() + const workflows = useWorkflowRegistry((s) => s.workflows) return (
diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/dashboard.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/dashboard.tsx index 686952a2fe5..9f574d50954 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/dashboard.tsx +++ b/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/dashboard.tsx @@ -2,6 +2,7 @@ import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react' import { Loader2 } from 'lucide-react' +import { useShallow } from 'zustand/react/shallow' import { Skeleton } from '@/components/emcn' import { formatLatency } from '@/app/workspace/[workspaceId]/logs/utils' import type { DashboardStatsResponse, WorkflowStats } from '@/hooks/queries/logs' @@ -146,7 +147,14 @@ function DashboardInner({ stats, isLoading, error }: DashboardProps) { const [lastAnchorIndices, setLastAnchorIndices] = useState>({}) const lastAnchorIndicesRef = useRef>({}) - const { workflowIds, searchQuery, toggleWorkflowId, timeRange } = useFilterStore() + const { workflowIds, searchQuery, toggleWorkflowId, timeRange } = useFilterStore( + useShallow((s) => ({ + workflowIds: s.workflowIds, + searchQuery: s.searchQuery, + toggleWorkflowId: s.toggleWorkflowId, + timeRange: s.timeRange, + })) + ) const allWorkflows = useWorkflowRegistry((state) => state.workflows) diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/logs-toolbar.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/logs-toolbar.tsx index ff6dcdfbd51..219c306dc37 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/logs-toolbar.tsx +++ b/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/logs-toolbar.tsx @@ -3,6 +3,7 @@ import { memo, useCallback, useMemo, useState } from 'react' import { ArrowUp, Bell, Library, MoreHorizontal, RefreshCw } from 'lucide-react' import { useParams } from 'next/navigation' +import { useShallow } from 'zustand/react/shallow' import { Button, Combobox, @@ -195,7 +196,25 @@ export const LogsToolbar = memo(function LogsToolbar({ setDateRange, clearDateRange, resetFilters, - } = useFilterStore() + } = useFilterStore( + useShallow((s) => ({ + level: s.level, + setLevel: s.setLevel, + workflowIds: s.workflowIds, + setWorkflowIds: s.setWorkflowIds, + folderIds: s.folderIds, + setFolderIds: s.setFolderIds, + triggers: s.triggers, + setTriggers: s.setTriggers, + timeRange: s.timeRange, + setTimeRange: s.setTimeRange, + startDate: s.startDate, + endDate: s.endDate, + setDateRange: s.setDateRange, + clearDateRange: s.clearDateRange, + resetFilters: s.resetFilters, + })) + ) const [datePickerOpen, setDatePickerOpen] = useState(false) const [previousTimeRange, setPreviousTimeRange] = useState(timeRange) diff --git a/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx b/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx index fa66608a39e..d21929f5ae9 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx +++ b/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx @@ -3,6 +3,7 @@ import { useCallback, useEffect, useMemo, useReducer, useRef, useState } from 'react' import { useQueryClient } from '@tanstack/react-query' import { useParams } from 'next/navigation' +import { useShallow } from 'zustand/react/shallow' import { Bell, Button, @@ -230,7 +231,30 @@ export default function Logs() { setTimeRange, setDateRange, clearDateRange, - } = useFilterStore() + } = useFilterStore( + useShallow((s) => ({ + setWorkspaceId: s.setWorkspaceId, + initializeFromURL: s.initializeFromURL, + timeRange: s.timeRange, + startDate: s.startDate, + endDate: s.endDate, + level: s.level, + workflowIds: s.workflowIds, + folderIds: s.folderIds, + setWorkflowIds: s.setWorkflowIds, + setSearchQuery: s.setSearchQuery, + triggers: s.triggers, + viewMode: s.viewMode, + setViewMode: s.setViewMode, + resetFilters: s.resetFilters, + setLevel: s.setLevel, + setFolderIds: s.setFolderIds, + setTriggers: s.setTriggers, + setTimeRange: s.setTimeRange, + setDateRange: s.setDateRange, + clearDateRange: s.clearDateRange, + })) + ) useEffect(() => { setWorkspaceId(workspaceId) @@ -1133,7 +1157,25 @@ function LogsFilterPanel({ searchQuery, onSearchQueryChange }: LogsFilterPanelPr setDateRange, clearDateRange, resetFilters, - } = useFilterStore() + } = useFilterStore( + useShallow((s) => ({ + level: s.level, + setLevel: s.setLevel, + workflowIds: s.workflowIds, + setWorkflowIds: s.setWorkflowIds, + folderIds: s.folderIds, + setFolderIds: s.setFolderIds, + triggers: s.triggers, + setTriggers: s.setTriggers, + timeRange: s.timeRange, + setTimeRange: s.setTimeRange, + startDate: s.startDate, + endDate: s.endDate, + setDateRange: s.setDateRange, + clearDateRange: s.clearDateRange, + resetFilters: s.resetFilters, + })) + ) const [datePickerOpen, setDatePickerOpen] = useState(false) const [previousTimeRange, setPreviousTimeRange] = useState(timeRange) diff --git a/apps/sim/app/workspace/[workspaceId]/templates/components/template-card.tsx b/apps/sim/app/workspace/[workspaceId]/templates/components/template-card.tsx index a19809e4e06..ad66eecbd57 100644 --- a/apps/sim/app/workspace/[workspaceId]/templates/components/template-card.tsx +++ b/apps/sim/app/workspace/[workspaceId]/templates/components/template-card.tsx @@ -1,5 +1,6 @@ import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react' import { Star, User } from 'lucide-react' +import Image from 'next/image' import { useParams, useRouter } from 'next/navigation' import { VerifiedBadge } from '@/components/ui/verified-badge' import { cn } from '@/lib/core/utils/cn' @@ -288,9 +289,14 @@ function TemplateCardInner({
{authorImageUrl ? ( -
- {author} -
+ {author} ) : (
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat.tsx index e8aa9bd0131..42bb7a79825 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat.tsx @@ -11,6 +11,7 @@ import { Square, X, } from 'lucide-react' +import { useShallow } from 'zustand/react/shallow' import { Badge, Button, @@ -220,7 +221,7 @@ interface StartInputFormatField { * position across sessions using the floating chat store. */ export function Chat() { - const { activeWorkflowId } = useWorkflowRegistry() + const activeWorkflowId = useWorkflowRegistry((s) => s.activeWorkflowId) const blocks = useWorkflowStore((state) => state.blocks) const triggerWorkflowUpdate = useWorkflowStore((state) => state.triggerUpdate) const setSubBlockValue = useSubBlockStore((state) => state.setValue) @@ -242,7 +243,26 @@ export function Chat() { getConversationId, clearChat, exportChatCSV, - } = useChatStore() + } = useChatStore( + useShallow((s) => ({ + isChatOpen: s.isChatOpen, + chatPosition: s.chatPosition, + chatWidth: s.chatWidth, + chatHeight: s.chatHeight, + setIsChatOpen: s.setIsChatOpen, + setChatPosition: s.setChatPosition, + setChatDimensions: s.setChatDimensions, + messages: s.messages, + addMessage: s.addMessage, + selectedWorkflowOutputs: s.selectedWorkflowOutputs, + setSelectedWorkflowOutput: s.setSelectedWorkflowOutput, + appendMessageContent: s.appendMessageContent, + finalizeMessageStream: s.finalizeMessageStream, + getConversationId: s.getConversationId, + clearChat: s.clearChat, + exportChatCSV: s.exportChatCSV, + })) + ) const hasConsoleHydrated = useTerminalConsoleStore((state) => state._hasHydrated) const entriesFromStore = useTerminalConsoleStore((state) => state.entries) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/components/output-select/output-select.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/components/output-select/output-select.tsx index 8decb13cf71..17afd48c5e3 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/components/output-select/output-select.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/components/output-select/output-select.tsx @@ -3,6 +3,7 @@ import type React from 'react' import { useMemo } from 'react' import { RepeatIcon, SplitIcon } from 'lucide-react' +import { useShallow } from 'zustand/react/shallow' import { Combobox, type ComboboxOptionGroup } from '@/components/emcn' import { getEffectiveBlockOutputs } from '@/lib/workflows/blocks/block-outputs' import { hasTriggerCapability } from '@/lib/workflows/triggers/trigger-utils' @@ -80,7 +81,14 @@ export function OutputSelect({ maxHeight = 200, }: OutputSelectProps) { const blocks = useWorkflowStore((state) => state.blocks) - const { isShowingDiff, isDiffReady, hasActiveDiff, baselineWorkflow } = useWorkflowDiffStore() + const { isShowingDiff, isDiffReady, hasActiveDiff, baselineWorkflow } = useWorkflowDiffStore( + useShallow((s) => ({ + isShowingDiff: s.isShowingDiff, + isDiffReady: s.isDiffReady, + hasActiveDiff: s.hasActiveDiff, + baselineWorkflow: s.baselineWorkflow, + })) + ) const subBlockValues = useSubBlockStore((state) => workflowId ? state.workflowValues[workflowId] : null ) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/command-list/command-list.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/command-list/command-list.tsx index f115a655f3e..8fc8935c4d8 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/command-list/command-list.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/command-list/command-list.tsx @@ -58,7 +58,7 @@ const commands: CommandItem[] = [ export function CommandList() { const params = useParams() const router = useRouter() - const { open: openSearchModal } = useSearchModalStore() + const openSearchModal = useSearchModalStore((s) => s.open) const preventZoomRef = usePreventZoom() const workspaceId = params.workspaceId as string | undefined @@ -195,7 +195,6 @@ export function CommandList() { filter: 'brightness(0) saturate(100%) invert(69%) sepia(0%) saturate(0%) hue-rotate(202deg) brightness(94%) contrast(89%)', }} - priority />
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/variables-input/variables-input.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/variables-input/variables-input.tsx index 3ca20f572f0..16184393b1c 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/variables-input/variables-input.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/variables-input/variables-input.tsx @@ -85,7 +85,7 @@ export function VariablesInput({ const params = useParams() const workflowId = params.workflowId as string const [storeValue, setStoreValue] = useSubBlockValue(blockId, subBlockId) - const { variables: workflowVariables } = useVariablesStore() + const workflowVariables = useVariablesStore((s) => s.variables) const accessiblePrefixes = useAccessibleReferencePrefixes(blockId) const [showTags, setShowTags] = useState(false) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/toolbar/hooks/use-toolbar-resize.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/toolbar/hooks/use-toolbar-resize.ts index a585d982190..9e910edea70 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/toolbar/hooks/use-toolbar-resize.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/toolbar/hooks/use-toolbar-resize.ts @@ -1,4 +1,5 @@ import { useCallback, useEffect, useRef, useState } from 'react' +import { useShallow } from 'zustand/react/shallow' import { useToolbarStore } from '@/stores/panel' /** @@ -76,7 +77,12 @@ export function useToolbarResize({ triggersContentRef, triggersHeaderRef, }: UseToolbarResizeProps) { - const { toolbarTriggersHeight, setToolbarTriggersHeight } = useToolbarStore() + const { toolbarTriggersHeight, setToolbarTriggersHeight } = useToolbarStore( + useShallow((s) => ({ + toolbarTriggersHeight: s.toolbarTriggersHeight, + setToolbarTriggersHeight: s.setToolbarTriggersHeight, + })) + ) const [isResizing, setIsResizing] = useState(false) const startYRef = useRef(0) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/hooks/use-panel-resize.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/hooks/use-panel-resize.ts index f4694662788..4f442fe053b 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/hooks/use-panel-resize.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/hooks/use-panel-resize.ts @@ -1,4 +1,5 @@ import { useCallback, useEffect } from 'react' +import { useShallow } from 'zustand/react/shallow' import { PANEL_WIDTH } from '@/stores/constants' import { usePanelStore } from '@/stores/panel' @@ -13,7 +14,13 @@ const CONTENT_WINDOW_GAP = 8 * @returns Resize state and handlers */ export function usePanelResize() { - const { setPanelWidth, isResizing, setIsResizing } = usePanelStore() + const { setPanelWidth, isResizing, setIsResizing } = usePanelStore( + useShallow((s) => ({ + setPanelWidth: s.setPanelWidth, + isResizing: s.isResizing, + setIsResizing: s.setIsResizing, + })) + ) /** * Handles mouse down on resize handle diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/variables/variables.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/variables/variables.tsx index 08b09689604..839f4c69104 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/variables/variables.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/variables/variables.tsx @@ -3,6 +3,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react' import { Plus, X } from 'lucide-react' import Editor from 'react-simple-code-editor' +import { useShallow } from 'zustand/react/shallow' import { Badge, Button, @@ -92,12 +93,22 @@ const STRINGS = { * - Uses emcn Input/Code/Combobox components for a consistent UI */ export function Variables() { - const { activeWorkflowId } = useWorkflowRegistry() + const activeWorkflowId = useWorkflowRegistry((s) => s.activeWorkflowId) const { isOpen, position, width, height, setIsOpen, setPosition, setDimensions } = - useVariablesStore() - - const { getVariablesByWorkflowId } = usePanelVariablesStore() + useVariablesStore( + useShallow((s) => ({ + isOpen: s.isOpen, + position: s.position, + width: s.width, + height: s.height, + setIsOpen: s.setIsOpen, + setPosition: s.setPosition, + setDimensions: s.setDimensions, + })) + ) + + const getVariablesByWorkflowId = usePanelVariablesStore((s) => s.getVariablesByWorkflowId) const { collaborativeUpdateVariable, collaborativeAddVariable, collaborativeDeleteVariable } = useCollaborativeWorkflow() diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-controls/workflow-controls.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-controls/workflow-controls.tsx index 53b0d88eb51..4cd7b328150 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-controls/workflow-controls.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-controls/workflow-controls.tsx @@ -4,6 +4,7 @@ import { memo, useCallback, useRef, useState } from 'react' import { createLogger } from '@sim/logger' import { Scan } from 'lucide-react' import { useReactFlow } from 'reactflow' +import { useShallow } from 'zustand/react/shallow' import { Button, ChevronDown, @@ -36,7 +37,9 @@ const logger = createLogger('WorkflowControls') export const WorkflowControls = memo(function WorkflowControls() { const reactFlowInstance = useReactFlow() const { fitViewToBounds } = useCanvasViewport(reactFlowInstance) - const { mode, setMode } = useCanvasModeStore() + const { mode, setMode } = useCanvasModeStore( + useShallow((s) => ({ mode: s.mode, setMode: s.setMode })) + ) const { undo, redo } = useCollaborativeWorkflow() const showWorkflowControls = useShowActionBar() const updateSetting = useUpdateGeneralSetting() diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts index e29c3849038..9233134b826 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts @@ -2,6 +2,7 @@ import { useCallback, useEffect, useRef, useState } from 'react' import { createLogger } from '@sim/logger' import { useQueryClient } from '@tanstack/react-query' import { v4 as uuidv4 } from 'uuid' +import { useShallow } from 'zustand/react/shallow' import { buildTraceSpans } from '@/lib/logs/execution/trace-spans/trace-spans' import { processStreamingBlockLogs } from '@/lib/tokenization' import { @@ -97,12 +98,27 @@ function normalizeErrorMessage(error: unknown): string { export function useWorkflowExecution() { const queryClient = useQueryClient() const currentWorkflow = useCurrentWorkflow() - const { activeWorkflowId, workflows } = useWorkflowRegistry() + const { activeWorkflowId, workflows } = useWorkflowRegistry( + useShallow((s) => ({ activeWorkflowId: s.activeWorkflowId, workflows: s.workflows })) + ) const { toggleConsole, addConsole, updateConsole, cancelRunningEntries, clearExecutionEntries } = - useTerminalConsoleStore() + useTerminalConsoleStore( + useShallow((s) => ({ + toggleConsole: s.toggleConsole, + addConsole: s.addConsole, + updateConsole: s.updateConsole, + cancelRunningEntries: s.cancelRunningEntries, + clearExecutionEntries: s.clearExecutionEntries, + })) + ) const hasHydrated = useTerminalConsoleStore((s) => s._hasHydrated) - const { getAllVariables } = useEnvironmentStore() - const { getVariablesByWorkflowId, variables } = useVariablesStore() + const getAllVariables = useEnvironmentStore((s) => s.getAllVariables) + const { getVariablesByWorkflowId, variables } = useVariablesStore( + useShallow((s) => ({ + getVariablesByWorkflowId: s.getVariablesByWorkflowId, + variables: s.variables, + })) + ) const { isExecuting, isDebugging, pendingBlocks, executor, debugContext } = useCurrentWorkflowExecution() const setCurrentExecutionId = useExecutionStore((s) => s.setCurrentExecutionId) diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/workflow-list.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/workflow-list.tsx index cddb472a6d4..ccde17e43b5 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/workflow-list.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/workflow-list.tsx @@ -2,6 +2,7 @@ import { memo, useCallback, useEffect, useMemo } from 'react' import clsx from 'clsx' +import { useShallow } from 'zustand/react/shallow' import { EmptyAreaContextMenu } from '@/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/empty-area-context-menu' import { FolderItem } from '@/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/folder-item/folder-item' import { WorkflowItem } from '@/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/workflow-item/workflow-item' @@ -78,7 +79,14 @@ export const WorkflowList = memo(function WorkflowList({ }: WorkflowListProps) { const { isLoading: foldersLoading } = useFolders(workspaceId) const folders = useFolderStore((state) => state.folders) - const { getFolderTree, expandedFolders, getFolderPath, setExpanded } = useFolderStore() + const { getFolderTree, expandedFolders, getFolderPath, setExpanded } = useFolderStore( + useShallow((s) => ({ + getFolderTree: s.getFolderTree, + expandedFolders: s.expandedFolders, + getFolderPath: s.getFolderPath, + setExpanded: s.setExpanded, + })) + ) const { isOpen: isEmptyAreaMenuOpen, diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/hooks/use-drag-drop.ts b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/hooks/use-drag-drop.ts index 581ca8ad907..4e86d19749e 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/hooks/use-drag-drop.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/hooks/use-drag-drop.ts @@ -47,7 +47,8 @@ export function useDragDrop(options: UseDragDropOptions = {}) { const workspaceId = params.workspaceId as string | undefined const reorderWorkflowsMutation = useReorderWorkflows() const reorderFoldersMutation = useReorderFolders() - const { setExpanded, expandedFolders } = useFolderStore() + const setExpanded = useFolderStore((s) => s.setExpanded) + const expandedFolders = useFolderStore((s) => s.expandedFolders) const handleAutoScroll = useCallback(() => { if (!scrollContainerRef.current) { diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/hooks/use-folder-selection.ts b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/hooks/use-folder-selection.ts index 7fbed4786bf..49597dec9ba 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/hooks/use-folder-selection.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/hooks/use-folder-selection.ts @@ -1,4 +1,5 @@ import { useCallback } from 'react' +import { useShallow } from 'zustand/react/shallow' import { useFolderStore } from '@/stores/folders/store' interface UseFolderSelectionProps { @@ -44,7 +45,15 @@ export function useFolderSelection({ selectFolderOnly, selectFolderRange, toggleFolderSelection, - } = useFolderStore() + } = useFolderStore( + useShallow((s) => ({ + selectedFolders: s.selectedFolders, + lastSelectedFolderId: s.lastSelectedFolderId, + selectFolderOnly: s.selectFolderOnly, + selectFolderRange: s.selectFolderRange, + toggleFolderSelection: s.toggleFolderSelection, + })) + ) /** * Deselect any workflows whose folder (or any ancestor folder) is currently selected. diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/hooks/use-sidebar-resize.ts b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/hooks/use-sidebar-resize.ts index 69b7877c061..22de4b1a537 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/hooks/use-sidebar-resize.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/hooks/use-sidebar-resize.ts @@ -1,4 +1,5 @@ import { useCallback, useEffect } from 'react' +import { useShallow } from 'zustand/react/shallow' import { SIDEBAR_WIDTH } from '@/stores/constants' import { useSidebarStore } from '@/stores/sidebar/store' @@ -10,7 +11,13 @@ import { useSidebarStore } from '@/stores/sidebar/store' * @returns Resize state and handlers */ export function useSidebarResize() { - const { setSidebarWidth, isResizing, setIsResizing } = useSidebarStore() + const { setSidebarWidth, isResizing, setIsResizing } = useSidebarStore( + useShallow((s) => ({ + setSidebarWidth: s.setSidebarWidth, + isResizing: s.isResizing, + setIsResizing: s.setIsResizing, + })) + ) /** * Handles mouse down on resize handle diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/hooks/use-workflow-selection.ts b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/hooks/use-workflow-selection.ts index b1b49b389dc..3fc12310a6f 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/hooks/use-workflow-selection.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/hooks/use-workflow-selection.ts @@ -1,4 +1,5 @@ import { useCallback } from 'react' +import { useShallow } from 'zustand/react/shallow' import { useFolderStore } from '@/stores/folders/store' interface UseWorkflowSelectionProps { @@ -30,7 +31,14 @@ export function useWorkflowSelection({ activeWorkflowId, workflowAncestorFolderIds, }: UseWorkflowSelectionProps) { - const { selectedWorkflows, selectOnly, selectRange, toggleWorkflowSelection } = useFolderStore() + const { selectedWorkflows, selectOnly, selectRange, toggleWorkflowSelection } = useFolderStore( + useShallow((s) => ({ + selectedWorkflows: s.selectedWorkflows, + selectOnly: s.selectOnly, + selectRange: s.selectRange, + toggleWorkflowSelection: s.toggleWorkflowSelection, + })) + ) /** * After a workflow selection change, deselect any folder that is an ancestor of a selected diff --git a/apps/sim/app/workspace/[workspaceId]/w/hooks/use-can-delete.ts b/apps/sim/app/workspace/[workspaceId]/w/hooks/use-can-delete.ts index f206fa90ce9..e109ca816cb 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/hooks/use-can-delete.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/hooks/use-can-delete.ts @@ -36,8 +36,8 @@ interface UseCanDeleteReturn { * @returns Functions to check deletion eligibility */ export function useCanDelete({ workspaceId }: UseCanDeleteProps): UseCanDeleteReturn { - const { workflows } = useWorkflowRegistry() - const { folders } = useFolderStore() + const workflows = useWorkflowRegistry((s) => s.workflows) + const folders = useFolderStore((s) => s.folders) /** * Pre-computed data structures for efficient lookups diff --git a/apps/sim/app/workspace/[workspaceId]/w/hooks/use-delete-selection.ts b/apps/sim/app/workspace/[workspaceId]/w/hooks/use-delete-selection.ts index ac0aeed55f2..b37cf32c322 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/hooks/use-delete-selection.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/hooks/use-delete-selection.ts @@ -46,7 +46,8 @@ export function useDeleteSelection({ onSuccess, }: UseDeleteSelectionProps) { const router = useRouter() - const { workflows, removeWorkflow } = useWorkflowRegistry() + const workflows = useWorkflowRegistry((s) => s.workflows) + const removeWorkflow = useWorkflowRegistry((s) => s.removeWorkflow) const deleteFolderMutation = useDeleteFolderMutation() const [isDeleting, setIsDeleting] = useState(false) diff --git a/apps/sim/app/workspace/[workspaceId]/w/hooks/use-delete-workflow.ts b/apps/sim/app/workspace/[workspaceId]/w/hooks/use-delete-workflow.ts index dc7d29e7081..37a56d24c0d 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/hooks/use-delete-workflow.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/hooks/use-delete-workflow.ts @@ -42,7 +42,8 @@ export function useDeleteWorkflow({ }: UseDeleteWorkflowProps) { const router = useRouter() const queryClient = useQueryClient() - const { workflows, removeWorkflow } = useWorkflowRegistry() + const workflows = useWorkflowRegistry((s) => s.workflows) + const removeWorkflow = useWorkflowRegistry((s) => s.removeWorkflow) const [isDeleting, setIsDeleting] = useState(false) /** diff --git a/apps/sim/app/workspace/[workspaceId]/w/hooks/use-export-folder.ts b/apps/sim/app/workspace/[workspaceId]/w/hooks/use-export-folder.ts index 402b13535fd..e7a646b2f68 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/hooks/use-export-folder.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/hooks/use-export-folder.ts @@ -89,8 +89,8 @@ function collectSubfolders( * Hook for managing folder export to ZIP. */ export function useExportFolder({ folderId, onSuccess }: UseExportFolderProps) { - const { workflows } = useWorkflowRegistry() - const { folders } = useFolderStore() + const workflows = useWorkflowRegistry((s) => s.workflows) + const folders = useFolderStore((s) => s.folders) const [isExporting, setIsExporting] = useState(false) const hasWorkflows = useMemo(() => { diff --git a/apps/sim/app/workspace/[workspaceId]/w/page.tsx b/apps/sim/app/workspace/[workspaceId]/w/page.tsx index d60e7a0b703..e19bfd387e4 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/page.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/page.tsx @@ -12,7 +12,8 @@ const logger = createLogger('WorkflowsPage') export default function WorkflowsPage() { const router = useRouter() - const { workflows, setActiveWorkflow } = useWorkflowRegistry() + const workflows = useWorkflowRegistry((s) => s.workflows) + const setActiveWorkflow = useWorkflowRegistry((s) => s.setActiveWorkflow) const params = useParams() const workspaceId = params.workspaceId as string const [isMounted, setIsMounted] = useState(false) diff --git a/apps/sim/app/workspace/providers/socket-provider.tsx b/apps/sim/app/workspace/providers/socket-provider.tsx index 3cebcaa5729..04b06e7214b 100644 --- a/apps/sim/app/workspace/providers/socket-provider.tsx +++ b/apps/sim/app/workspace/providers/socket-provider.tsx @@ -12,7 +12,7 @@ import { } from 'react' import { createLogger } from '@sim/logger' import { useParams } from 'next/navigation' -import { io, type Socket } from 'socket.io-client' +import type { Socket } from 'socket.io-client' import { getEnv } from '@/lib/core/config/env' import { useOperationQueueStore } from '@/stores/operation-queue/store' @@ -197,8 +197,9 @@ export function SocketProvider({ children, user }: SocketProviderProps) { initializedRef.current = true setIsConnecting(true) - const initializeSocket = () => { + const initializeSocket = async () => { try { + const { io } = await import('socket.io-client') const socketUrl = getEnv('NEXT_PUBLIC_SOCKET_URL') || 'http://localhost:3002' logger.info('Attempting to connect to Socket.IO server', { diff --git a/apps/sim/hooks/queries/a2a/agents.ts b/apps/sim/hooks/queries/a2a/agents.ts index e67b58c2eb1..b0d9c850e49 100644 --- a/apps/sim/hooks/queries/a2a/agents.ts +++ b/apps/sim/hooks/queries/a2a/agents.ts @@ -36,8 +36,10 @@ export interface A2AAgent { */ export const a2aAgentKeys = { all: ['a2a-agents'] as const, - list: (workspaceId: string) => [...a2aAgentKeys.all, 'list', workspaceId] as const, - detail: (agentId: string) => [...a2aAgentKeys.all, 'detail', agentId] as const, + lists: () => [...a2aAgentKeys.all, 'list'] as const, + list: (workspaceId: string) => [...a2aAgentKeys.lists(), workspaceId] as const, + details: () => [...a2aAgentKeys.all, 'detail'] as const, + detail: (agentId: string) => [...a2aAgentKeys.details(), agentId] as const, byWorkflow: (workspaceId: string, workflowId: string) => [...a2aAgentKeys.all, 'byWorkflow', workspaceId, workflowId] as const, } @@ -148,9 +150,8 @@ export function useCreateA2AAgent() { return useMutation({ mutationFn: createA2AAgent, onSuccess: () => { - // Invalidate all a2a-agent queries (list, detail, byWorkflow, etc.) queryClient.invalidateQueries({ - queryKey: a2aAgentKeys.all, + queryKey: a2aAgentKeys.lists(), }) }, }) @@ -197,10 +198,12 @@ export function useUpdateA2AAgent() { return useMutation({ mutationFn: updateA2AAgent, - onSuccess: () => { - // Invalidate all a2a-agent queries (list, detail, byWorkflow, etc.) + onSuccess: (_data, variables) => { + queryClient.invalidateQueries({ + queryKey: a2aAgentKeys.lists(), + }) queryClient.invalidateQueries({ - queryKey: a2aAgentKeys.all, + queryKey: a2aAgentKeys.detail(variables.agentId), }) }, }) @@ -227,10 +230,12 @@ export function useDeleteA2AAgent() { return useMutation({ mutationFn: deleteA2AAgent, - onSuccess: () => { - // Invalidate all a2a-agent queries (list, detail, byWorkflow, etc.) + onSuccess: (_data, variables) => { queryClient.invalidateQueries({ - queryKey: a2aAgentKeys.all, + queryKey: a2aAgentKeys.lists(), + }) + queryClient.invalidateQueries({ + queryKey: a2aAgentKeys.detail(variables.agentId), }) }, }) @@ -272,10 +277,12 @@ export function usePublishA2AAgent() { return useMutation({ mutationFn: publishA2AAgent, - onSuccess: () => { - // Invalidate all a2a-agent queries (list, detail, byWorkflow, etc.) + onSuccess: (_data, variables) => { + queryClient.invalidateQueries({ + queryKey: a2aAgentKeys.lists(), + }) queryClient.invalidateQueries({ - queryKey: a2aAgentKeys.all, + queryKey: a2aAgentKeys.detail(variables.agentId), }) }, }) diff --git a/apps/sim/hooks/queries/credential-sets.ts b/apps/sim/hooks/queries/credential-sets.ts index 5b71a4633df..49cace670bf 100644 --- a/apps/sim/hooks/queries/credential-sets.ts +++ b/apps/sim/hooks/queries/credential-sets.ts @@ -1,6 +1,6 @@ 'use client' -import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' +import { keepPreviousData, useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { fetchJson } from '@/hooks/selectors/helpers' export interface CredentialSet { @@ -88,6 +88,7 @@ export function useCredentialSets(organizationId?: string, enabled = true) { queryFn: ({ signal }) => fetchCredentialSets(organizationId ?? '', signal), enabled: Boolean(organizationId) && enabled, staleTime: 60 * 1000, + placeholderData: keepPreviousData, }) } @@ -112,6 +113,7 @@ export function useCredentialSetDetail(id?: string, enabled = true) { queryFn: ({ signal }) => fetchCredentialSetById(id ?? '', signal), enabled: Boolean(id) && enabled, staleTime: 60 * 1000, + placeholderData: keepPreviousData, }) } diff --git a/apps/sim/hooks/queries/deployments.ts b/apps/sim/hooks/queries/deployments.ts index 716408bebf3..0896e4d599b 100644 --- a/apps/sim/hooks/queries/deployments.ts +++ b/apps/sim/hooks/queries/deployments.ts @@ -1,7 +1,7 @@ import { useCallback } from 'react' import { createLogger } from '@sim/logger' import type { QueryClient } from '@tanstack/react-query' -import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' +import { keepPreviousData, useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import type { WorkflowDeploymentVersionResponse } from '@/lib/workflows/persistence/utils' import { useWorkflowRegistry } from '@/stores/workflows/registry/store' import type { WorkflowState } from '@/stores/workflows/workflow/types' @@ -89,6 +89,7 @@ export function useDeploymentInfo(workflowId: string | null, options?: { enabled queryFn: ({ signal }) => fetchDeploymentInfo(workflowId!, signal), enabled: Boolean(workflowId) && (options?.enabled ?? true), staleTime: 30 * 1000, // 30 seconds + placeholderData: keepPreviousData, }) } @@ -123,6 +124,7 @@ export function useDeployedWorkflowState( queryFn: ({ signal }) => fetchDeployedWorkflowState(workflowId!, signal), enabled: Boolean(workflowId) && (options?.enabled ?? true), staleTime: 30 * 1000, + placeholderData: keepPreviousData, }) } @@ -162,6 +164,7 @@ export function useDeploymentVersions(workflowId: string | null, options?: { ena queryFn: ({ signal }) => fetchDeploymentVersions(workflowId!, signal), enabled: Boolean(workflowId) && (options?.enabled ?? true), staleTime: 30 * 1000, // 30 seconds + placeholderData: keepPreviousData, }) } @@ -209,6 +212,7 @@ export function useChatDeploymentStatus( queryFn: ({ signal }) => fetchChatDeploymentStatus(workflowId!, signal), enabled: Boolean(workflowId) && (options?.enabled ?? true), staleTime: 30 * 1000, // 30 seconds + placeholderData: keepPreviousData, }) } @@ -256,6 +260,7 @@ export function useChatDetail(chatId: string | null, options?: { enabled?: boole queryFn: ({ signal }) => fetchChatDetail(chatId!, signal), enabled: Boolean(chatId) && (options?.enabled ?? true), staleTime: 30 * 1000, // 30 seconds + placeholderData: keepPreviousData, }) } diff --git a/apps/sim/hooks/queries/kb/knowledge.ts b/apps/sim/hooks/queries/kb/knowledge.ts index 73d6b765d24..160f3263112 100644 --- a/apps/sim/hooks/queries/kb/knowledge.ts +++ b/apps/sim/hooks/queries/kb/knowledge.ts @@ -731,7 +731,7 @@ export function useCreateKnowledgeBase(workspaceId?: string) { mutationFn: createKnowledgeBase, onSuccess: () => { queryClient.invalidateQueries({ - queryKey: knowledgeKeys.all, + queryKey: knowledgeKeys.lists(), }) }, }) @@ -779,10 +779,10 @@ export function useUpdateKnowledgeBase(workspaceId?: string) { }, onSuccess: (_, { knowledgeBaseId }) => { queryClient.invalidateQueries({ - queryKey: knowledgeKeys.detail(knowledgeBaseId), + queryKey: knowledgeKeys.lists(), }) queryClient.invalidateQueries({ - queryKey: knowledgeKeys.all, + queryKey: knowledgeKeys.detail(knowledgeBaseId), }) }, }) @@ -817,7 +817,7 @@ export function useDeleteKnowledgeBase(workspaceId?: string) { mutationFn: deleteKnowledgeBase, onSuccess: () => { queryClient.invalidateQueries({ - queryKey: knowledgeKeys.all, + queryKey: knowledgeKeys.lists(), }) }, }) diff --git a/apps/sim/hooks/queries/notifications.ts b/apps/sim/hooks/queries/notifications.ts index 58c405dbf35..be6894a83ec 100644 --- a/apps/sim/hooks/queries/notifications.ts +++ b/apps/sim/hooks/queries/notifications.ts @@ -1,5 +1,5 @@ import { createLogger } from '@sim/logger' -import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' +import { keepPreviousData, useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import type { CoreTriggerType } from '@/stores/logs/filters/types' const logger = createLogger('NotificationQueries') @@ -97,6 +97,7 @@ export function useNotifications(workspaceId?: string) { queryFn: ({ signal }) => fetchNotifications(workspaceId!, signal), enabled: Boolean(workspaceId), staleTime: 30 * 1000, + placeholderData: keepPreviousData, }) } diff --git a/apps/sim/hooks/queries/schedules.ts b/apps/sim/hooks/queries/schedules.ts index a2514874f22..684b294086e 100644 --- a/apps/sim/hooks/queries/schedules.ts +++ b/apps/sim/hooks/queries/schedules.ts @@ -1,5 +1,5 @@ import { createLogger } from '@sim/logger' -import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' +import { keepPreviousData, useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { parseCronToHumanReadable } from '@/lib/workflows/schedules/utils' import { deploymentKeys } from '@/hooks/queries/deployments' @@ -96,6 +96,7 @@ export function useWorkspaceSchedules(workspaceId?: string) { }, enabled: Boolean(workspaceId), staleTime: 30 * 1000, + placeholderData: keepPreviousData, }) } @@ -113,6 +114,7 @@ export function useScheduleQuery( enabled: !!workflowId && !!blockId && (options?.enabled ?? true), staleTime: 30 * 1000, // 30 seconds retry: false, + placeholderData: keepPreviousData, }) } diff --git a/apps/sim/hooks/queries/workflows.ts b/apps/sim/hooks/queries/workflows.ts index cc9e7b0b696..16ceb2c9822 100644 --- a/apps/sim/hooks/queries/workflows.ts +++ b/apps/sim/hooks/queries/workflows.ts @@ -60,6 +60,7 @@ export function useWorkflowState(workflowId: string | undefined) { queryFn: ({ signal }) => fetchWorkflowState(workflowId!, signal), enabled: Boolean(workflowId), staleTime: 30 * 1000, // 30 seconds + placeholderData: keepPreviousData, }) } diff --git a/apps/sim/lib/auth/auth.ts b/apps/sim/lib/auth/auth.ts index 02c3c48cfa4..bd514245ea6 100644 --- a/apps/sim/lib/auth/auth.ts +++ b/apps/sim/lib/auth/auth.ts @@ -1,3 +1,4 @@ +import { cache } from 'react' import { sso } from '@better-auth/sso' import { stripe } from '@better-auth/stripe' import { db } from '@sim/db' @@ -3023,7 +3024,7 @@ export const auth = betterAuth({ }, }) -export async function getSession() { +async function getSessionImpl() { if (isAuthDisabled) { await ensureAnonymousUserExists() return createAnonymousSession() @@ -3035,5 +3036,7 @@ export async function getSession() { }) } +export const getSession = cache(getSessionImpl) + export const signIn = auth.api.signInEmail export const signUp = auth.api.signUpEmail diff --git a/apps/sim/lib/blog/mdx.tsx b/apps/sim/lib/blog/mdx.tsx index 67302696f58..db460c93782 100644 --- a/apps/sim/lib/blog/mdx.tsx +++ b/apps/sim/lib/blog/mdx.tsx @@ -13,7 +13,6 @@ export const mdxComponents: MDXRemoteProps['components'] = { className={clsx('h-auto w-full rounded-lg', props.className)} sizes='(max-width: 768px) 100vw, 800px' loading='lazy' - unoptimized /> ), h2: ({ children, className, ...props }: any) => ( diff --git a/apps/sim/lib/og/capture-preview.ts b/apps/sim/lib/og/capture-preview.ts index 7f49019c0ff..a15b597517b 100644 --- a/apps/sim/lib/og/capture-preview.ts +++ b/apps/sim/lib/og/capture-preview.ts @@ -1,5 +1,4 @@ import { createLogger } from '@sim/logger' -import { toPng } from 'html-to-image' const logger = createLogger('OGCapturePreview') @@ -30,6 +29,7 @@ export async function captureWorkflowPreview( try { logger.info(`Capturing workflow preview for OG image (attempt ${attempt}/${retries})`) + const { toPng } = await import('html-to-image') const dataUrl = await toPng(element, { width: OG_IMAGE_WIDTH, height: OG_IMAGE_HEIGHT, diff --git a/apps/sim/lib/workflows/operations/import-export.ts b/apps/sim/lib/workflows/operations/import-export.ts index 8fbd59fb530..164e9ff89ae 100644 --- a/apps/sim/lib/workflows/operations/import-export.ts +++ b/apps/sim/lib/workflows/operations/import-export.ts @@ -1,5 +1,4 @@ import { createLogger } from '@sim/logger' -import JSZip from 'jszip' import { type ExportWorkflowState, sanitizeForExport, @@ -9,6 +8,11 @@ import type { Variable, WorkflowState } from '@/stores/workflows/workflow/types' const logger = createLogger('WorkflowImportExport') +async function getJSZip() { + const { default: JSZip } = await import('jszip') + return JSZip +} + export interface WorkflowExportData { workflow: { id: string @@ -138,6 +142,7 @@ export function exportWorkflowToJson(workflowData: WorkflowExportData): string { * Workflows are placed at the root level (no folder structure). */ export async function exportWorkflowsToZip(workflows: WorkflowExportData[]): Promise { + const JSZip = await getJSZip() const zip = new JSZip() const seenFilenames = new Set() @@ -182,6 +187,7 @@ export async function exportWorkspaceToZip( folders: FolderExportData[], workspaceColor?: string ): Promise { + const JSZip = await getJSZip() const zip = new JSZip() const foldersMap = new Map(folders.map((f) => [f.id, f])) @@ -244,6 +250,7 @@ export async function exportFolderToZip( workflows: WorkflowExportData[], folders: FolderExportData[] ): Promise { + const JSZip = await getJSZip() const zip = new JSZip() const foldersMap = new Map(folders.map((f) => [f.id, f])) @@ -317,6 +324,7 @@ function extractSortOrder(content: string): number | undefined { export async function extractWorkflowsFromZip( zipFile: File ): Promise<{ workflows: ImportedWorkflow[]; metadata?: WorkspaceImportMetadata }> { + const JSZip = await getJSZip() const zip = await JSZip.loadAsync(await zipFile.arrayBuffer()) const workflows: ImportedWorkflow[] = [] let metadata: WorkspaceImportMetadata | undefined diff --git a/apps/sim/next.config.ts b/apps/sim/next.config.ts index ede66f5987f..139dd979775 100644 --- a/apps/sim/next.config.ts +++ b/apps/sim/next.config.ts @@ -97,6 +97,25 @@ const nextConfig: NextConfig = { turbopackSourceMaps: false, turbopackFileSystemCacheForDev: true, preloadEntriesOnStart: false, + optimizePackageImports: [ + 'lucide-react', + 'lodash', + 'framer-motion', + 'reactflow', + '@radix-ui/react-dialog', + '@radix-ui/react-dropdown-menu', + '@radix-ui/react-popover', + '@radix-ui/react-select', + '@radix-ui/react-tabs', + '@radix-ui/react-tooltip', + '@radix-ui/react-accordion', + '@radix-ui/react-checkbox', + '@radix-ui/react-switch', + '@radix-ui/react-slider', + 'react-markdown', + 'zod', + 'date-fns', + ], }, ...(isDev && { allowedDevOrigins: [ From 0be1721430f4a4d080128af5caabb0894ec78ec6 Mon Sep 17 00:00:00 2001 From: Adithya Krishna Date: Tue, 24 Mar 2026 22:38:57 +0530 Subject: [PATCH 2/4] chore: fix review changes --- apps/sim/hooks/queries/a2a/agents.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/apps/sim/hooks/queries/a2a/agents.ts b/apps/sim/hooks/queries/a2a/agents.ts index b0d9c850e49..b317c2e6b38 100644 --- a/apps/sim/hooks/queries/a2a/agents.ts +++ b/apps/sim/hooks/queries/a2a/agents.ts @@ -40,8 +40,9 @@ export const a2aAgentKeys = { list: (workspaceId: string) => [...a2aAgentKeys.lists(), workspaceId] as const, details: () => [...a2aAgentKeys.all, 'detail'] as const, detail: (agentId: string) => [...a2aAgentKeys.details(), agentId] as const, + byWorkflows: () => [...a2aAgentKeys.all, 'byWorkflow'] as const, byWorkflow: (workspaceId: string, workflowId: string) => - [...a2aAgentKeys.all, 'byWorkflow', workspaceId, workflowId] as const, + [...a2aAgentKeys.byWorkflows(), workspaceId, workflowId] as const, } /** @@ -153,6 +154,9 @@ export function useCreateA2AAgent() { queryClient.invalidateQueries({ queryKey: a2aAgentKeys.lists(), }) + queryClient.invalidateQueries({ + queryKey: a2aAgentKeys.byWorkflows(), + }) }, }) } @@ -205,6 +209,9 @@ export function useUpdateA2AAgent() { queryClient.invalidateQueries({ queryKey: a2aAgentKeys.detail(variables.agentId), }) + queryClient.invalidateQueries({ + queryKey: a2aAgentKeys.byWorkflows(), + }) }, }) } @@ -237,6 +244,9 @@ export function useDeleteA2AAgent() { queryClient.invalidateQueries({ queryKey: a2aAgentKeys.detail(variables.agentId), }) + queryClient.invalidateQueries({ + queryKey: a2aAgentKeys.byWorkflows(), + }) }, }) } @@ -284,6 +294,9 @@ export function usePublishA2AAgent() { queryClient.invalidateQueries({ queryKey: a2aAgentKeys.detail(variables.agentId), }) + queryClient.invalidateQueries({ + queryKey: a2aAgentKeys.byWorkflows(), + }) }, }) } From db4bb06ddd467e0a19d58d6accc8ccf84978fd45 Mon Sep 17 00:00:00 2001 From: Adithya Krishna Date: Tue, 24 Mar 2026 22:53:32 +0530 Subject: [PATCH 3/4] chore: fix review changes --- apps/sim/hooks/queries/kb/knowledge.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/sim/hooks/queries/kb/knowledge.ts b/apps/sim/hooks/queries/kb/knowledge.ts index 160f3263112..53b938690d5 100644 --- a/apps/sim/hooks/queries/kb/knowledge.ts +++ b/apps/sim/hooks/queries/kb/knowledge.ts @@ -815,10 +815,13 @@ export function useDeleteKnowledgeBase(workspaceId?: string) { return useMutation({ mutationFn: deleteKnowledgeBase, - onSuccess: () => { + onSuccess: (_data, variables) => { queryClient.invalidateQueries({ queryKey: knowledgeKeys.lists(), }) + queryClient.invalidateQueries({ + queryKey: knowledgeKeys.detail(variables.knowledgeBaseId), + }) }, }) } From b99cecee81a6c0a9e4e984a226a5c9fb3cd8f016 Mon Sep 17 00:00:00 2001 From: Adithya Krishna Date: Tue, 24 Mar 2026 23:08:48 +0530 Subject: [PATCH 4/4] chore: fix review changes --- .../components/variables/variables.tsx | 10 ++++++++-- apps/sim/hooks/queries/credential-sets.ts | 3 +++ apps/sim/hooks/queries/schedules.ts | 3 +++ apps/sim/hooks/queries/tasks.ts | 14 ++++++++++---- apps/sim/hooks/queries/workspace.ts | 3 ++- 5 files changed, 26 insertions(+), 7 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/variables/variables.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/variables/variables.tsx index 839f4c69104..d20be4837be 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/variables/variables.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/variables/variables.tsx @@ -108,12 +108,18 @@ export function Variables() { })) ) - const getVariablesByWorkflowId = usePanelVariablesStore((s) => s.getVariablesByWorkflowId) + const variables = usePanelVariablesStore((s) => s.variables) const { collaborativeUpdateVariable, collaborativeAddVariable, collaborativeDeleteVariable } = useCollaborativeWorkflow() - const workflowVariables = activeWorkflowId ? getVariablesByWorkflowId(activeWorkflowId) : [] + const workflowVariables = useMemo( + () => + activeWorkflowId + ? Object.values(variables).filter((v) => v.workflowId === activeWorkflowId) + : [], + [variables, activeWorkflowId] + ) const actualPosition = useMemo( () => getVariablesPosition(position, width, height), diff --git a/apps/sim/hooks/queries/credential-sets.ts b/apps/sim/hooks/queries/credential-sets.ts index 49cace670bf..5c639fc16c8 100644 --- a/apps/sim/hooks/queries/credential-sets.ts +++ b/apps/sim/hooks/queries/credential-sets.ts @@ -318,6 +318,9 @@ export function useDeleteCredentialSet() { queryKey: credentialSetKeys.list(variables.organizationId), }) queryClient.invalidateQueries({ queryKey: credentialSetKeys.memberships() }) + queryClient.invalidateQueries({ + queryKey: credentialSetKeys.detail(variables.credentialSetId), + }) }, }) } diff --git a/apps/sim/hooks/queries/schedules.ts b/apps/sim/hooks/queries/schedules.ts index 684b294086e..265a36aca05 100644 --- a/apps/sim/hooks/queries/schedules.ts +++ b/apps/sim/hooks/queries/schedules.ts @@ -236,6 +236,7 @@ export function useDisableSchedule() { }, onSuccess: ({ workspaceId }) => { queryClient.invalidateQueries({ queryKey: scheduleKeys.list(workspaceId) }) + queryClient.invalidateQueries({ queryKey: scheduleKeys.details() }) }, onError: (error) => { logger.error('Failed to disable schedule', { error }) @@ -270,6 +271,7 @@ export function useDeleteSchedule() { }, onSuccess: ({ workspaceId }) => { queryClient.invalidateQueries({ queryKey: scheduleKeys.list(workspaceId) }) + queryClient.invalidateQueries({ queryKey: scheduleKeys.details() }) }, onError: (error) => { logger.error('Failed to delete schedule', { error }) @@ -313,6 +315,7 @@ export function useUpdateSchedule() { }, onSuccess: ({ workspaceId }) => { queryClient.invalidateQueries({ queryKey: scheduleKeys.list(workspaceId) }) + queryClient.invalidateQueries({ queryKey: scheduleKeys.details() }) }, onError: (error) => { logger.error('Failed to update schedule', { error }) diff --git a/apps/sim/hooks/queries/tasks.ts b/apps/sim/hooks/queries/tasks.ts index 184859f2526..8bc3c10c536 100644 --- a/apps/sim/hooks/queries/tasks.ts +++ b/apps/sim/hooks/queries/tasks.ts @@ -79,7 +79,8 @@ export const taskKeys = { all: ['tasks'] as const, lists: () => [...taskKeys.all, 'list'] as const, list: (workspaceId: string | undefined) => [...taskKeys.lists(), workspaceId ?? ''] as const, - detail: (chatId: string | undefined) => [...taskKeys.all, 'detail', chatId ?? ''] as const, + details: () => [...taskKeys.all, 'detail'] as const, + detail: (chatId: string | undefined) => [...taskKeys.details(), chatId ?? ''] as const, } interface TaskResponse { @@ -177,8 +178,9 @@ export function useDeleteTask(workspaceId?: string) { const queryClient = useQueryClient() return useMutation({ mutationFn: deleteTask, - onSettled: () => { + onSettled: (_data, _error, chatId) => { queryClient.invalidateQueries({ queryKey: taskKeys.list(workspaceId) }) + queryClient.removeQueries({ queryKey: taskKeys.detail(chatId) }) }, }) } @@ -192,8 +194,11 @@ export function useDeleteTasks(workspaceId?: string) { mutationFn: async (chatIds: string[]) => { await Promise.all(chatIds.map(deleteTask)) }, - onSettled: () => { + onSettled: (_data, _error, chatIds) => { queryClient.invalidateQueries({ queryKey: taskKeys.list(workspaceId) }) + for (const chatId of chatIds) { + queryClient.removeQueries({ queryKey: taskKeys.detail(chatId) }) + } }, }) } @@ -232,8 +237,9 @@ export function useRenameTask(workspaceId?: string) { queryClient.setQueryData(taskKeys.list(workspaceId), context.previousTasks) } }, - onSettled: () => { + onSettled: (_data, _error, variables) => { queryClient.invalidateQueries({ queryKey: taskKeys.list(workspaceId) }) + queryClient.invalidateQueries({ queryKey: taskKeys.detail(variables.chatId) }) }, }) } diff --git a/apps/sim/hooks/queries/workspace.ts b/apps/sim/hooks/queries/workspace.ts index b4722aca3af..b223ca18678 100644 --- a/apps/sim/hooks/queries/workspace.ts +++ b/apps/sim/hooks/queries/workspace.ts @@ -120,8 +120,9 @@ export function useDeleteWorkspace() { return response.json() }, - onSuccess: () => { + onSuccess: (_data, variables) => { queryClient.invalidateQueries({ queryKey: workspaceKeys.lists() }) + queryClient.invalidateQueries({ queryKey: workspaceKeys.detail(variables.workspaceId) }) }, }) }