mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-18 13:23:33 +08:00
fix(desktop): improve docked terminal sizing (#708)
Tested: cd desktop && bun run test -- src/pages/ActiveSession.test.tsx Tested: bun run check:desktop Confidence: high Scope-risk: narrow
This commit is contained in:
parent
18c6a43033
commit
4573e71801
@ -958,6 +958,63 @@ describe('ActiveSession task polling', () => {
|
||||
expect(useTabStore.getState().activeTabId).toBe(terminalTab?.sessionId)
|
||||
})
|
||||
|
||||
it('keeps the docked terminal usable on a new empty session', () => {
|
||||
const sessionId = 'empty-terminal-session'
|
||||
|
||||
useSessionStore.setState({
|
||||
sessions: [{
|
||||
id: sessionId,
|
||||
title: 'Empty Terminal Session',
|
||||
createdAt: '2026-04-10T00:00:00.000Z',
|
||||
modifiedAt: '2026-04-10T00:00:00.000Z',
|
||||
messageCount: 0,
|
||||
projectPath: '/tmp/project-root',
|
||||
workDir: '/tmp/project-root',
|
||||
workDirExists: true,
|
||||
}],
|
||||
activeSessionId: sessionId,
|
||||
isLoading: false,
|
||||
error: null,
|
||||
})
|
||||
useTabStore.setState({
|
||||
tabs: [{ sessionId, title: 'Empty Terminal Session', type: 'session', status: 'idle' }],
|
||||
activeTabId: sessionId,
|
||||
})
|
||||
useChatStore.setState({
|
||||
sessions: {
|
||||
[sessionId]: {
|
||||
messages: [],
|
||||
chatState: 'idle',
|
||||
connectionState: 'connected',
|
||||
streamingText: '',
|
||||
streamingToolInput: '',
|
||||
activeToolUseId: null,
|
||||
activeToolName: null,
|
||||
activeThinkingId: null,
|
||||
pendingPermission: null,
|
||||
pendingComputerUsePermission: null,
|
||||
tokenUsage: { input_tokens: 0, output_tokens: 0 },
|
||||
streamingResponseChars: 0,
|
||||
elapsedSeconds: 0,
|
||||
statusVerb: '',
|
||||
slashCommands: [],
|
||||
agentTaskNotifications: {},
|
||||
elapsedTimer: null,
|
||||
},
|
||||
},
|
||||
})
|
||||
useTerminalPanelStore.getState().openPanel(sessionId)
|
||||
|
||||
render(<ActiveSession />)
|
||||
|
||||
expect(screen.getByTestId('active-session-chat-column')).toHaveClass('min-h-0')
|
||||
expect(screen.getByTestId('empty-session-hero')).toHaveClass('min-h-0')
|
||||
expect(screen.getByTestId('empty-session-hero')).toHaveClass('pb-6')
|
||||
expect(screen.getByTestId('empty-session-hero')).not.toHaveClass('pb-32')
|
||||
expect(screen.getByTestId('session-terminal-panel')).toHaveStyle({ height: '420px' })
|
||||
expect(screen.getByTestId('terminal-resize-handle')).toHaveAttribute('aria-valuemax', '760')
|
||||
})
|
||||
|
||||
it('keeps the docked terminal mounted when the panel is hidden', async () => {
|
||||
const sessionId = 'terminal-hide-session'
|
||||
|
||||
|
||||
@ -335,6 +335,7 @@ export function ActiveSession() {
|
||||
const streamingText = sessionState?.streamingText ?? ''
|
||||
const activeGoal = sessionState?.activeGoal ?? null
|
||||
const isEmpty = messages.length === 0 && !streamingText && (session?.messageCount ?? 0) === 0
|
||||
const compactEmptyHero = isEmpty && showTerminalPanel
|
||||
const isHistoryLoading =
|
||||
!isMemberSession &&
|
||||
(session?.messageCount ?? 0) > 0 &&
|
||||
@ -370,7 +371,7 @@ export function ActiveSession() {
|
||||
<div data-testid="active-session-content-row" className="flex min-h-0 min-w-0 flex-1">
|
||||
<div
|
||||
data-testid="active-session-chat-column"
|
||||
className={`flex flex-col ${showRightPanel ? CHAT_COLUMN_WITH_WORKSPACE_CLASS : isMobileLayout ? 'min-w-0 flex-1' : 'min-w-[360px] flex-1'}`}
|
||||
className={`flex min-h-0 flex-col ${showRightPanel ? CHAT_COLUMN_WITH_WORKSPACE_CLASS : isMobileLayout ? 'min-w-0 flex-1' : 'min-w-[360px] flex-1'}`}
|
||||
>
|
||||
{isMemberSession && (
|
||||
<div className="shrink-0 border-b border-[var(--color-border)] bg-[var(--color-surface-container)]">
|
||||
@ -418,11 +419,17 @@ export function ActiveSession() {
|
||||
)}
|
||||
|
||||
{isEmpty ? (
|
||||
<div className="flex flex-1 flex-col items-center justify-center p-8 pb-32">
|
||||
<div
|
||||
data-testid="empty-session-hero"
|
||||
className={[
|
||||
'flex min-h-0 flex-1 flex-col items-center justify-center overflow-hidden px-8 pt-8',
|
||||
compactEmptyHero ? 'pb-6' : 'pb-32',
|
||||
].join(' ')}
|
||||
>
|
||||
<div className="flex max-w-md flex-col items-center text-center">
|
||||
{isMemberSession ? (
|
||||
<>
|
||||
<span className="material-symbols-outlined text-[48px] mb-4 text-[var(--color-text-tertiary)]">smart_toy</span>
|
||||
<span className={`material-symbols-outlined mb-4 text-[var(--color-text-tertiary)] ${compactEmptyHero ? 'text-[36px]' : 'text-[48px]'}`}>smart_toy</span>
|
||||
<p className="text-[var(--color-text-secondary)]">
|
||||
{memberInfo?.status === 'running'
|
||||
? `${memberInfo.role} ${t('teams.working')}`
|
||||
@ -431,11 +438,15 @@ export function ActiveSession() {
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<img src={publicAssetPath('app-icon.png')} alt="Claude Code Haha" className="mb-6 h-24 w-24" />
|
||||
<h1 className="mb-2 text-3xl font-extrabold tracking-tight text-[var(--color-text-primary)]" style={{ fontFamily: 'var(--font-headline)' }}>
|
||||
<img
|
||||
src={publicAssetPath('app-icon.png')}
|
||||
alt="Claude Code Haha"
|
||||
className={compactEmptyHero ? 'mb-4 h-16 w-16' : 'mb-6 h-24 w-24'}
|
||||
/>
|
||||
<h1 className={`${compactEmptyHero ? 'mb-1 text-2xl' : 'mb-2 text-3xl'} font-extrabold tracking-tight text-[var(--color-text-primary)]`} style={{ fontFamily: 'var(--font-headline)' }}>
|
||||
{t('empty.title')}
|
||||
</h1>
|
||||
<p className="mx-auto max-w-xs text-[var(--color-text-secondary)]" style={{ fontFamily: 'var(--font-body)' }}>
|
||||
<p className={`mx-auto max-w-xs text-[var(--color-text-secondary)] ${compactEmptyHero ? 'text-sm' : ''}`} style={{ fontFamily: 'var(--font-body)' }}>
|
||||
{t('empty.subtitle')}
|
||||
</p>
|
||||
</>
|
||||
@ -543,7 +554,7 @@ export function ActiveSession() {
|
||||
<div
|
||||
data-testid="session-terminal-panel"
|
||||
className={[
|
||||
'flex shrink-0 flex-col border-t border-[var(--color-border)] bg-[var(--color-surface-container-lowest)]',
|
||||
'flex min-h-0 shrink-0 flex-col border-t border-[var(--color-border)] bg-[var(--color-surface-container-lowest)]',
|
||||
showTerminalPanel ? '' : 'hidden',
|
||||
].join(' ')}
|
||||
style={{ height: showTerminalPanel ? terminalPanelHeight : 0 }}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { create } from 'zustand'
|
||||
import { destroyTerminalRuntime } from '../lib/terminalRuntime'
|
||||
|
||||
export const TERMINAL_PANEL_DEFAULT_HEIGHT = 300
|
||||
export const TERMINAL_PANEL_MIN_HEIGHT = 220
|
||||
export const TERMINAL_PANEL_MAX_HEIGHT = 560
|
||||
export const TERMINAL_PANEL_DEFAULT_HEIGHT = 420
|
||||
export const TERMINAL_PANEL_MIN_HEIGHT = 260
|
||||
export const TERMINAL_PANEL_MAX_HEIGHT = 760
|
||||
export const SESSION_TERMINAL_RUNTIME_PREFIX = '__session_terminal__'
|
||||
|
||||
type TerminalPanelSessionState = {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user