mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-21 13:00:04 +08:00
chore: optimize imports and useShallow (#3740)
* chore: fix conflicts * chore: fix review changes * chore: fix review changes * chore: fix review changes
This commit is contained in:
@@ -60,7 +60,6 @@ export default async function Page({ params }: { params: Promise<{ slug: string
|
||||
sizes='(max-width: 768px) 100vw, 450px'
|
||||
priority
|
||||
itemProp='image'
|
||||
unoptimized
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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
|
||||
/>
|
||||
<div className='p-3'>
|
||||
<div className='mb-1 text-[#999] text-xs'>
|
||||
|
||||
@@ -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
|
||||
/>
|
||||
<div className='p-3'>
|
||||
<div className='mb-1 text-[#999] text-xs'>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
|
||||
@@ -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({
|
||||
<div className='mt-[10px] flex items-center justify-between'>
|
||||
<div className='flex min-w-0 items-center gap-[8px]'>
|
||||
{authorImageUrl ? (
|
||||
<div className='h-[20px] w-[20px] flex-shrink-0 overflow-hidden rounded-full'>
|
||||
<img src={authorImageUrl} alt={author} className='h-full w-full object-cover' />
|
||||
</div>
|
||||
<Image
|
||||
src={authorImageUrl}
|
||||
alt={author}
|
||||
width={20}
|
||||
height={20}
|
||||
className='flex-shrink-0 rounded-full object-cover'
|
||||
unoptimized
|
||||
/>
|
||||
) : (
|
||||
<div className='flex h-[20px] w-[20px] flex-shrink-0 items-center justify-center rounded-full bg-[var(--surface-7)]'>
|
||||
<User className='h-[12px] w-[12px] text-[var(--text-muted)]' />
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ function WorkflowsListInner({
|
||||
searchQuery: string
|
||||
segmentDurationMs: number
|
||||
}) {
|
||||
const { workflows } = useWorkflowRegistry()
|
||||
const workflows = useWorkflowRegistry((s) => s.workflows)
|
||||
|
||||
return (
|
||||
<div className='flex h-full flex-col overflow-hidden rounded-[6px] bg-[var(--surface-2)] dark:bg-[var(--surface-1)]'>
|
||||
|
||||
@@ -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<Record<string, number>>({})
|
||||
const lastAnchorIndicesRef = useRef<Record<string, number>>({})
|
||||
|
||||
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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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({
|
||||
<div className='mt-[10px] flex items-center justify-between'>
|
||||
<div className='flex min-w-0 flex-1 items-center gap-[6px]'>
|
||||
{authorImageUrl ? (
|
||||
<div className='h-[20px] w-[20px] flex-shrink-0 overflow-hidden rounded-full'>
|
||||
<img src={authorImageUrl} alt={author} className='h-full w-full object-cover' />
|
||||
</div>
|
||||
<Image
|
||||
src={authorImageUrl}
|
||||
alt={author}
|
||||
width={20}
|
||||
height={20}
|
||||
className='flex-shrink-0 rounded-full object-cover'
|
||||
unoptimized
|
||||
/>
|
||||
) : (
|
||||
<div className='flex h-[20px] w-[20px] flex-shrink-0 items-center justify-center rounded-full bg-[var(--surface-7)]'>
|
||||
<User className='h-[12px] w-[12px] text-[var(--text-tertiary)]' />
|
||||
|
||||
@@ -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)
|
||||
|
||||
+9
-1
@@ -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
|
||||
)
|
||||
|
||||
+1
-2
@@ -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
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
+1
-1
@@ -85,7 +85,7 @@ export function VariablesInput({
|
||||
const params = useParams()
|
||||
const workflowId = params.workflowId as string
|
||||
const [storeValue, setStoreValue] = useSubBlockValue<VariableAssignment[]>(blockId, subBlockId)
|
||||
const { variables: workflowVariables } = useVariablesStore()
|
||||
const workflowVariables = useVariablesStore((s) => s.variables)
|
||||
const accessiblePrefixes = useAccessibleReferencePrefixes(blockId)
|
||||
|
||||
const [showTags, setShowTags] = useState(false)
|
||||
|
||||
+7
-1
@@ -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<number>(0)
|
||||
|
||||
+8
-1
@@ -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
|
||||
|
||||
+21
-4
@@ -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,17 +93,33 @@ 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()
|
||||
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()
|
||||
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),
|
||||
|
||||
+4
-1
@@ -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()
|
||||
|
||||
+20
-4
@@ -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)
|
||||
|
||||
+9
-1
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+10
-1
@@ -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.
|
||||
|
||||
+8
-1
@@ -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
|
||||
|
||||
+9
-1
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
/**
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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', {
|
||||
|
||||
@@ -36,10 +36,13 @@ 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,
|
||||
byWorkflows: () => [...a2aAgentKeys.all, 'byWorkflow'] as const,
|
||||
byWorkflow: (workspaceId: string, workflowId: string) =>
|
||||
[...a2aAgentKeys.all, 'byWorkflow', workspaceId, workflowId] as const,
|
||||
[...a2aAgentKeys.byWorkflows(), workspaceId, workflowId] as const,
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,9 +151,11 @@ 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(),
|
||||
})
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: a2aAgentKeys.byWorkflows(),
|
||||
})
|
||||
},
|
||||
})
|
||||
@@ -197,10 +202,15 @@ export function useUpdateA2AAgent() {
|
||||
|
||||
return useMutation({
|
||||
mutationFn: updateA2AAgent,
|
||||
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),
|
||||
})
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: a2aAgentKeys.byWorkflows(),
|
||||
})
|
||||
},
|
||||
})
|
||||
@@ -227,10 +237,15 @@ 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),
|
||||
})
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: a2aAgentKeys.byWorkflows(),
|
||||
})
|
||||
},
|
||||
})
|
||||
@@ -272,10 +287,15 @@ export function usePublishA2AAgent() {
|
||||
|
||||
return useMutation({
|
||||
mutationFn: publishA2AAgent,
|
||||
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),
|
||||
})
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: a2aAgentKeys.byWorkflows(),
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -316,6 +318,9 @@ export function useDeleteCredentialSet() {
|
||||
queryKey: credentialSetKeys.list(variables.organizationId),
|
||||
})
|
||||
queryClient.invalidateQueries({ queryKey: credentialSetKeys.memberships() })
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: credentialSetKeys.detail(variables.credentialSetId),
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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),
|
||||
})
|
||||
},
|
||||
})
|
||||
@@ -815,9 +815,12 @@ export function useDeleteKnowledgeBase(workspaceId?: string) {
|
||||
|
||||
return useMutation({
|
||||
mutationFn: deleteKnowledgeBase,
|
||||
onSuccess: () => {
|
||||
onSuccess: (_data, variables) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: knowledgeKeys.all,
|
||||
queryKey: knowledgeKeys.lists(),
|
||||
})
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: knowledgeKeys.detail(variables.knowledgeBaseId),
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -234,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 })
|
||||
@@ -268,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 })
|
||||
@@ -311,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 })
|
||||
|
||||
@@ -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) })
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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) })
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) => (
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<Blob> {
|
||||
const JSZip = await getJSZip()
|
||||
const zip = new JSZip()
|
||||
const seenFilenames = new Set<string>()
|
||||
|
||||
@@ -182,6 +187,7 @@ export async function exportWorkspaceToZip(
|
||||
folders: FolderExportData[],
|
||||
workspaceColor?: string
|
||||
): Promise<Blob> {
|
||||
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<Blob> {
|
||||
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
|
||||
|
||||
@@ -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: [
|
||||
|
||||
Reference in New Issue
Block a user