diff --git a/scripts/test-chat-clear-confirmation.cjs b/scripts/test-chat-clear-confirmation.cjs index 3975982..bd8292e 100644 --- a/scripts/test-chat-clear-confirmation.cjs +++ b/scripts/test-chat-clear-confirmation.cjs @@ -27,8 +27,10 @@ function elements(root, predicate) { function setup(overrides = {}) { const state = [] + const effects = [] let index = 0 let cleared = 0 + const modeChanges = [] const panel = compile('../src/renderer/src/features/workspace/WorkspaceQaPanel.tsx', { '../../i18n': i18n, '../../components/AppStatusModals': { ConfirmStatusModal }, @@ -36,7 +38,7 @@ function setup(overrides = {}) { 'react-dom': { createPortal: child => child }, react: { ...React, - useEffect() {}, + useEffect(effect) { effects.push(effect) }, useState(initial) { const slot = index++ if (!(slot in state)) state[slot] = initial @@ -45,13 +47,16 @@ function setup(overrides = {}) { } }, { document: { body: {} } }).default const props = { - dark: true, workspaceActive: true, qaMode: 'ai', visibleAiMessages: [{ id: '1', content: 'hello' }], + dark: true, workspaceActive: true, qaMode: 'ai', agentEnabled: true, visibleAiMessages: [{ id: '1', content: 'hello' }], visibleTeacherMessages: [], agentMessages: [], workspaceChatScrollRef: { current: null }, + onModeChange(mode) { modeChanges.push(mode) }, onClearConversation() { cleared++ }, ...overrides } return { - render() { index = 0; return panel(props) }, - cleared: () => cleared + render() { index = 0; effects.length = 0; return panel(props) }, + cleared: () => cleared, + runEffects() { effects.forEach(effect => effect()) }, + modeChanges } } @@ -113,3 +118,30 @@ test('input no longer opens a native confirmation dialog', () => { assert.doesNotMatch(source, /window\.confirm/) assert.match(source, /onClick=\{onClearConversation\}/) }) + +for (const dark of [false, true]) { + for (const agentEnabled of [false, true]) { + test(`agent availability controls tab count and layout (${dark ? 'dark' : 'light'}, enabled=${agentEnabled})`, () => { + const harness = setup({ dark, agentEnabled }) + const grids = elements(harness.render(), node => node.props.className?.includes('mt-3 grid')) + assert.equal(grids.length, 1) + const tabs = elements(grids[0], node => node.type === 'button') + assert.deepEqual(tabs.map(tab => tab.props.children[1].props.children), agentEnabled ? ['AI', '에이전트', '강사'] : ['AI', '강사']) + assert.ok(grids[0].props.className.includes(agentEnabled ? 'grid-cols-3' : 'grid-cols-2')) + }) + } +} + +test('returns to AI when the selected agent is disabled after status loading', () => { + const harness = setup({ qaMode: 'agent', agentEnabled: false, agentStatusLoading: false, minimized: true }) + harness.render() + harness.runEffects() + assert.deepEqual(harness.modeChanges, ['ai']) +}) + +test('does not reset the selected agent while status is still loading', () => { + const harness = setup({ qaMode: 'agent', agentEnabled: false, agentStatusLoading: true, minimized: true }) + harness.render() + harness.runEffects() + assert.deepEqual(harness.modeChanges, []) +}) diff --git a/src/renderer/src/features/workspace/WorkspaceQaPanel.tsx b/src/renderer/src/features/workspace/WorkspaceQaPanel.tsx index 3cb85b3..ffe6abf 100644 --- a/src/renderer/src/features/workspace/WorkspaceQaPanel.tsx +++ b/src/renderer/src/features/workspace/WorkspaceQaPanel.tsx @@ -142,8 +142,10 @@ export default function WorkspaceQaPanel({ } useEffect(() => { - if (teacherQaDisabled && qaMode === 'teacher') onModeChange('ai') - }, [onModeChange, qaMode, teacherQaDisabled]) + if ((teacherQaDisabled && qaMode === 'teacher') || (!agentStatusLoading && !agentEnabled && qaMode === 'agent')) { + onModeChange('ai') + } + }, [agentEnabled, agentStatusLoading, onModeChange, qaMode, teacherQaDisabled]) useEffect(() => { if (!contextMenu) return @@ -228,12 +230,12 @@ export default function WorkspaceQaPanel({ -
+
{[ { id: 'ai' as const, label: 'AI', Icon: Bot }, { id: 'agent' as const, label: t("에이전트"), Icon: WandSparkles }, { id: 'teacher' as const, label: t("강사"), Icon: User } - ].map(({ id, label, Icon }) => { + ].filter(({ id }) => id !== 'agent' || agentEnabled).map(({ id, label, Icon }) => { const disabled = id === 'teacher' && teacherQaDisabled const teacherTabFlash = id === 'teacher' && teacherChatFlash && !minimized && qaMode === 'ai'