feat(frontend): Esc 로 답변 생성 중단 — 생성 중 아니면 기존대로 목록 이동
중단 버튼·백엔드 cancel·OpenCode abort 체인은 이미 있었고 Esc 배선만 없었음. 서버만 생성 중(재진입, generatingRemotely)일 때도 Esc 가 cancel 을 보냄. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
8571db5bee
commit
e9e644b15b
@@ -0,0 +1,55 @@
|
||||
import { describe, expect, it, vi, beforeEach } from "vitest"
|
||||
import { act, fireEvent, render } from "@testing-library/react"
|
||||
import { MemoryRouter, Route, Routes } from "react-router-dom"
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
|
||||
import SessionChatPage from "./SessionChatPage"
|
||||
import { useSnapChatStore } from "../store/snapChatStore"
|
||||
import * as stream from "../api/snap.stream"
|
||||
|
||||
// Esc 는 답변 생성 중이면 중단, 아니면 목록으로 — 클로드처럼.
|
||||
// NavRail 안 ClipboardHistory 가 IndexedDB 를 써서(jsdom 없음) 레일은 비움.
|
||||
vi.mock("../components/NavRail", () => ({ NavRail: () => null }))
|
||||
vi.mock("../api/snap.stream", async (orig) => ({
|
||||
...(await orig<typeof stream>()),
|
||||
cancelStream: vi.fn().mockResolvedValue(undefined),
|
||||
snapStream: vi.fn().mockResolvedValue(undefined),
|
||||
}))
|
||||
|
||||
function mount() {
|
||||
const qc = new QueryClient({ defaultOptions: { queries: { retry: false } } })
|
||||
return render(
|
||||
<QueryClientProvider client={qc}>
|
||||
<MemoryRouter initialEntries={["/snap/s/s1"]}>
|
||||
<Routes>
|
||||
<Route path="/snap/s/:id" element={<SessionChatPage />} />
|
||||
<Route path="/snap" element={<div>목록화면-테스트</div>} />
|
||||
</Routes>
|
||||
</MemoryRouter>
|
||||
</QueryClientProvider>
|
||||
)
|
||||
}
|
||||
|
||||
describe("SessionChatPage Esc", () => {
|
||||
beforeEach(() => {
|
||||
useSnapChatStore.getState().reset()
|
||||
vi.mocked(stream.cancelStream).mockClear()
|
||||
})
|
||||
|
||||
it("스트리밍 중 Esc 는 중단(cancelStream)하고 화면에 남는다", () => {
|
||||
const { queryByText } = mount()
|
||||
act(() => {
|
||||
useSnapChatStore.getState().setStreaming(true)
|
||||
})
|
||||
fireEvent.keyDown(window, { key: "Escape" })
|
||||
expect(vi.mocked(stream.cancelStream)).toHaveBeenCalledWith("s1")
|
||||
expect(useSnapChatStore.getState().isStreaming).toBe(false)
|
||||
expect(queryByText("목록화면-테스트")).toBeNull()
|
||||
})
|
||||
|
||||
it("답변 중이 아니면 Esc 는 목록으로 간다", () => {
|
||||
const { getByText } = mount()
|
||||
fireEvent.keyDown(window, { key: "Escape" })
|
||||
expect(vi.mocked(stream.cancelStream)).not.toHaveBeenCalled()
|
||||
expect(getByText("목록화면-테스트")).toBeTruthy()
|
||||
})
|
||||
})
|
||||
@@ -22,9 +22,6 @@ export default function SessionChatPage() {
|
||||
const [navBlocks, setNavBlocks] = useState<{ index: number; lang: string }[]>([])
|
||||
const scrollRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
// 단계적 Esc: 대화창에선 목록/검색 화면으로(창은 목록에서 Esc 로 숨김).
|
||||
useEscapeKey(() => navigate(PATHS.SNAP))
|
||||
|
||||
const { messages, isStreaming, isRevealing } = useSnapChatStore(
|
||||
useShallow((s) => ({
|
||||
messages: s.messages,
|
||||
@@ -37,6 +34,13 @@ export default function SessionChatPage() {
|
||||
// 시머로 "생각 중" 표시 + 전송 잠금(보내면 어차피 409). 폴링이 완성본을 곧 가져옴.
|
||||
const generatingRemotely = !busy && !!detail?.isGenerating && messages.at(-1)?.role === "user"
|
||||
|
||||
// 단계적 Esc: 답변 생성 중이면 중단(클로드처럼), 아니면 목록/검색 화면으로(창은 목록에서 Esc 로 숨김).
|
||||
// 재진입해서 서버만 생성 중(generatingRemotely)일 때도 Esc 가 백엔드 취소를 보냄.
|
||||
useEscapeKey(() => {
|
||||
if (busy || generatingRemotely) stop()
|
||||
else navigate(PATHS.SNAP)
|
||||
})
|
||||
|
||||
// 세션 진입: 과거대화 seed. NewChatPage 에서 넘어온 firstMessage 있으면 seed 없이 바로 전송.
|
||||
const firstRequest = location.state as {
|
||||
firstMessage?: string
|
||||
|
||||
@@ -6,3 +6,4 @@
|
||||
| 10:26 | 삼성향 라이트 팔레트 추가·기본으로 — 삼성닷컴 실측 토큰(검정 CTA·흰 바탕·#f7f7f7 면·#ddd 테두리), 알약 radius 20px. 다크는 그대로. 폰트는 라이선스 근거 없어 미적용 |
|
||||
| 10:40 | PwC 로고·마크 전부 제거(LogoMark 빈 렌더, 파비콘 투명), 기본 모드 라이트로(예전 dark 저장값 한 번 초기화), 삼성 팔레트 포인트를 Samsung Blue #1428A0 로(버튼·링·링크) |
|
||||
| 10:43 | SAP MCP 를 -12 에 따로 띄우는 준비 — OpenCode 템플릿 sap-icf 를 MCP_API_KEY 유무로 on/off 렌더, .env.example SAP 블록, README 절차(-13 번들 재활용, 컨테이너 간 통신 없이) |
|
||||
| 13:24 | Esc 로 답변 중단 — 생성 중이면 Esc 가 중단(클로드처럼), 아니면 목록으로. 재진입 상태에서도 백엔드 cancel. 페이지 테스트 2개 |
|
||||
|
||||
Reference in New Issue
Block a user