fix(chat): '생각하는 중'과 '작성 중'이 둘 다 보이던 것 — 상태줄 하나로 합치고 첫 글자 전/후로 라벨만 바뀜. 0.1.3
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
69d4dd340f
commit
596c7e52a8
@@ -1,7 +1,7 @@
|
|||||||
import type { ReactNode } from "react"
|
import type { ReactNode } from "react"
|
||||||
|
|
||||||
/** 답변 자리(첫 토큰 전·재진입 대기·세션 생성 중). Message 의 assistant 모양과 똑같이 —
|
/** 답변 자리(첫 토큰 전·재진입 대기·세션 생성 중). Message 의 assistant 모양과 똑같이 —
|
||||||
* AI 배지 + CODEASSIST 라벨, 본문은 상자 없이. 안에 시머 텍스트나 스트리밍 본문을 넣는다. */
|
* AI 배지 + CODEASSIST 라벨, 본문은 상자 없이. "생각하는 중" 표시는 아래 WorkingRow 가 맡음. */
|
||||||
export function ThinkingBubble({ children }: { children?: ReactNode }) {
|
export function ThinkingBubble({ children }: { children?: ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-start gap-1">
|
<div className="flex flex-col items-start gap-1">
|
||||||
@@ -13,9 +13,7 @@ export function ThinkingBubble({ children }: { children?: ReactNode }) {
|
|||||||
CODEASSIST
|
CODEASSIST
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-foreground w-full text-sm leading-[1.9]">
|
<div className="text-foreground w-full text-sm leading-[1.9]">{children}</div>
|
||||||
{children ?? <span className="shimmer-text text-sm">생각하는 중…</span>}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,8 +66,8 @@ export function ThinkingSteps({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 하단 "작성 중… · N초" — 스피너 + 경과 초. busy 가 true 인 동안만 그림. */
|
/** 하단 상태줄 — 스피너 + 경과 초. 답변 글자 오기 전엔 "생각하는 중", 오기 시작하면 "작성 중". */
|
||||||
export function WorkingRow({ busy }: { busy: boolean }) {
|
export function WorkingRow({ busy, label = "작성 중…" }: { busy: boolean; label?: string }) {
|
||||||
const [elapsed, setElapsed] = useState(0)
|
const [elapsed, setElapsed] = useState(0)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!busy) return
|
if (!busy) return
|
||||||
@@ -80,7 +80,7 @@ export function WorkingRow({ busy }: { busy: boolean }) {
|
|||||||
return (
|
return (
|
||||||
<div className="text-muted-foreground flex items-center gap-2 text-[12.5px]">
|
<div className="text-muted-foreground flex items-center gap-2 text-[12.5px]">
|
||||||
<Loader2 size={14} className="animate-spin" />
|
<Loader2 size={14} className="animate-spin" />
|
||||||
작성 중… · {elapsed}초
|
{label} · {elapsed}초
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ describe("NewChatPage 전송", () => {
|
|||||||
mount()
|
mount()
|
||||||
fireEvent.click(screen.getByText("MARA 에서 자재번호로 자재유형(MTART) 읽는 SELECT SINGLE"))
|
fireEvent.click(screen.getByText("MARA 에서 자재번호로 자재유형(MTART) 읽는 SELECT SINGLE"))
|
||||||
expect(mutate).toHaveBeenCalledOnce()
|
expect(mutate).toHaveBeenCalledOnce()
|
||||||
expect(await screen.findByText("생각하는 중…")).toBeTruthy()
|
expect(await screen.findByText(/생각하는 중…/)).toBeTruthy()
|
||||||
expect(screen.getByText("MARA 에서 자재번호로 자재유형(MTART) 읽는 SELECT SINGLE")).toBeTruthy()
|
expect(screen.getByText("MARA 에서 자재번호로 자재유형(MTART) 읽는 SELECT SINGLE")).toBeTruthy()
|
||||||
expect(screen.queryByText("무엇을 도와드릴까요?")).toBeNull()
|
expect(screen.queryByText("무엇을 도와드릴까요?")).toBeNull()
|
||||||
act(() => lastCallbacks().onSuccess({ id: "ses_new" }))
|
act(() => lastCallbacks().onSuccess({ id: "ses_new" }))
|
||||||
@@ -40,10 +40,10 @@ describe("NewChatPage 전송", () => {
|
|||||||
it("세션 생성 실패면 헤로로 돌아온다", async () => {
|
it("세션 생성 실패면 헤로로 돌아온다", async () => {
|
||||||
mount()
|
mount()
|
||||||
fireEvent.click(screen.getByText("내부 테이블 LOOP 에서 그룹 소계 구하는 관용구"))
|
fireEvent.click(screen.getByText("내부 테이블 LOOP 에서 그룹 소계 구하는 관용구"))
|
||||||
expect(await screen.findByText("생각하는 중…")).toBeTruthy()
|
expect(await screen.findByText(/생각하는 중…/)).toBeTruthy()
|
||||||
act(() => lastCallbacks().onError())
|
act(() => lastCallbacks().onError())
|
||||||
expect(await screen.findByText("무엇을 도와드릴까요?")).toBeTruthy()
|
expect(await screen.findByText("무엇을 도와드릴까요?")).toBeTruthy()
|
||||||
expect(screen.queryByText("생각하는 중…")).toBeNull()
|
expect(screen.queryByText(/생각하는 중…/)).toBeNull()
|
||||||
})
|
})
|
||||||
|
|
||||||
it("생성 중엔 두 번째 전송을 무시한다", () => {
|
it("생성 중엔 두 번째 전송을 무시한다", () => {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { Hero } from "../components/Hero"
|
|||||||
import { Composer } from "../components/Composer"
|
import { Composer } from "../components/Composer"
|
||||||
import { Message } from "../components/Message"
|
import { Message } from "../components/Message"
|
||||||
import { ThinkingBubble } from "../components/ThinkingBubble"
|
import { ThinkingBubble } from "../components/ThinkingBubble"
|
||||||
|
import { WorkingRow } from "../components/ThinkingSteps"
|
||||||
import { useEscapeKey } from "../hooks/useEscapeKey"
|
import { useEscapeKey } from "../hooks/useEscapeKey"
|
||||||
import type { SnapImageInput } from "../contract/types"
|
import type { SnapImageInput } from "../contract/types"
|
||||||
|
|
||||||
@@ -61,6 +62,7 @@ export default function NewChatPage() {
|
|||||||
{/* eslint-disable-next-line jsx-a11y/aria-role -- Message 의 role 은 ARIA 아니고 화자 */}
|
{/* eslint-disable-next-line jsx-a11y/aria-role -- Message 의 role 은 ARIA 아니고 화자 */}
|
||||||
<Message role="user" content={pending} />
|
<Message role="user" content={pending} />
|
||||||
<ThinkingBubble />
|
<ThinkingBubble />
|
||||||
|
<WorkingRow busy label="생각하는 중…" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<Composer
|
<Composer
|
||||||
|
|||||||
@@ -174,12 +174,7 @@ export default function SessionChatPage() {
|
|||||||
isDone={!isStreaming}
|
isDone={!isStreaming}
|
||||||
answerStarted={m.content !== ""}
|
answerStarted={m.content !== ""}
|
||||||
/>
|
/>
|
||||||
{m.content === "" ? (
|
{m.content !== "" && (
|
||||||
// 첫 토큰 오기 전 빈 시간 메움 — 과정도 아직 없으면 시머로 "생각 중" 신호
|
|
||||||
steps.length === 0 && (
|
|
||||||
<span className="shimmer-text text-sm">생각하는 중…</span>
|
|
||||||
)
|
|
||||||
) : (
|
|
||||||
<StreamingText
|
<StreamingText
|
||||||
text={m.content}
|
text={m.content}
|
||||||
isStreaming={isStreaming}
|
isStreaming={isStreaming}
|
||||||
@@ -188,7 +183,10 @@ export default function SessionChatPage() {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</ThinkingBubble>
|
</ThinkingBubble>
|
||||||
<WorkingRow busy={isStreaming} />
|
<WorkingRow
|
||||||
|
busy={isStreaming}
|
||||||
|
label={m.content === "" ? "생각하는 중…" : "작성 중…"}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -222,7 +220,7 @@ export default function SessionChatPage() {
|
|||||||
{generatingRemotely && (
|
{generatingRemotely && (
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
<ThinkingBubble />
|
<ThinkingBubble />
|
||||||
<WorkingRow busy />
|
<WorkingRow busy label="생각하는 중…" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Generated
+1
-1
@@ -485,7 +485,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codeassist-tauri"
|
name = "codeassist-tauri"
|
||||||
version = "0.1.1"
|
version = "0.1.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"png 0.17.16",
|
"png 0.17.16",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "codeassist-tauri"
|
name = "codeassist-tauri"
|
||||||
version = "0.1.2"
|
version = "0.1.3"
|
||||||
description = "CodeAssist 표준 Rust/Tauri 데스크톱 앱"
|
description = "CodeAssist 표준 Rust/Tauri 데스크톱 앱"
|
||||||
authors = ["justdodev"]
|
authors = ["justdodev"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "CodeAssist",
|
"productName": "CodeAssist",
|
||||||
"version": "0.1.2",
|
"version": "0.1.3",
|
||||||
"identifier": "com.codeassist.app",
|
"identifier": "com.codeassist.app",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": { "cwd": "../../2_frontend", "script": "npm run dev" },
|
"beforeDevCommand": { "cwd": "../../2_frontend", "script": "npm run dev" },
|
||||||
|
|||||||
Reference in New Issue
Block a user