fix(chat): hide agent tab when course agent is disabled
This commit is contained in:
@@ -27,8 +27,10 @@ function elements(root, predicate) {
|
|||||||
|
|
||||||
function setup(overrides = {}) {
|
function setup(overrides = {}) {
|
||||||
const state = []
|
const state = []
|
||||||
|
const effects = []
|
||||||
let index = 0
|
let index = 0
|
||||||
let cleared = 0
|
let cleared = 0
|
||||||
|
const modeChanges = []
|
||||||
const panel = compile('../src/renderer/src/features/workspace/WorkspaceQaPanel.tsx', {
|
const panel = compile('../src/renderer/src/features/workspace/WorkspaceQaPanel.tsx', {
|
||||||
'../../i18n': i18n,
|
'../../i18n': i18n,
|
||||||
'../../components/AppStatusModals': { ConfirmStatusModal },
|
'../../components/AppStatusModals': { ConfirmStatusModal },
|
||||||
@@ -36,7 +38,7 @@ function setup(overrides = {}) {
|
|||||||
'react-dom': { createPortal: child => child },
|
'react-dom': { createPortal: child => child },
|
||||||
react: {
|
react: {
|
||||||
...React,
|
...React,
|
||||||
useEffect() {},
|
useEffect(effect) { effects.push(effect) },
|
||||||
useState(initial) {
|
useState(initial) {
|
||||||
const slot = index++
|
const slot = index++
|
||||||
if (!(slot in state)) state[slot] = initial
|
if (!(slot in state)) state[slot] = initial
|
||||||
@@ -45,13 +47,16 @@ function setup(overrides = {}) {
|
|||||||
}
|
}
|
||||||
}, { document: { body: {} } }).default
|
}, { document: { body: {} } }).default
|
||||||
const props = {
|
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 },
|
visibleTeacherMessages: [], agentMessages: [], workspaceChatScrollRef: { current: null },
|
||||||
|
onModeChange(mode) { modeChanges.push(mode) },
|
||||||
onClearConversation() { cleared++ }, ...overrides
|
onClearConversation() { cleared++ }, ...overrides
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
render() { index = 0; return panel(props) },
|
render() { index = 0; effects.length = 0; return panel(props) },
|
||||||
cleared: () => cleared
|
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.doesNotMatch(source, /window\.confirm/)
|
||||||
assert.match(source, /onClick=\{onClearConversation\}/)
|
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, [])
|
||||||
|
})
|
||||||
|
|||||||
@@ -142,8 +142,10 @@ export default function WorkspaceQaPanel({
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (teacherQaDisabled && qaMode === 'teacher') onModeChange('ai')
|
if ((teacherQaDisabled && qaMode === 'teacher') || (!agentStatusLoading && !agentEnabled && qaMode === 'agent')) {
|
||||||
}, [onModeChange, qaMode, teacherQaDisabled])
|
onModeChange('ai')
|
||||||
|
}
|
||||||
|
}, [agentEnabled, agentStatusLoading, onModeChange, qaMode, teacherQaDisabled])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!contextMenu) return
|
if (!contextMenu) return
|
||||||
@@ -228,12 +230,12 @@ export default function WorkspaceQaPanel({
|
|||||||
<span className={['pointer-events-none absolute right-0 top-8 z-50 hidden whitespace-nowrap rounded-md border px-2 py-1 text-[11px] font-semibold shadow-[0_10px_24px_rgba(0,0,0,0.24)] group-hover:block', dark ? 'border-white/10 bg-[#303030] text-white/78' : 'border-[#d8dee9] bg-white text-[#4f596b]'].join(' ')}>{t("최소화")}</span>
|
<span className={['pointer-events-none absolute right-0 top-8 z-50 hidden whitespace-nowrap rounded-md border px-2 py-1 text-[11px] font-semibold shadow-[0_10px_24px_rgba(0,0,0,0.24)] group-hover:block', dark ? 'border-white/10 bg-[#303030] text-white/78' : 'border-[#d8dee9] bg-white text-[#4f596b]'].join(' ')}>{t("최소화")}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className={['mt-3 grid grid-cols-3 overflow-hidden rounded-md border', borderSoft].join(' ')}>
|
<div className={['mt-3 grid overflow-hidden rounded-md border', agentEnabled ? 'grid-cols-3' : 'grid-cols-2', borderSoft].join(' ')}>
|
||||||
{[
|
{[
|
||||||
{ id: 'ai' as const, label: 'AI', Icon: Bot },
|
{ id: 'ai' as const, label: 'AI', Icon: Bot },
|
||||||
{ id: 'agent' as const, label: t("에이전트"), Icon: WandSparkles },
|
{ id: 'agent' as const, label: t("에이전트"), Icon: WandSparkles },
|
||||||
{ id: 'teacher' as const, label: t("강사"), Icon: User }
|
{ 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 disabled = id === 'teacher' && teacherQaDisabled
|
||||||
const teacherTabFlash = id === 'teacher' && teacherChatFlash && !minimized && qaMode === 'ai'
|
const teacherTabFlash = id === 'teacher' && teacherChatFlash && !minimized && qaMode === 'ai'
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user