mirror of
https://github.com/nesquena/hermes-webui.git
synced 2026-05-26 03:30:36 +00:00
Merge remote-tracking branch pr/1249 into stage/batch-v0.50.238
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
### Fixed
|
||||
- **Compaction preserves visible prompts** — WebUI now keeps model-facing compacted context separately from the visible transcript, so automatic context compaction no longer replaces earlier user prompts in the scrollback. (`api/models.py`, `api/streaming.py`, `api/routes.py`) @franksong2702 — Closes #1217
|
||||
- **MiniMax China provider visible in model picker** — `MINIMAX_CN_API_KEY` now maps to the `minimax-cn` provider instead of being collapsed into global `minimax`; WebUI includes a static MiniMax (China) model catalog/display label so `providers.minimax-cn: {}` can render a populated picker group. (`api/config.py`, `api/providers.py`) @franksong2702 — Closes #1236
|
||||
- **Embedded terminal resize and collapse controls restored** — restores the collapse/expand dock markup and controlled height CSS variable lost during the v0.50.237 batch integration, and reinstates regression coverage for terminal resizing and collapsed-state behavior. (`static/index.html`, `static/style.css`, `static/terminal.js`, `tests/test_embedded_workspace_terminal.py`) @franksong2702
|
||||
|
||||
## [v0.50.237] — 2026-04-29
|
||||
|
||||
|
||||
@@ -325,6 +325,7 @@
|
||||
<button type="button" class="composer-terminal-action" id="btnTerminalClear" onclick="clearComposerTerminal()" data-i18n="terminal_clear">Clear</button>
|
||||
<button type="button" class="composer-terminal-action" id="btnTerminalCopy" onclick="copyComposerTerminalOutput()" data-i18n="terminal_copy_output">Copy output</button>
|
||||
<button type="button" class="composer-terminal-action" id="btnTerminalRestart" onclick="restartComposerTerminal()" data-i18n="terminal_restart">Restart</button>
|
||||
<button type="button" class="composer-terminal-action" id="btnTerminalCollapse" onclick="collapseComposerTerminal()" data-i18n="terminal_collapse">Collapse</button>
|
||||
<button type="button" class="composer-terminal-action" id="btnTerminalClose" onclick="closeComposerTerminal()" data-i18n="terminal_close">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -332,6 +333,18 @@
|
||||
<div class="composer-terminal-surface" id="terminalSurface" aria-label="Workspace terminal"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="composer-terminal-dock" id="composerTerminalDock" hidden>
|
||||
<div class="composer-terminal-dock-title">
|
||||
<span class="composer-terminal-dock-dot" aria-hidden="true"></span>
|
||||
<span data-i18n="terminal_title">Terminal</span>
|
||||
<span class="composer-terminal-dot" aria-hidden="true">·</span>
|
||||
<span id="terminalDockWorkspaceLabel"></span>
|
||||
</div>
|
||||
<div class="composer-terminal-actions">
|
||||
<button type="button" class="composer-terminal-action" id="btnTerminalExpand" onclick="expandComposerTerminal()" data-i18n="terminal_expand">Expand</button>
|
||||
<button type="button" class="composer-terminal-action" id="btnTerminalDockClose" onclick="closeComposerTerminal()" data-i18n="terminal_close">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Queue pill outer: same positioning wrapper as .queue-card (max-width + padding) -->
|
||||
|
||||
+20
-3
@@ -793,10 +793,23 @@
|
||||
.send-btn:disabled{opacity:.35;cursor:not-allowed;transform:none;box-shadow:none;}
|
||||
.send-btn.visible{animation:send-pop-in .18s cubic-bezier(.34,1.56,.64,1) forwards;}
|
||||
.composer-terminal-panel{position:absolute;left:0;right:0;bottom:-24px;width:min(calc(100% - 64px),720px);margin:0 auto;box-sizing:border-box;overflow:hidden;pointer-events:none;z-index:1;}
|
||||
.composer-terminal-panel.is-open{pointer-events:auto;}
|
||||
.composer-terminal-panel.is-open,.composer-terminal-panel.is-collapsed{pointer-events:auto;}
|
||||
.composer-terminal-panel[hidden]{display:none!important;}
|
||||
.composer-terminal-inner{height:260px;min-height:180px;display:flex;flex-direction:column;overflow:hidden;resize:vertical;border:1px solid var(--border2);border-radius:14px;background:var(--surface);box-shadow:0 12px 32px rgba(0,0,0,.22);padding-bottom:38px;transform:translateY(100%);opacity:0;transition:transform .4s cubic-bezier(.32,.72,.16,1),opacity .25s ease;}
|
||||
.composer-terminal-inner{height:var(--composer-terminal-height,260px);min-height:180px;max-height:min(520px,50vh);display:flex;flex-direction:column;overflow:hidden;border:1px solid var(--border2);border-radius:14px;background:var(--surface);box-shadow:0 12px 32px rgba(0,0,0,.22);padding-bottom:38px;transform:translateY(100%);opacity:0;transition:transform .4s cubic-bezier(.32,.72,.16,1),opacity .25s ease;}
|
||||
.composer-terminal-panel.is-open .composer-terminal-inner{transform:translateY(0);opacity:1;}
|
||||
.composer-terminal-panel.is-expanding-from-dock .composer-terminal-inner{transition:opacity .18s ease;}
|
||||
.composer-terminal-panel.is-collapsed{bottom:-2px;width:min(calc(100% - 112px),560px);overflow:visible;z-index:4;}
|
||||
.composer-terminal-panel.is-collapsed .composer-terminal-inner{position:absolute;opacity:0;pointer-events:none;transform:translateY(100%);}
|
||||
.composer-terminal-dock{min-height:42px;display:flex;align-items:center;justify-content:space-between;gap:12px;border:1px solid var(--border);border-radius:13px;background:color-mix(in srgb,var(--surface) 86%,transparent);box-shadow:0 8px 22px rgba(0,0,0,.16);padding:7px 9px 7px 12px;backdrop-filter:blur(10px);transform:translateY(100%);opacity:0;transition:transform .32s cubic-bezier(.32,.72,.16,1),opacity .2s ease;}
|
||||
.composer-terminal-panel.is-collapsed .composer-terminal-dock{transform:translateY(0);opacity:.94;}
|
||||
.composer-terminal-dock[hidden]{display:none!important;}
|
||||
.composer-terminal-dock-title{min-width:0;display:flex;align-items:center;gap:6px;color:var(--muted);font-size:12px;font-weight:700;letter-spacing:.02em;text-transform:uppercase;}
|
||||
.composer-terminal-dock-dot{width:7px;height:7px;border-radius:999px;background:var(--success);box-shadow:0 0 0 3px color-mix(in srgb,var(--success) 16%,transparent);flex:0 0 auto;}
|
||||
#terminalDockWorkspaceLabel{min-width:0;max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--muted);text-transform:none;letter-spacing:0;font-weight:600;}
|
||||
.composer-terminal-resize-handle{height:12px;display:flex;align-items:center;justify-content:center;flex:0 0 auto;cursor:ns-resize;touch-action:none;background:linear-gradient(to bottom,rgba(255,255,255,.04),transparent);}
|
||||
.composer-terminal-resize-handle::before{content:"";width:52px;height:4px;border-radius:999px;background:var(--border2);opacity:.72;transition:opacity .15s,background .15s;}
|
||||
.composer-terminal-resize-handle:hover::before,.composer-terminal-resize-handle:focus-visible::before{opacity:1;background:var(--muted);}
|
||||
.composer-terminal-inner.is-resizing{transition:none;user-select:none;}
|
||||
.composer-terminal-header{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:8px 10px;border-bottom:1px solid var(--border);background:rgba(255,255,255,.025);}
|
||||
.composer-terminal-title{min-width:0;display:flex;align-items:center;gap:6px;color:var(--text);font-size:12px;font-weight:700;letter-spacing:.02em;text-transform:uppercase;}
|
||||
.composer-terminal-dot{color:var(--muted);font-weight:400;}
|
||||
@@ -972,7 +985,11 @@
|
||||
.ctx-indicator{width:32px;height:32px;}
|
||||
.ctx-tooltip{right:-4px;min-width:190px;max-width:220px;}
|
||||
.composer-terminal-panel{width:calc(100% - 20px);}
|
||||
.composer-terminal-inner{height:190px;min-height:140px;border-radius:12px;padding-bottom:28px;}
|
||||
.composer-terminal-panel.is-collapsed{bottom:-1px;width:calc(100% - 28px);}
|
||||
.composer-terminal-inner{height:var(--composer-terminal-height,190px);min-height:140px;max-height:min(300px,44vh);border-radius:12px;padding-bottom:28px;}
|
||||
.composer-terminal-dock{min-height:40px;padding:6px 7px 6px 10px;border-radius:12px;gap:8px;}
|
||||
.composer-terminal-dock-title{font-size:11px;}
|
||||
.composer-terminal-resize-handle{height:10px;cursor:default;}
|
||||
.composer-terminal-header{padding:7px 8px;}
|
||||
.composer-terminal-actions{gap:2px;overflow-x:auto;}
|
||||
.composer-terminal-action{padding:5px 7px;font-size:10px;white-space:nowrap;}
|
||||
|
||||
+36
-10
@@ -28,6 +28,7 @@ function _terminalEls(){
|
||||
return {
|
||||
panel:$('composerTerminalPanel'),
|
||||
inner:$('composerTerminalPanel')&&$('composerTerminalPanel').querySelector('.composer-terminal-inner'),
|
||||
dock:$('composerTerminalDock'),
|
||||
viewport:$('terminalViewport'),
|
||||
surface:$('terminalSurface'),
|
||||
toggle:$('btnTerminalToggle'),
|
||||
@@ -201,7 +202,7 @@ function _applyTerminalHeight(height){
|
||||
handle.setAttribute('aria-valuemax',String(bounds.max));
|
||||
handle.setAttribute('aria-valuenow',String(next));
|
||||
}
|
||||
if(TERMINAL_UI.open){
|
||||
if(TERMINAL_UI.open&&!TERMINAL_UI.collapsed){
|
||||
_fitTerminal();
|
||||
_syncTerminalTranscriptSpace(true);
|
||||
}
|
||||
@@ -280,7 +281,8 @@ function _terminalIsMessagesNearBottom(el){
|
||||
return el.scrollHeight-el.scrollTop-el.clientHeight<150;
|
||||
}
|
||||
|
||||
function _syncTerminalTranscriptSpace(open){
|
||||
function _syncTerminalTranscriptSpace(open,opts){
|
||||
opts=opts||{};
|
||||
const messages=_terminalMessagesEl();
|
||||
if(!messages)return;
|
||||
const wasNearBottom=_terminalIsMessagesNearBottom(messages);
|
||||
@@ -289,17 +291,29 @@ function _syncTerminalTranscriptSpace(open){
|
||||
messages.classList.remove('terminal-collapsed');
|
||||
messages.classList.remove('terminal-expanding-from-dock');
|
||||
messages.style.removeProperty('--terminal-card-height');
|
||||
messages.style.removeProperty('--terminal-dock-height');
|
||||
if(wasNearBottom&&typeof scrollToBottom==='function')requestAnimationFrame(scrollToBottom);
|
||||
return;
|
||||
}
|
||||
messages.classList.add('terminal-open');
|
||||
if(open==='collapsed'){
|
||||
messages.classList.remove('terminal-open');
|
||||
messages.classList.add('terminal-collapsed');
|
||||
}else{
|
||||
messages.classList.add('terminal-open');
|
||||
messages.classList.remove('terminal-collapsed');
|
||||
}
|
||||
const measure=()=>{
|
||||
if(!TERMINAL_UI.open)return;
|
||||
const {panel,inner}= _terminalEls();
|
||||
const h=(inner||panel)&&((inner||panel).getBoundingClientRect().height);
|
||||
if(h>0)messages.style.setProperty('--terminal-card-height',Math.ceil(h+24)+'px');
|
||||
const {panel,inner,dock}= _terminalEls();
|
||||
const target=open==='collapsed'?(dock||panel):(inner||panel);
|
||||
const h=target&&target.getBoundingClientRect().height;
|
||||
if(h>0){
|
||||
if(open==='collapsed')messages.style.setProperty('--terminal-dock-height',Math.ceil(h+24)+'px');
|
||||
else messages.style.setProperty('--terminal-card-height',Math.ceil(h+24)+'px');
|
||||
}
|
||||
if(wasNearBottom&&typeof scrollToBottom==='function')scrollToBottom();
|
||||
};
|
||||
if(opts.immediate)measure();
|
||||
requestAnimationFrame(measure);
|
||||
setTimeout(measure,420);
|
||||
}
|
||||
@@ -317,9 +331,11 @@ function _fitTerminal(){
|
||||
|
||||
function _setTerminalChromeState(state){
|
||||
const {panel,inner,dock,workspace,dockWorkspace}= _terminalEls();
|
||||
const composerWrap=$('composerWrap');
|
||||
if(!panel)return;
|
||||
const collapsed=state==='collapsed';
|
||||
const expanded=state==='expanded';
|
||||
if(composerWrap)composerWrap.classList.toggle('terminal-dock-visible',collapsed);
|
||||
panel.hidden=!(collapsed||expanded);
|
||||
panel.classList.toggle('is-open',expanded);
|
||||
panel.classList.toggle('is-collapsed',collapsed);
|
||||
@@ -412,10 +428,15 @@ async function _startComposerTerminal(restart=false){
|
||||
async function toggleComposerTerminal(force){
|
||||
const next=typeof force==='boolean'?force:!TERMINAL_UI.open;
|
||||
if(next){
|
||||
const {panel,inner,workspace}= _terminalEls();
|
||||
if(TERMINAL_UI.open){
|
||||
if(TERMINAL_UI.collapsed)expandComposerTerminal();
|
||||
else focusComposerTerminalInput();
|
||||
return;
|
||||
}
|
||||
const {panel,inner}= _terminalEls();
|
||||
const messages=_terminalMessagesEl();
|
||||
if(!panel)return;
|
||||
clearTimeout(TERMINAL_UI.closeTimer);
|
||||
panel.hidden=false;
|
||||
_initTerminalResizeHandle();
|
||||
_resetTerminalHeightForViewport();
|
||||
if(messages)messages.classList.add('terminal-expanding-from-dock');
|
||||
@@ -467,7 +488,6 @@ function expandComposerTerminal(){
|
||||
if(messages)void messages.offsetHeight;
|
||||
_setTerminalChromeState('expanded');
|
||||
_resetTerminalHeightForViewport();
|
||||
_syncTerminalTranscriptSpace(true);
|
||||
requestAnimationFrame(()=>{
|
||||
_fitTerminal();
|
||||
focusComposerTerminalInput();
|
||||
@@ -502,7 +522,7 @@ async function closeComposerTerminal(sessionId,opts){
|
||||
}
|
||||
const {panel}= _terminalEls();
|
||||
if(panel){
|
||||
panel.classList.remove('is-open');
|
||||
panel.classList.remove('is-open','is-collapsed','is-expanding-from-dock');
|
||||
_syncTerminalTranscriptSpace(false);
|
||||
clearTimeout(TERMINAL_UI.closeTimer);
|
||||
TERMINAL_UI.closeTimer=setTimeout(()=>{
|
||||
@@ -515,6 +535,8 @@ async function closeComposerTerminal(sessionId,opts){
|
||||
}
|
||||
TERMINAL_UI.open=false;
|
||||
TERMINAL_UI.collapsed=false;
|
||||
const composerWrap=$('composerWrap');
|
||||
if(composerWrap)composerWrap.classList.remove('terminal-dock-visible');
|
||||
TERMINAL_UI.sessionId=null;
|
||||
TERMINAL_UI.workspace=null;
|
||||
syncTerminalButton();
|
||||
@@ -595,6 +617,10 @@ window.addEventListener('beforeunload',()=>{
|
||||
|
||||
window.addEventListener('resize',()=>{
|
||||
if(!TERMINAL_UI.open)return;
|
||||
if(TERMINAL_UI.collapsed){
|
||||
_syncTerminalTranscriptSpace('collapsed');
|
||||
return;
|
||||
}
|
||||
_resetTerminalHeightForViewport();
|
||||
});
|
||||
|
||||
|
||||
@@ -33,14 +33,129 @@ def test_terminal_surface_uses_composer_flyout_card_pattern():
|
||||
flyout = html.split('<div class="composer-flyout">', 1)[1].split('<div class="queue-pill-outer">', 1)[0]
|
||||
assert 'id="composerTerminalPanel"' in flyout
|
||||
assert 'class="composer-terminal-inner"' in flyout
|
||||
assert 'id="composerTerminalDock"' in flyout
|
||||
assert 'id="terminalResizeHandle"' in flyout
|
||||
assert 'id="composerTerminalPanel"' not in html.split('<div class="queue-pill-outer">', 1)[1]
|
||||
assert ".composer-terminal-panel{position:absolute" in style_css
|
||||
assert "bottom:-24px" in style_css
|
||||
assert "width:min(calc(100% - 64px),720px)" in style_css
|
||||
assert ".composer-terminal-inner{height:260px" in style_css
|
||||
assert ".composer-wrap.terminal-dock-visible .composer-flyout{z-index:4" in style_css
|
||||
assert ".composer-terminal-panel.is-collapsed{bottom:-2px;width:min(calc(100% - 112px),560px);overflow:visible;z-index:4" in style_css
|
||||
assert ".composer-terminal-panel.is-expanding-from-dock .composer-terminal-inner{transition:opacity .18s ease" in style_css
|
||||
assert ".messages.terminal-expanding-from-dock{transition:none!important" in style_css
|
||||
assert ".composer-terminal-dock{min-height:42px" in style_css
|
||||
assert ".composer-terminal-inner{height:var(--composer-terminal-height,260px)" in style_css
|
||||
assert "transform:translateY(100%)" in style_css
|
||||
|
||||
|
||||
def test_terminal_uses_controlled_desktop_resize_handle():
|
||||
html = _read("static/index.html")
|
||||
style_css = _read("static/style.css")
|
||||
terminal_js = _read("static/terminal.js")
|
||||
|
||||
assert 'class="composer-terminal-resize-handle"' in html
|
||||
assert 'role="separator"' in html
|
||||
assert 'aria-orientation="horizontal"' in html
|
||||
terminal_inner_rule = style_css.split(".composer-terminal-inner{", 1)[1].split("}", 1)[0]
|
||||
assert "resize:" not in terminal_inner_rule
|
||||
assert "cursor:ns-resize" in style_css
|
||||
assert "const TERMINAL_HEIGHT_DEFAULT=260" in terminal_js
|
||||
assert "const TERMINAL_HEIGHT_MIN=180" in terminal_js
|
||||
assert "const TERMINAL_HEIGHT_MAX=520" in terminal_js
|
||||
assert "max:Math.max(min,Math.min(hardMax,maxByViewport))" in terminal_js
|
||||
|
||||
|
||||
def test_terminal_resize_path_refits_backend_and_transcript_space():
|
||||
terminal_js = _read("static/terminal.js")
|
||||
|
||||
assert "function _applyTerminalHeight" in terminal_js
|
||||
apply_block = terminal_js.split("function _applyTerminalHeight", 1)[1].split("function _resetTerminalHeightForViewport", 1)[0]
|
||||
assert "_fitTerminal();" in apply_block
|
||||
assert "_syncTerminalTranscriptSpace(true);" in apply_block
|
||||
assert "function _moveTerminalHeightResize" in terminal_js
|
||||
assert "_applyTerminalHeight(TERMINAL_UI.resizeStartHeight+(TERMINAL_UI.resizeStartY-ev.clientY))" in terminal_js
|
||||
assert "handle.addEventListener('pointerdown',_startTerminalHeightResize)" in terminal_js
|
||||
assert "handle.addEventListener('pointermove',_moveTerminalHeightResize)" in terminal_js
|
||||
assert "clearTimeout(TERMINAL_UI.resizeTimer)" in terminal_js
|
||||
assert "api('/api/terminal/resize'" in terminal_js
|
||||
|
||||
|
||||
def test_terminal_open_reserves_transcript_space():
|
||||
style_css = _read("static/style.css")
|
||||
terminal_js = _read("static/terminal.js")
|
||||
|
||||
assert ".messages.terminal-open{padding-bottom:var(--terminal-card-height" in style_css
|
||||
assert ".messages.terminal-collapsed{padding-bottom:var(--terminal-dock-height" in style_css
|
||||
assert "scroll-padding-bottom:var(--terminal-card-height" in style_css
|
||||
assert "classList.add('terminal-open')" in terminal_js
|
||||
assert "classList.add('terminal-collapsed')" in terminal_js
|
||||
assert "classList.remove('terminal-open')" in terminal_js
|
||||
assert "classList.remove('terminal-collapsed')" in terminal_js
|
||||
assert "messages.style.setProperty('--terminal-card-height'" in terminal_js
|
||||
assert "messages.style.setProperty('--terminal-dock-height'" in terminal_js
|
||||
assert "messages.style.removeProperty('--terminal-card-height')" in terminal_js
|
||||
assert "messages.style.removeProperty('--terminal-dock-height')" in terminal_js
|
||||
assert "function _terminalIsMessagesNearBottom" in terminal_js
|
||||
assert "scrollToBottom" in terminal_js
|
||||
|
||||
|
||||
def test_terminal_initial_open_settles_transcript_space_before_reveal():
|
||||
terminal_js = _read("static/terminal.js")
|
||||
|
||||
open_block = terminal_js.split("async function toggleComposerTerminal", 1)[1].split("function collapseComposerTerminal", 1)[0]
|
||||
assert "messages.classList.add('terminal-expanding-from-dock')" in open_block
|
||||
assert "_syncTerminalTranscriptSpace(true,{immediate:true});" in open_block
|
||||
assert "void messages.offsetHeight;" in open_block
|
||||
assert "panel.classList.add('is-open')" in open_block
|
||||
assert "messages.classList.remove('terminal-expanding-from-dock')" in open_block
|
||||
assert open_block.index("_syncTerminalTranscriptSpace(true,{immediate:true});") < open_block.index("panel.classList.add('is-open')")
|
||||
assert open_block.index("void messages.offsetHeight;") < open_block.index("panel.classList.add('is-open')")
|
||||
|
||||
|
||||
def test_terminal_collapsed_state_preserves_pty_and_output_surface():
|
||||
html = _read("static/index.html")
|
||||
terminal_js = _read("static/terminal.js")
|
||||
|
||||
assert 'id="btnTerminalCollapse"' in html
|
||||
assert 'onclick="collapseComposerTerminal()"' in html
|
||||
assert 'id="btnTerminalExpand"' in html
|
||||
assert 'onclick="expandComposerTerminal()"' in html
|
||||
assert 'id="btnTerminalDockClose"' in html
|
||||
assert 'onclick="closeComposerTerminal()"' in html
|
||||
assert "collapsed:false" in terminal_js
|
||||
collapse_block = terminal_js.split("function collapseComposerTerminal", 1)[1].split("function expandComposerTerminal", 1)[0]
|
||||
assert "api('/api/terminal/close'" not in collapse_block
|
||||
assert "_disposeXterm" not in collapse_block
|
||||
assert "_setTerminalChromeState('collapsed')" in collapse_block
|
||||
assert "composerWrap.classList.toggle('terminal-dock-visible',collapsed)" in terminal_js
|
||||
expand_block = terminal_js.split("function expandComposerTerminal", 1)[1].split("function _disposeXterm", 1)[0]
|
||||
assert "_setTerminalChromeState('expanded')" in expand_block
|
||||
assert "panel.classList.add('is-expanding-from-dock')" in expand_block
|
||||
assert "panel.classList.remove('is-expanding-from-dock')" in expand_block
|
||||
assert "messages.classList.add('terminal-expanding-from-dock')" in expand_block
|
||||
assert "messages.classList.remove('terminal-expanding-from-dock')" in expand_block
|
||||
assert "_syncTerminalTranscriptSpace(true,{immediate:true});" in expand_block
|
||||
assert "void messages.offsetHeight;" in expand_block
|
||||
assert expand_block.index("_syncTerminalTranscriptSpace(true,{immediate:true});") < expand_block.index("_setTerminalChromeState('expanded')")
|
||||
assert expand_block.index("void messages.offsetHeight;") < expand_block.index("_setTerminalChromeState('expanded')")
|
||||
assert "_resetTerminalHeightForViewport();" in expand_block
|
||||
assert "focusComposerTerminalInput();" in expand_block
|
||||
close_block = terminal_js.split("async function closeComposerTerminal", 1)[1].split("async function restartComposerTerminal", 1)[0]
|
||||
assert "api('/api/terminal/close'" in close_block
|
||||
assert "_disposeXterm();" in close_block
|
||||
|
||||
|
||||
def test_terminal_slash_command_expands_existing_collapsed_terminal():
|
||||
commands_js = _read("static/commands.js")
|
||||
terminal_js = _read("static/terminal.js")
|
||||
|
||||
assert "await toggleComposerTerminal(true)" in commands_js
|
||||
toggle_block = terminal_js.split("async function toggleComposerTerminal", 1)[1].split("function collapseComposerTerminal", 1)[0]
|
||||
assert "if(TERMINAL_UI.open)" in toggle_block
|
||||
assert "if(TERMINAL_UI.collapsed)expandComposerTerminal();" in toggle_block
|
||||
assert "else focusComposerTerminalInput();" in toggle_block
|
||||
|
||||
|
||||
def test_terminal_v1_does_not_expose_send_to_chat_action():
|
||||
html = _read("static/index.html")
|
||||
terminal_js = _read("static/terminal.js")
|
||||
|
||||
Reference in New Issue
Block a user