Skip to content

Commit 86deb24

Browse files
committed
improvement(logs): fix Gantt time bounds to walk full span tree; cleanup effects, memos, callbacks, React Query mutations
1 parent 3f0059b commit 86deb24

31 files changed

Lines changed: 409 additions & 422 deletions

File tree

apps/sim/app/(auth)/signup/signup-form.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,7 @@ function SignupFormContent({ githubAvailable, googleAvailable, isProduction }: S
9898
const [showEmailValidationError, setShowEmailValidationError] = useState(false)
9999
const [formError, setFormError] = useState<string | null>(null)
100100
const turnstileRef = useRef<TurnstileInstance>(null)
101-
const [turnstileSiteKey, setTurnstileSiteKey] = useState<string | undefined>()
102-
103-
useEffect(() => {
104-
setTurnstileSiteKey(getEnv('NEXT_PUBLIC_TURNSTILE_SITE_KEY'))
105-
}, [])
101+
const [turnstileSiteKey] = useState(() => getEnv('NEXT_PUBLIC_TURNSTILE_SITE_KEY'))
106102
const rawRedirectUrl = searchParams.get('redirect') || searchParams.get('callbackUrl') || ''
107103
const isValidRedirectUrl = rawRedirectUrl ? validateCallbackUrl(rawRedirectUrl) : false
108104
const invalidCallbackRef = useRef(false)

apps/sim/app/(landing)/components/auth-modal/auth-modal.tsx

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client'
22

3-
import { useCallback, useEffect, useMemo, useState } from 'react'
3+
import { useEffect, useMemo, useState } from 'react'
44
import { createLogger } from '@sim/logger'
55
import { Loader2, X } from 'lucide-react'
66
import Image from 'next/image'
@@ -88,24 +88,21 @@ export function AuthModal({ children, defaultView = 'login', source }: AuthModal
8888
}
8989
}, [open, providerStatus, hasModalContent, defaultView, router, view])
9090

91-
const handleOpenChange = useCallback(
92-
(nextOpen: boolean) => {
93-
if (nextOpen && providerStatus && !hasModalContent) {
94-
router.push(defaultView === 'login' ? '/login' : '/signup')
95-
return
96-
}
97-
setOpen(nextOpen)
98-
if (nextOpen) {
99-
const initialView =
100-
defaultView === 'signup' && providerStatus?.registrationDisabled ? 'login' : defaultView
101-
setView(initialView)
102-
captureClientEvent('auth_modal_opened', { view: initialView, source })
103-
}
104-
},
105-
[defaultView, hasModalContent, providerStatus, router, source]
106-
)
91+
function handleOpenChange(nextOpen: boolean) {
92+
if (nextOpen && providerStatus && !hasModalContent) {
93+
router.push(defaultView === 'login' ? '/login' : '/signup')
94+
return
95+
}
96+
setOpen(nextOpen)
97+
if (nextOpen) {
98+
const initialView =
99+
defaultView === 'signup' && providerStatus?.registrationDisabled ? 'login' : defaultView
100+
setView(initialView)
101+
captureClientEvent('auth_modal_opened', { view: initialView, source })
102+
}
103+
}
107104

