feat(hooks): extend ApiHookClient and GUI for tab/listbox control
This commit is contained in:
@@ -83,3 +83,34 @@ class ApiHookClient:
|
||||
|
||||
def post_gui(self, gui_data):
|
||||
return self._make_request('POST', '/api/gui', data=gui_data)
|
||||
|
||||
def select_tab(self, tab_bar, tab):
|
||||
"""Tells the GUI to switch to a specific tab in a tab bar."""
|
||||
return self.post_gui({
|
||||
"action": "select_tab",
|
||||
"tab_bar": tab_bar,
|
||||
"tab": tab
|
||||
})
|
||||
|
||||
def select_list_item(self, listbox, item_value):
|
||||
"""Tells the GUI to select an item in a listbox by its value."""
|
||||
return self.post_gui({
|
||||
"action": "select_list_item",
|
||||
"listbox": listbox,
|
||||
"item_value": item_value
|
||||
})
|
||||
|
||||
def set_value(self, item, value):
|
||||
"""Sets the value of a GUI item."""
|
||||
return self.post_gui({
|
||||
"action": "set_value",
|
||||
"item": item,
|
||||
"value": value
|
||||
})
|
||||
|
||||
def click(self, item):
|
||||
"""Simulates a click on a GUI button or item."""
|
||||
return self.post_gui({
|
||||
"action": "click",
|
||||
"item": item
|
||||
})
|
||||
|
||||
29
gui.py
29
gui.py
@@ -2100,10 +2100,10 @@ class App:
|
||||
height=200,
|
||||
)
|
||||
with dpg.group(horizontal=True):
|
||||
dpg.add_button(label="Gen + Send", callback=self.cb_generate_send)
|
||||
dpg.add_button(label="MD Only", callback=self.cb_md_only)
|
||||
dpg.add_button(label="Reset", callback=self.cb_reset_session)
|
||||
dpg.add_button(label="-> History", callback=self.cb_append_message_to_history)
|
||||
dpg.add_button(label="Gen + Send", tag="btn_gen_send", callback=self.cb_generate_send)
|
||||
dpg.add_button(label="MD Only", tag="btn_md_only", callback=self.cb_md_only)
|
||||
dpg.add_button(label="Reset", tag="btn_reset", callback=self.cb_reset_session)
|
||||
dpg.add_button(label="-> History", tag="btn_to_history", callback=self.cb_append_message_to_history)
|
||||
|
||||
with dpg.tab(label="AI Response"):
|
||||
dpg.add_input_text(
|
||||
@@ -2133,8 +2133,8 @@ class App:
|
||||
dpg.add_spacer(width=20)
|
||||
dpg.add_text("LIVE", tag="operations_live_indicator", color=(100, 255, 100), show=False)
|
||||
|
||||
with dpg.tab_bar():
|
||||
with dpg.tab(label="Comms Log"):
|
||||
with dpg.tab_bar(tag="operations_tabs"):
|
||||
with dpg.tab(label="Comms Log", tag="tab_comms"):
|
||||
with dpg.group(horizontal=True):
|
||||
dpg.add_text("Status: idle", tag="ai_status", color=(200, 220, 160))
|
||||
dpg.add_spacer(width=16)
|
||||
@@ -2148,7 +2148,7 @@ class App:
|
||||
with dpg.child_window(tag="comms_scroll", height=-1, border=False, horizontal_scrollbar=True):
|
||||
pass
|
||||
|
||||
with dpg.tab(label="Tool Log"):
|
||||
with dpg.tab(label="Tool Log", tag="tab_tool"):
|
||||
with dpg.group(horizontal=True):
|
||||
dpg.add_text("Tool call history")
|
||||
dpg.add_button(label="Clear", callback=self.cb_clear_tool_log)
|
||||
@@ -2305,6 +2305,21 @@ class App:
|
||||
cb = dpg.get_item_callback(item)
|
||||
if cb:
|
||||
cb()
|
||||
elif action == "select_tab":
|
||||
tab_bar = task.get("tab_bar")
|
||||
tab = task.get("tab")
|
||||
if tab_bar and dpg.does_item_exist(tab_bar):
|
||||
dpg.set_value(tab_bar, tab)
|
||||
elif action == "select_list_item":
|
||||
listbox = task.get("listbox")
|
||||
val = task.get("item_value")
|
||||
if listbox and dpg.does_item_exist(listbox):
|
||||
dpg.set_value(listbox, val)
|
||||
cb = dpg.get_item_callback(listbox)
|
||||
if cb:
|
||||
# Dear PyGui callbacks for listbox usually receive (sender, app_data, user_data)
|
||||
# app_data is the selected value.
|
||||
cb(listbox, val)
|
||||
elif action == "refresh_api_metrics":
|
||||
self._refresh_api_metrics(task.get("payload", {}))
|
||||
except Exception as e:
|
||||
|
||||
68
tests/test_api_hook_extensions.py
Normal file
68
tests/test_api_hook_extensions.py
Normal file
@@ -0,0 +1,68 @@
|
||||
import pytest
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Ensure project root is in path for imports
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
|
||||
from api_hook_client import ApiHookClient
|
||||
|
||||
def test_api_client_has_extensions():
|
||||
client = ApiHookClient()
|
||||
# These should fail initially as they are not implemented
|
||||
assert hasattr(client, 'select_tab')
|
||||
assert hasattr(client, 'select_list_item')
|
||||
|
||||
def test_select_tab_integration(live_gui):
|
||||
client = ApiHookClient()
|
||||
# We'll need to make sure the tags exist in gui.py
|
||||
# For now, this is a placeholder for the integration test
|
||||
response = client.select_tab("operations_tabs", "tab_tool")
|
||||
assert response == {'status': 'queued'}
|
||||
|
||||
def test_select_list_item_integration(live_gui):
|
||||
client = ApiHookClient()
|
||||
# Assuming 'Default' discussion exists or we can just test that it queues
|
||||
response = client.select_list_item("disc_listbox", "Default")
|
||||
assert response == {'status': 'queued'}
|
||||
|
||||
def test_app_processes_new_actions():
|
||||
import gui
|
||||
from unittest.mock import MagicMock, patch
|
||||
import dearpygui.dearpygui as dpg
|
||||
|
||||
dpg.create_context()
|
||||
try:
|
||||
with patch('gui.load_config', return_value={}), \
|
||||
patch('gui.PerformanceMonitor'), \
|
||||
patch('gui.shell_runner'), \
|
||||
patch('gui.project_manager'), \
|
||||
patch.object(gui.App, '_load_active_project'):
|
||||
app = gui.App()
|
||||
|
||||
with patch('dearpygui.dearpygui.set_value') as mock_set_value, \
|
||||
patch('dearpygui.dearpygui.does_item_exist', return_value=True), \
|
||||
patch('dearpygui.dearpygui.get_item_callback') as mock_get_cb:
|
||||
|
||||
# Test select_tab
|
||||
app._pending_gui_tasks.append({
|
||||
"action": "select_tab",
|
||||
"tab_bar": "some_tab_bar",
|
||||
"tab": "some_tab"
|
||||
})
|
||||
app._process_pending_gui_tasks()
|
||||
mock_set_value.assert_any_call("some_tab_bar", "some_tab")
|
||||
|
||||
# Test select_list_item
|
||||
mock_cb = MagicMock()
|
||||
mock_get_cb.return_value = mock_cb
|
||||
app._pending_gui_tasks.append({
|
||||
"action": "select_list_item",
|
||||
"listbox": "some_listbox",
|
||||
"item_value": "some_value"
|
||||
})
|
||||
app._process_pending_gui_tasks()
|
||||
mock_set_value.assert_any_call("some_listbox", "some_value")
|
||||
mock_cb.assert_called_with("some_listbox", "some_value")
|
||||
finally:
|
||||
dpg.destroy_context()
|
||||
Reference in New Issue
Block a user