mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
fix(web): refactor pico chat flow and fix proxied websocket URLs (#1639)
- move chat controller, state, protocol, history, and websocket logic into a dedicated chat feature module - improve chat reconnection, session hydration, and send gating based on actual websocket state - preserve gateway status during transient SSE disconnects and update stop state immediately - generate wss websocket URLs behind HTTPS proxies and add backend tests for forwarded proto handling
This commit is contained in:
@@ -42,7 +42,7 @@ export function ChatComposer({
|
||||
placeholder={t("chat.placeholder")}
|
||||
disabled={!canInput}
|
||||
className={cn(
|
||||
"max-h-[200px] min-h-[60px] resize-none border-0 bg-transparent px-2 py-1 text-[15px] shadow-none transition-colors focus-visible:ring-0 focus-visible:outline-none dark:bg-transparent",
|
||||
"placeholder:text-muted-foreground max-h-[200px] min-h-[60px] resize-none border-0 bg-transparent px-2 py-1 text-[15px] shadow-none transition-colors focus-visible:ring-0 focus-visible:outline-none dark:bg-transparent",
|
||||
!canInput && "cursor-not-allowed",
|
||||
)}
|
||||
minRows={1}
|
||||
@@ -56,7 +56,7 @@ export function ChatComposer({
|
||||
size="icon"
|
||||
className="size-8 rounded-full bg-violet-500 text-white transition-transform hover:bg-violet-600 active:scale-95"
|
||||
onClick={onSend}
|
||||
disabled={!input.trim() || !isConnected}
|
||||
disabled={!input.trim() || !canInput}
|
||||
>
|
||||
<IconArrowUp className="size-4" />
|
||||
</Button>
|
||||
|
||||
@@ -34,7 +34,7 @@ export function ChatEmptyState({
|
||||
<p className="text-muted-foreground mb-4 text-center text-sm">
|
||||
{t("chat.empty.noConfiguredModelDescription")}
|
||||
</p>
|
||||
<Button asChild variant="secondary" size="sm" className="px-4">
|
||||
<Button asChild variant="outline" size="sm" className="px-4">
|
||||
<Link to="/models">{t("chat.empty.goToModels")}</Link>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -15,7 +15,6 @@ import { useChatModels } from "@/hooks/use-chat-models"
|
||||
import { useGateway } from "@/hooks/use-gateway"
|
||||
import { usePicoChat } from "@/hooks/use-pico-chat"
|
||||
import { useSessionHistory } from "@/hooks/use-session-history"
|
||||
import { hydrateActiveSession } from "@/lib/pico-chat-controller"
|
||||
|
||||
export function ChatPage() {
|
||||
const { t } = useTranslation()
|
||||
@@ -26,6 +25,7 @@ export function ChatPage() {
|
||||
|
||||
const {
|
||||
messages,
|
||||
connectionState,
|
||||
isTyping,
|
||||
activeSessionId,
|
||||
sendMessage,
|
||||
@@ -34,7 +34,8 @@ export function ChatPage() {
|
||||
} = usePicoChat()
|
||||
|
||||
const { state: gwState } = useGateway()
|
||||
const isConnected = gwState === "running"
|
||||
const isGatewayRunning = gwState === "running"
|
||||
const isChatConnected = connectionState === "connected"
|
||||
|
||||
const {
|
||||
defaultModelName,
|
||||
@@ -43,7 +44,8 @@ export function ChatPage() {
|
||||
oauthModels,
|
||||
localModels,
|
||||
handleSetDefault,
|
||||
} = useChatModels({ isConnected })
|
||||
} = useChatModels({ isConnected: isGatewayRunning })
|
||||
const canSend = isChatConnected && Boolean(defaultModelName)
|
||||
|
||||
const {
|
||||
sessions,
|
||||
@@ -68,10 +70,6 @@ export function ChatPage() {
|
||||
syncScrollState(e.currentTarget)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
void hydrateActiveSession()
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (scrollRef.current) {
|
||||
if (isAtBottom) {
|
||||
@@ -82,9 +80,10 @@ export function ChatPage() {
|
||||
}, [messages, isTyping, isAtBottom])
|
||||
|
||||
const handleSend = () => {
|
||||
if (!input.trim() || !isConnected) return
|
||||
sendMessage(input.trim())
|
||||
setInput("")
|
||||
if (!input.trim() || !canSend) return
|
||||
if (sendMessage(input.trim())) {
|
||||
setInput("")
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -143,7 +142,7 @@ export function ChatPage() {
|
||||
<ChatEmptyState
|
||||
hasConfiguredModels={hasConfiguredModels}
|
||||
defaultModelName={defaultModelName}
|
||||
isConnected={isConnected}
|
||||
isConnected={isGatewayRunning}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -168,7 +167,7 @@ export function ChatPage() {
|
||||
input={input}
|
||||
onInputChange={setInput}
|
||||
onSend={handleSend}
|
||||
isConnected={isConnected}
|
||||
isConnected={isChatConnected}
|
||||
hasDefaultModel={Boolean(defaultModelName)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user