108-
const handleSocialLogin = useCallback(async (provider: 'github' | 'google') => {
105+
async function handleSocialLogin(provider: 'github' | 'google') {
109106
setSocialLoading(provider)
110107
try {
111108
await client.signIn.social({ provider, callbackURL: '/workspace' })
@@ -114,17 +111,17 @@ export function AuthModal({ children, defaultView = 'login', source }: AuthModal
114111
} finally {
115112
setSocialLoading(null)
116113
}
117-
}, [])
114+
}
118115

119-
const handleSSOLogin = useCallback(() => {
116+
function handleSSOLogin() {
120117
setOpen(false)
121118
router.push('/sso')
122-
}, [router])
119+
}
123120

124-
const handleEmailContinue = useCallback(() => {
121+
function handleEmailContinue() {
125122
setOpen(false)
126123
router.push(view === 'login' ? '/login' : '/signup')
127-
}, [router, view])
124+
}
128125

129126
return (
130127
<Modal open={open} onOpenChange={handleOpenChange}>

apps/sim/app/(landing)/components/contact/contact-form.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client'
22

3-
import { useEffect, useRef, useState } from 'react'
3+
import { useRef, useState } from 'react'
44
import { Turnstile, type TurnstileInstance } from '@marsidev/react-turnstile'
55
import { toError } from '@sim/utils/errors'
66
import { useMutation } from '@tanstack/react-query'
@@ -99,11 +99,7 @@ export function ContactForm() {
9999
const [isSubmitting, setIsSubmitting] = useState(false)
100100
const [website, setWebsite] = useState('')
101101
const [widgetReady, setWidgetReady] = useState(false)
102-
const [turnstileSiteKey, setTurnstileSiteKey] = useState<string | undefined>()
103-
104-
useEffect(() => {
105-
setTurnstileSiteKey(getEnv('NEXT_PUBLIC_TURNSTILE_SITE_KEY'))
106-
}, [])
102+
const [turnstileSiteKey] = useState(() => getEnv('NEXT_PUBLIC_TURNSTILE_SITE_KEY'))
107103

108104
function updateField<TField extends keyof ContactFormState>(
109105
field: TField,

apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/special-tags.tsx

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client'
22

3-
import { createElement, useEffect, useMemo, useState } from 'react'
3+
import { createElement, useMemo, useState } from 'react'
44
import { useParams } from 'next/navigation'
55
import { ArrowRight, ChevronDown, Expandable, ExpandableContent } from '@/components/emcn'
66
import { cn } from '@/lib/core/utils/cn'
@@ -403,23 +403,19 @@ interface OptionsDisplayProps {
403403

404404
function OptionsDisplay({ data, onSelect }: OptionsDisplayProps) {
405405
const disabled = !onSelect
406-
const [expanded, setExpanded] = useState(!disabled)
406+
const [collapsedByUser, setCollapsedByUser] = useState(false)
407+
// When interactive (not disabled), always expanded. When disabled, the user can toggle.
408+
const expanded = !disabled || !collapsedByUser
407409
const entries = Object.entries(data)
408410

409-
useEffect(() => {
410-
if (!disabled) {
411-
setExpanded(true)
412-
}
413-
}, [disabled])
414-
415411
if (entries.length === 0) return null
416412

417413
return (
418414
<div>
419415
{disabled ? (
420416
<button
421417
type='button'
422-
onClick={() => setExpanded((prev) => !prev)}
418+
onClick={() => setCollapsedByUser((prev) => !prev)}
423419
aria-expanded={expanded}
424420
className='flex items-center gap-2'
425421
>
@@ -527,12 +523,12 @@ export function WorkspaceResourceDisplay({
527523
}
528524
}, [data.id, data.type, files, knowledgeBases, tables, workflows])
529525

530-
const context = useMemo(() => toChatMessageContext(data, resource.title), [data, resource.title])
526+
const context = toChatMessageContext(data, resource.title)
531527

532-
const workflowColor = useMemo(() => {
533-
if (data.type !== 'workflow') return null
534-
return workflows.find((workflow) => workflow.id === data.id)?.color ?? null
535-
}, [data.id, data.type, workflows])
528+
const workflowColor =
529+
data.type === 'workflow'
530+
? (workflows.find((workflow) => workflow.id === data.id)?.color ?? null)
531+
: null
536532

537533
const mentionContent = (
538534
<>

apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/resource-content.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client'
22

3-
import { lazy, memo, Suspense, useEffect, useMemo, useState } from 'react'
3+
import { lazy, memo, Suspense, useMemo, useRef, useState } from 'react'
44
import { createLogger } from '@sim/logger'
55
import { formatDuration } from '@sim/utils/formatting'
66
import { Square } from 'lucide-react'
@@ -248,9 +248,14 @@ export function EmbeddedWorkflowActions({ workspaceId, workflowId }: EmbeddedWor
248248
)
249249
const { usageExceeded } = useUsageLimits()
250250

251-
useEffect(() => {
251+
// Keep the active workflow in the registry up-to-date whenever the embedded
252+
// workflow changes. This is safe during render because the store setter does
253+
// not trigger a synchronous re-render of this component.
254+
const prevWorkflowIdRef = useRef<string | undefined>(undefined)
255+
if (prevWorkflowIdRef.current !== workflowId) {
256+
prevWorkflowIdRef.current = workflowId
252257
setActiveWorkflow(workflowId)
253-
}, [setActiveWorkflow, workflowId])
258+
}
254259

255260
const isRunButtonDisabled =
256261
!isExecuting && !effectivePermissions.canRead && !effectivePermissions.isLoading

apps/sim/app/workspace/[workspaceId]/home/components/user-input/user-input.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -239,16 +239,16 @@ export const UserInput = forwardRef<UserInputHandle, UserInputProps>(function Us
239239
valueRef.current = value
240240
const sttPrefixRef = useRef('')
241241

242-
const handleTranscript = useCallback((text: string) => {
242+
function handleTranscript(text: string) {
243243
const prefix = sttPrefixRef.current
244244
const newVal = prefix ? `${prefix} ${text}` : text
245245
setValue(newVal)
246246
valueRef.current = newVal
247-
}, [])
247+
}
248248

249-
const handleUsageLimitExceeded = useCallback(() => {
249+
function handleUsageLimitExceeded() {
250250
navigateToSettings({ section: 'subscription' })
251-
}, [navigateToSettings])
251+
}
252252

253253
const {
254254
isListening,
@@ -588,7 +588,7 @@ export const UserInput = forwardRef<UserInputHandle, UserInputProps>(function Us
588588
[handleSubmit, mentionTokensWithContext, value, textareaRef]
589589
)
590590

591-
const handleInputChange = useCallback((e: React.ChangeEvent<HTMLTextAreaElement>) => {
591+
function handleInputChange(e: React.ChangeEvent<HTMLTextAreaElement>) {
592592
const newValue = e.target.value
593593
const caret = e.target.selectionStart ?? newValue.length
594594

@@ -608,7 +608,7 @@ export const UserInput = forwardRef<UserInputHandle, UserInputProps>(function Us
608608
}
609609

610610
setValue(newValue)
611-
}, [])
611+
}
612612

613613
const handleSelectAdjust = useCallback(() => {
614614
const textarea = textareaRef.current

apps/sim/app/workspace/[workspaceId]/home/home.tsx

Lines changed: 61 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,11 @@ export function Home({ chatId }: HomeProps = {}) {
125125
setIsResourceCollapsed(true)
126126
}, [clearWidth])
127127

128-
const handleResourceEvent = useCallback(() => {
128+
function handleResourceEvent() {
129129
if (isResourceCollapsedRef.current) {
130130
setIsResourceCollapsed(false)
131131
}
132-
}, [])
132+
}
133133

134134
const {
135135
messages,
@@ -201,34 +201,35 @@ export function Home({ chatId }: HomeProps = {}) {
201201
}
202202
}, [resources, collapseResource])
203203

204-
const handleStopGeneration = useCallback(() => {
204+
function handleStopGeneration() {
205205
captureEvent(posthogRef.current, 'task_generation_aborted', {
206206
workspace_id: workspaceId,
207207
view: 'mothership',
208208
})
209209
void stopGeneration().catch(() => {})
210-
}, [stopGeneration, workspaceId])
211-
212-
const handleSubmit = useCallback(
213-
(text: string, fileAttachments?: FileAttachmentForApi[], contexts?: ChatContext[]) => {
214-
const trimmed = text.trim()
215-
if (!trimmed && !(fileAttachments && fileAttachments.length > 0)) return
216-
217-
captureEvent(posthogRef.current, 'task_message_sent', {
218-
workspace_id: workspaceId,
219-
has_attachments: !!(fileAttachments && fileAttachments.length > 0),
220-
has_contexts: !!(contexts && contexts.length > 0),
221-
is_new_task: !chatId,
222-
})
223-
224-
if (initialViewInputRef.current) {
225-
setIsInputEntering(true)
226-
}
210+
}
227211

228-
sendMessage(trimmed || 'Analyze the attached file(s).', fileAttachments, contexts)
229-
},
230-
[sendMessage, workspaceId, chatId]
231-
)
212+
function handleSubmit(
213+
text: string,
214+
fileAttachments?: FileAttachmentForApi[],
215+
contexts?: ChatContext[]
216+
) {
217+
const trimmed = text.trim()
218+
if (!trimmed && !(fileAttachments && fileAttachments.length > 0)) return
219+
220+
captureEvent(posthogRef.current, 'task_message_sent', {
221+
workspace_id: workspaceId,
222+
has_attachments: !!(fileAttachments && fileAttachments.length > 0),
223+
has_contexts: !!(contexts && contexts.length > 0),
224+
is_new_task: !chatId,
225+
})
226+
227+
if (initialViewInputRef.current) {
228+
setIsInputEntering(true)
229+
}
230+
231+
sendMessage(trimmed || 'Analyze the attached file(s).', fileAttachments, contexts)
232+
}
232233

233234
useEffect(() => {
234235
const handler = (e: Event) => {
@@ -239,55 +240,45 @@ export function Home({ chatId }: HomeProps = {}) {
239240
return () => window.removeEventListener('mothership-send-message', handler)
240241
}, [sendMessage])
241242

242-
const resolveResourceFromContext = useCallback(
243-
(context: ChatContext): { type: MothershipResourceType; id: string } | null => {
244-
switch (context.kind) {
245-
case 'workflow':
246-
case 'current_workflow':
247-
return context.workflowId ? { type: 'workflow', id: context.workflowId } : null
248-
case 'knowledge':
249-
return context.knowledgeId ? { type: 'knowledgebase', id: context.knowledgeId } : null
250-
case 'table':
251-
return context.tableId ? { type: 'table', id: context.tableId } : null
252-
case 'file':
253-
return context.fileId ? { type: 'file', id: context.fileId } : null
254-
default:
255-
return null
256-
}
257-
},
258-
[]
259-
)
243+
function resolveResourceFromContext(
244+
context: ChatContext
245+
): { type: MothershipResourceType; id: string } | null {
246+
switch (context.kind) {
247+
case 'workflow':
248+
case 'current_workflow':
249+
return context.workflowId ? { type: 'workflow', id: context.workflowId } : null
250+
case 'knowledge':
251+
return context.knowledgeId ? { type: 'knowledgebase', id: context.knowledgeId } : null
252+
case 'table':
253+
return context.tableId ? { type: 'table', id: context.tableId } : null
254+
case 'file':
255+
return context.fileId ? { type: 'file', id: context.fileId } : null
256+
default:
257+
return null
258+
}
259+
}
260260

261-
const handleContextAdd = useCallback(
262-
(context: ChatContext) => {
263-
const resolved = resolveResourceFromContext(context)
264-
if (resolved) {
265-
addResource({ ...resolved, title: context.label })
266-
handleResourceEvent()
267-
}
268-
},
269-
[resolveResourceFromContext, addResource, handleResourceEvent]
270-
)
261+
function handleContextAdd(context: ChatContext) {
262+
const resolved = resolveResourceFromContext(context)
263+
if (resolved) {
264+
addResource({ ...resolved, title: context.label })
265+
handleResourceEvent()
266+
}
267+
}
271268

272-
const handleInitialContextRemove = useCallback(
273-
(context: ChatContext) => {
274-
const resolved = resolveResourceFromContext(context)
275-
if (!resolved) return
276-
removeResource(resolved.type, resolved.id)
277-
},
278-
[resolveResourceFromContext, removeResource]
279-
)
269+
function handleInitialContextRemove(context: ChatContext) {
270+
const resolved = resolveResourceFromContext(context)
271+
if (!resolved) return
272+
removeResource(resolved.type, resolved.id)
273+
}
280274

281-
const handleWorkspaceResourceSelect = useCallback(
282-
(resource: MothershipResource) => {
283-
const wasAdded = addResource(resource)
284-
if (!wasAdded) {
285-
setActiveResourceId(resource.id)
286-
}
287-
handleResourceEvent()
288-
},
289-
[addResource, handleResourceEvent, setActiveResourceId]
290-
)
275+
function handleWorkspaceResourceSelect(resource: MothershipResource) {
276+
const wasAdded = addResource(resource)
277+
if (!wasAdded) {
278+
setActiveResourceId(resource.id)
279+
}
280+
handleResourceEvent()
281+
}
291282

292283
const hasMessages = messages.length > 0
293284
const showChatSkeleton = Boolean(chatId) && !hasMessages && isChatHistoryPending

0 commit comments

Comments
 (0)