Skip to content

Commit b57636e

Browse files
committed
finalized task navigation
1 parent 38c9ecd commit b57636e

9 files changed

Lines changed: 35 additions & 121 deletions

File tree

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { useEffect } from 'react'
44
import { createLogger } from '@sim/logger'
5-
import { AlertTriangle, RefreshCw } from 'lucide-react'
5+
import { RefreshCw } from 'lucide-react'
66
import { Button } from '@/components/emcn'
77

88
const logger = createLogger('WorkspaceError')
@@ -20,9 +20,6 @@ export default function WorkspaceError({ error, reset }: WorkspaceErrorProps) {
2020
return (
2121
<div className='flex h-full flex-1 items-center justify-center bg-white dark:bg-[var(--bg)]'>
2222
<div className='flex flex-col items-center gap-[16px] text-center'>
23-
<div className='flex h-[48px] w-[48px] items-center justify-center rounded-full bg-[var(--surface-4)]'>
24-
<AlertTriangle className='h-[24px] w-[24px] text-[var(--text-error)]' />
25-
</div>
2623
<div className='flex flex-col gap-[8px]'>
2724
<h2 className='font-semibold text-[16px] text-[var(--text-primary)]'>
2825
Something went wrong

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

Lines changed: 8 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,51 +2,28 @@
22

33
import { useCallback, useState } from 'react'
44
import { Loader2 } from 'lucide-react'
5-
import { useParams, useRouter } from 'next/navigation'
6-
import { MOTHERSHIP_CHAT_API_PATH } from '@/lib/copilot/constants'
5+
import { useParams } from 'next/navigation'
76
import { MessageContent, UserInput } from './components'
87
import { useChat } from './hooks'
98

109
interface HomeProps {
1110
chatId?: string
12-
streamId?: string
13-
initialMessage?: string
1411
}
1512

16-
export function Home({ chatId, streamId, initialMessage }: HomeProps = {}) {
13+
export function Home({ chatId }: HomeProps = {}) {
1714
const { workspaceId } = useParams<{ workspaceId: string }>()
18-
const router = useRouter()
1915
const [inputValue, setInputValue] = useState('')
20-
const { messages, isSending, currentChatId, sendMessage, stopGeneration, chatBottomRef } =
21-
useChat(workspaceId, chatId, streamId, initialMessage)
16+
const { messages, isSending, sendMessage, stopGeneration, chatBottomRef } = useChat(
17+
workspaceId,
18+
chatId
19+
)
2220

2321
const handleSubmit = useCallback(() => {
2422
const trimmed = inputValue.trim()
2523
if (!trimmed) return
2624
setInputValue('')
27-
28-
if (chatId || currentChatId) {
29-
sendMessage(trimmed)
30-
return
31-
}
32-
33-
const userMessageId = crypto.randomUUID()
34-
35-
fetch(MOTHERSHIP_CHAT_API_PATH, {
36-
method: 'POST',
37-
headers: { 'Content-Type': 'application/json' },
38-
body: JSON.stringify({
39-
message: trimmed,
40-
workspaceId,
41-
userMessageId,
42-
createNewChat: true,
43-
}),
44-
}).catch(() => {})
45-
46-
router.push(
47-
`/workspace/${workspaceId}/task/new?sid=${userMessageId}&m=${encodeURIComponent(trimmed)}`
48-
)
49-
}, [inputValue, chatId, currentChatId, sendMessage, workspaceId, router])
25+
sendMessage(trimmed)
26+
}, [inputValue, sendMessage])
5027

5128
const hasMessages = messages.length > 0
5229

apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts

Lines changed: 18 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { useCallback, useEffect, useRef, useState } from 'react'
22
import { useQueryClient } from '@tanstack/react-query'
3+
import { usePathname } from 'next/navigation'
34
import { MOTHERSHIP_CHAT_API_PATH } from '@/lib/copilot/constants'
45
import {
56
type TaskStoredContentBlock,
@@ -21,7 +22,6 @@ export interface UseChatReturn {
2122
messages: ChatMessage[]
2223
isSending: boolean
2324
error: string | null
24-
currentChatId: string | undefined
2525
sendMessage: (message: string) => Promise<void>
2626
stopGeneration: () => void
2727
chatBottomRef: React.RefObject<HTMLDivElement | null>
@@ -68,30 +68,40 @@ function getPayloadData(payload: SSEPayload): SSEPayloadData | undefined {
6868
return typeof payload.data === 'object' ? payload.data : undefined
6969
}
7070

71-
export function useChat(
72-
workspaceId: string,
73-
initialChatId?: string,
74-
initialStreamId?: string,
75-
initialMessage?: string
76-
): UseChatReturn {
71+
export function useChat(workspaceId: string, initialChatId?: string): UseChatReturn {
72+
const pathname = usePathname()
7773
const queryClient = useQueryClient()
7874
const [messages, setMessages] = useState<ChatMessage[]>([])
79-
const [isSending, setIsSending] = useState(Boolean(initialStreamId))
75+
const [isSending, setIsSending] = useState(false)
8076
const [error, setError] = useState<string | null>(null)
8177
const abortControllerRef = useRef<AbortController | null>(null)
8278
const chatIdRef = useRef<string | undefined>(initialChatId)
8379
const chatBottomRef = useRef<HTMLDivElement>(null)
8480
const appliedChatIdRef = useRef<string | undefined>(undefined)
8581

82+
const isHomePage = pathname.endsWith('/home')
83+
8684
const { data: chatHistory } = useChatHistory(initialChatId)
8785

8886
useEffect(() => {
8987
chatIdRef.current = initialChatId
9088
appliedChatIdRef.current = undefined
9189
setMessages([])
9290
setError(null)
91+
setIsSending(false)
9392
}, [initialChatId])
9493

94+
useEffect(() => {
95+
if (!isHomePage || !chatIdRef.current) return
96+
chatIdRef.current = undefined
97+
appliedChatIdRef.current = undefined
98+
abortControllerRef.current?.abort()
99+
abortControllerRef.current = null
100+
setMessages([])
101+
setError(null)
102+
setIsSending(false)
103+
}, [isHomePage])
104+
95105
useEffect(() => {
96106
if (!chatHistory || appliedChatIdRef.current === chatHistory.id) return
97107
appliedChatIdRef.current = chatHistory.id
@@ -288,47 +298,6 @@ export function useChat(
288298
}
289299
}, [chatHistory?.activeStreamId, processSSEStream, finalize])
290300

291-
useEffect(() => {
292-
if (!initialStreamId) return
293-
294-
const abortController = new AbortController()
295-
abortControllerRef.current = abortController
296-
297-
const userMessageId = initialStreamId
298-
const assistantId = crypto.randomUUID()
299-
300-
setMessages([
301-
{ id: userMessageId, role: 'user', content: initialMessage || '' },
302-
{ id: assistantId, role: 'assistant', content: '', contentBlocks: [] },
303-
])
304-
305-
const connectToStream = async () => {
306-
try {
307-
const response = await fetch(
308-
`/api/copilot/chat/stream?streamId=${initialStreamId}&from=0`,
309-
{ signal: abortController.signal }
310-
)
311-
312-
if (!response.ok || !response.body) {
313-
throw new Error('Failed to connect to stream')
314-
}
315-
316-
await processSSEStream(response.body.getReader(), assistantId)
317-
} catch (err) {
318-
if (err instanceof Error && err.name === 'AbortError') return
319-
setError(err instanceof Error ? err.message : 'Failed to connect to stream')
320-
} finally {
321-
finalize()
322-
}
323-
}
324-
325-
connectToStream()
326-
327-
return () => {
328-
abortController.abort()
329-
}
330-
}, [initialStreamId, initialMessage, workspaceId, processSSEStream, finalize])
331-
332301
const sendMessage = useCallback(
333302
async (message: string) => {
334303
if (!message.trim() || !workspaceId) return
@@ -389,7 +358,6 @@ export function useChat(
389358
messages,
390359
isSending,
391360
error,
392-
currentChatId: chatIdRef.current,
393361
sendMessage,
394362
stopGeneration,
395363
chatBottomRef,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@ export default async function HomePage({ params }: HomePageProps) {
2222
redirect('/')
2323
}
2424

25-
return <Home />
25+
return <Home key='home' />
2626
}

apps/sim/app/workspace/[workspaceId]/tables/[tableId]/error.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { useEffect } from 'react'
44
import { createLogger } from '@sim/logger'
5-
import { AlertTriangle, ArrowLeft, RefreshCw } from 'lucide-react'
5+
import { ArrowLeft, RefreshCw } from 'lucide-react'
66
import { useParams, useRouter } from 'next/navigation'
77
import { Button } from '@/components/emcn'
88

@@ -38,9 +38,6 @@ export default function TableViewerError({ error, reset }: TableViewerErrorProps
3838
{/* Error Content */}
3939
<div className='flex flex-1 items-center justify-center'>
4040
<div className='flex flex-col items-center gap-[16px] text-center'>
41-
<div className='flex h-[48px] w-[48px] items-center justify-center rounded-full bg-[var(--surface-4)]'>
42-
<AlertTriangle className='h-[24px] w-[24px] text-[var(--text-error)]' />
43-
</div>
4441
<div className='flex flex-col gap-[8px]'>
4542
<h2 className='font-semibold text-[16px] text-[var(--text-primary)]'>
4643
Failed to load table

apps/sim/app/workspace/[workspaceId]/tables/error.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { useEffect } from 'react'
44
import { createLogger } from '@sim/logger'
5-
import { AlertTriangle, RefreshCw } from 'lucide-react'
5+
import { RefreshCw } from 'lucide-react'
66
import { Button } from '@/components/emcn'
77

88
const logger = createLogger('TablesError')
@@ -20,9 +20,6 @@ export default function TablesError({ error, reset }: TablesErrorProps) {
2020
return (
2121
<div className='flex h-full flex-1 items-center justify-center bg-white dark:bg-[var(--bg)]'>
2222
<div className='flex flex-col items-center gap-[16px] text-center'>
23-
<div className='flex h-[48px] w-[48px] items-center justify-center rounded-full bg-[var(--surface-4)]'>
24-
<AlertTriangle className='h-[24px] w-[24px] text-[var(--text-error)]' />
25-
</div>
2623
<div className='flex flex-col gap-[8px]'>
2724
<h2 className='font-semibold text-[16px] text-[var(--text-primary)]'>
2825
Failed to load tables

apps/sim/app/workspace/[workspaceId]/task/[taskId]/loading.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,8 @@ export default function TaskLoading() {
44
return (
55
<div className='flex h-full bg-[#FCFCFC] dark:bg-[var(--surface-2)]'>
66
<div className='flex h-full min-w-0 flex-1 flex-col'>
7-
<div className='min-h-0 flex-1 overflow-y-auto px-[16px] py-[16px]'>
8-
<div className='mx-auto max-w-[768px] space-y-[16px]'>
9-
<div className='flex items-center gap-[8px] py-[8px] text-[13px] text-[var(--text-tertiary)]'>
10-
<Loader2 className='h-[14px] w-[14px] animate-spin' />
11-
Thinking...
12-
</div>
13-
</div>
7+
<div className='flex min-h-0 flex-1 items-center justify-center'>
8+
<Loader2 className='h-[20px] w-[20px] animate-spin text-[var(--text-tertiary)]' />
149
</div>
1510
</div>
1611
</div>

apps/sim/app/workspace/[workspaceId]/task/[taskId]/page.tsx

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,9 @@ interface TaskPageProps {
55
workspaceId: string
66
taskId: string
77
}>
8-
searchParams: Promise<{
9-
sid?: string
10-
m?: string
11-
}>
128
}
139

14-
export default async function TaskPage({ params, searchParams }: TaskPageProps) {
10+
export default async function TaskPage({ params }: TaskPageProps) {
1511
const { taskId } = await params
16-
17-
if (taskId === 'new') {
18-
const { sid, m } = await searchParams
19-
return <Home streamId={sid} initialMessage={m} />
20-
}
21-
22-
return <Home chatId={taskId} />
12+
return <Home key={taskId} chatId={taskId} />
2313
}

apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -362,15 +362,13 @@ export const Sidebar = memo(function Sidebar() {
362362
[fetchedTasks, workspaceId]
363363
)
364364

365-
const [isScrolledFromTop, setIsScrolledFromTop] = useState(false)
366365
const [hasOverflowBottom, setHasOverflowBottom] = useState(false)
367366

368367
useEffect(() => {
369368
const container = scrollContainerRef.current
370369
if (!container) return
371370

372371
const updateScrollState = () => {
373-
setIsScrolledFromTop(container.scrollTop > 0)
374372
setHasOverflowBottom(
375373
container.scrollHeight > container.scrollTop + container.clientHeight + 1
376374
)
@@ -654,12 +652,7 @@ export const Sidebar = memo(function Sidebar() {
654652
</div>
655653

656654
{/* Workspace */}
657-
<div
658-
className={cn(
659-
'mt-[14px] flex flex-shrink-0 flex-col border-b pb-[4px] transition-colors duration-150',
660-
!isScrolledFromTop && 'border-transparent'
661-
)}
662-
>
655+
<div className='mt-[14px] flex flex-shrink-0 flex-col pb-[5px]'>
663656
<div className='px-[16px] pb-[6px]'>
664657
<div className='font-base text-[var(--text-tertiary)] text-small'>Workspace</div>
665658
</div>

0 commit comments

Comments
 (0)