|
|
@@ -379,11 +379,14 @@ def test_command_and_chat_inputs_share_a_row(server):
|
|
|
observed["same_row"] = command.region.y == chat.region.y
|
|
|
observed["chat_right"] = chat.region.x > command.region.x
|
|
|
observed["title"] = chat.border_title
|
|
|
+ observed["widths"] = (command.region.width, chat.region.width)
|
|
|
|
|
|
asyncio.run(scenario())
|
|
|
assert observed["same_row"] is True
|
|
|
assert observed["chat_right"] is True
|
|
|
assert observed["title"] == "chat"
|
|
|
+ command_w, chat_w = observed["widths"]
|
|
|
+ assert abs(command_w - chat_w) <= 2, observed["widths"]
|
|
|
|
|
|
|
|
|
def test_empty_command_enter_sends_nothing(server):
|
|
|
@@ -1390,6 +1393,114 @@ def test_maximize_chat_when_triage_disabled(server):
|
|
|
assert observed["restored"] is None
|
|
|
|
|
|
|
|
|
+def test_maximize_chat_keeps_chat_input_at_bottom(server):
|
|
|
+ """Maximizing the conversation keeps only #chat-input, docked at the bottom."""
|
|
|
+ pytest.importorskip("textual")
|
|
|
+ from textual.widgets import Input, RichLog
|
|
|
+
|
|
|
+ from stt_daemon.tui.app import AssistantTUI
|
|
|
+
|
|
|
+ path, _service = server
|
|
|
+ app = AssistantTUI(path, triage_enabled=True)
|
|
|
+ observed: dict = {}
|
|
|
+
|
|
|
+ async def scenario():
|
|
|
+ async with app.run_test(size=(80, 40)) as pilot:
|
|
|
+ await pilot.pause()
|
|
|
+ app._timer.stop()
|
|
|
+ app._drain()
|
|
|
+ app._lower_view = "chat"
|
|
|
+ app.state.ingest({"type": "mode", "mode": "chat"})
|
|
|
+ app.state.ingest({"type": "chat_message", "role": "user", "text": "hi"})
|
|
|
+ app._render()
|
|
|
+ await pilot.pause()
|
|
|
+ app.query_one("#chat", RichLog).focus()
|
|
|
+ await pilot.pause()
|
|
|
+ await pilot.press("m")
|
|
|
+ await pilot.pause()
|
|
|
+ chat = app.query_one("#chat", RichLog)
|
|
|
+ chat_input = app.query_one("#chat-input", Input)
|
|
|
+ command = app.query_one("#command", Input)
|
|
|
+ observed["allow"] = app.ALLOW_IN_MAXIMIZED_VIEW
|
|
|
+ observed["chat_input_display"] = chat_input.display
|
|
|
+ observed["command_display"] = command.display
|
|
|
+ observed["chat_region"] = chat.region
|
|
|
+ observed["input_region"] = chat_input.region
|
|
|
+ observed["input_below_chat"] = chat_input.region.y > chat.region.y
|
|
|
+ observed["input_bottom"] = (
|
|
|
+ chat_input.region.y + chat_input.region.height
|
|
|
+ >= app.screen.size.height - 1
|
|
|
+ )
|
|
|
+ await pilot.press("m")
|
|
|
+ await pilot.pause()
|
|
|
+ observed["restored_allow"] = app.ALLOW_IN_MAXIMIZED_VIEW
|
|
|
+ observed["restored_command"] = command.display
|
|
|
+ observed["restored_chat_input"] = chat_input.display
|
|
|
+
|
|
|
+ asyncio.run(scenario())
|
|
|
+ assert observed["allow"] == "#inputs"
|
|
|
+ assert observed["chat_input_display"] is True
|
|
|
+ assert observed["command_display"] is False
|
|
|
+ assert observed["input_below_chat"] is True, observed
|
|
|
+ assert observed["input_bottom"] is True
|
|
|
+ assert observed["restored_allow"] == ".__never__"
|
|
|
+ assert observed["restored_command"] is True
|
|
|
+ assert observed["restored_chat_input"] is True
|
|
|
+
|
|
|
+
|
|
|
+def test_maximize_output_keeps_command_input_at_bottom(server):
|
|
|
+ """Maximizing the command output keeps only #command, docked at the bottom."""
|
|
|
+ pytest.importorskip("textual")
|
|
|
+ from textual.widgets import Input, RichLog
|
|
|
+
|
|
|
+ from stt_daemon.tui.app import AssistantTUI
|
|
|
+
|
|
|
+ path, _service = server
|
|
|
+ app = AssistantTUI(path, triage_enabled=True)
|
|
|
+ observed: dict = {}
|
|
|
+
|
|
|
+ async def scenario():
|
|
|
+ async with app.run_test(size=(80, 40)) as pilot:
|
|
|
+ await pilot.pause()
|
|
|
+ app._timer.stop()
|
|
|
+ app._drain()
|
|
|
+ app._lower_view = "output"
|
|
|
+ app.state.ingest(
|
|
|
+ {"type": "tool_result", "tool": "get_datetime", "ok": True, "result": "now"}
|
|
|
+ )
|
|
|
+ app._render()
|
|
|
+ await pilot.pause()
|
|
|
+ app.query_one("#output", RichLog).focus()
|
|
|
+ await pilot.pause()
|
|
|
+ await pilot.press("m")
|
|
|
+ await pilot.pause()
|
|
|
+ output = app.query_one("#output", RichLog)
|
|
|
+ command = app.query_one("#command", Input)
|
|
|
+ chat_input = app.query_one("#chat-input", Input)
|
|
|
+ observed["allow"] = app.ALLOW_IN_MAXIMIZED_VIEW
|
|
|
+ observed["command_display"] = command.display
|
|
|
+ observed["chat_input_display"] = chat_input.display
|
|
|
+ observed["input_below_output"] = command.region.y > output.region.y
|
|
|
+ observed["input_bottom"] = (
|
|
|
+ command.region.y + command.region.height >= app.screen.size.height - 1
|
|
|
+ )
|
|
|
+ await pilot.press("m")
|
|
|
+ await pilot.pause()
|
|
|
+ observed["restored_allow"] = app.ALLOW_IN_MAXIMIZED_VIEW
|
|
|
+ observed["restored_command"] = command.display
|
|
|
+ observed["restored_chat_input"] = chat_input.display
|
|
|
+
|
|
|
+ asyncio.run(scenario())
|
|
|
+ assert observed["allow"] == "#inputs"
|
|
|
+ assert observed["command_display"] is True
|
|
|
+ assert observed["chat_input_display"] is False
|
|
|
+ assert observed["input_below_output"] is True, observed
|
|
|
+ assert observed["input_bottom"] is True
|
|
|
+ assert observed["restored_allow"] == ".__never__"
|
|
|
+ assert observed["restored_command"] is True
|
|
|
+ assert observed["restored_chat_input"] is True
|
|
|
+
|
|
|
+
|
|
|
def test_footer_hidden_while_maximized(server):
|
|
|
"""ALLOW_IN_MAXIMIZED_VIEW hides the Footer while a pane is maximized."""
|
|
|
pytest.importorskip("textual")
|