better text panel ux
This commit is contained in:
@@ -209,3 +209,11 @@ Entry layout: index + timestamp + direction + kind + provider/model header row,
|
|||||||
### UI / Visual Updates
|
### UI / Visual Updates
|
||||||
- The success blink notification on the response text box is now dimmer and more transparent to be less visually jarring.
|
- The success blink notification on the response text box is now dimmer and more transparent to be less visually jarring.
|
||||||
- Added a new floating **Last Script Output** popup window. This window automatically displays and blinks blue whenever the AI executes a PowerShell tool, showing both the executed script and its result in real-time.
|
- Added a new floating **Last Script Output** popup window. This window automatically displays and blinks blue whenever the AI executes a PowerShell tool, showing both the executed script and its result in real-time.
|
||||||
|
|
||||||
|
|
||||||
|
## Recent Changes (Text Viewer Maximization)
|
||||||
|
- **Global Text Viewer (gui.py)**: Added a dedicated, large popup window (win_text_viewer) to allow reading and scrolling through large, dense text blocks without feeling cramped.
|
||||||
|
- **Comms History**: Every multi-line text field in the comms log now has a [+] button next to its label that opens the text in the Global Text Viewer.
|
||||||
|
- **Tool Log History**: Added [+ Script] and [+ Output] buttons next to each logged tool call to easily maximize and read the full executed scripts and raw tool outputs.
|
||||||
|
- **Last Script Output Popup**: Expanded the default size of the popup (now 800x600) and gave the input script panel more vertical space to prevent it from feeling 'scrunched'. Added [+ Maximize] buttons for both the script and the output sections to inspect them in full detail.
|
||||||
|
- **Confirm Dialog**: The script confirmation modal now has a [+ Maximize] button so you can read large generated scripts in full-screen before approving them.
|
||||||
|
|||||||
74
gui.py
74
gui.py
@@ -66,10 +66,20 @@ _NUM_COLOR = (180, 255, 180) # numbers / token counts
|
|||||||
_SUBHDR_COLOR = (220, 200, 120) # sub-section header
|
_SUBHDR_COLOR = (220, 200, 120) # sub-section header
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _show_text_viewer(title: str, text: str):
|
||||||
|
if dpg.does_item_exist("win_text_viewer"):
|
||||||
|
dpg.set_value("text_viewer_content", text if text is not None else "")
|
||||||
|
dpg.configure_item("win_text_viewer", label=f"Text Viewer - {title}", show=True)
|
||||||
|
dpg.focus_item("win_text_viewer")
|
||||||
|
|
||||||
|
|
||||||
def _add_text_field(parent: str, label: str, value: str):
|
def _add_text_field(parent: str, label: str, value: str):
|
||||||
"""Render a labelled text value; long values get a scrollable box."""
|
"""Render a labelled text value; long values get a scrollable box."""
|
||||||
with dpg.group(horizontal=False, parent=parent):
|
with dpg.group(horizontal=False, parent=parent):
|
||||||
dpg.add_text(f"{label}:", color=_LABEL_COLOR)
|
with dpg.group(horizontal=True):
|
||||||
|
dpg.add_text(f"{label}:", color=_LABEL_COLOR)
|
||||||
|
dpg.add_button(label="[+]", callback=lambda s, a, u: _show_text_viewer(label, u), user_data=value)
|
||||||
if len(value) > COMMS_CLAMP_CHARS:
|
if len(value) > COMMS_CLAMP_CHARS:
|
||||||
dpg.add_input_text(
|
dpg.add_input_text(
|
||||||
default_value=value,
|
default_value=value,
|
||||||
@@ -250,7 +260,7 @@ class ConfirmDialog:
|
|||||||
def show(self):
|
def show(self):
|
||||||
"""Called from main thread only. Wrapped in try/except to prevent thread lockups."""
|
"""Called from main thread only. Wrapped in try/except to prevent thread lockups."""
|
||||||
try:
|
try:
|
||||||
w, h = 700, 440
|
w, h = 700, 480
|
||||||
vp_w = dpg.get_viewport_width()
|
vp_w = dpg.get_viewport_width()
|
||||||
vp_h = dpg.get_viewport_height()
|
vp_h = dpg.get_viewport_height()
|
||||||
px = max(0, (vp_w - w) // 2)
|
px = max(0, (vp_w - w) // 2)
|
||||||
@@ -268,6 +278,13 @@ class ConfirmDialog:
|
|||||||
dpg.add_text("The AI wants to run the following PowerShell script:")
|
dpg.add_text("The AI wants to run the following PowerShell script:")
|
||||||
dpg.add_text(f"base_dir: {self._base_dir}", color=(200, 200, 100))
|
dpg.add_text(f"base_dir: {self._base_dir}", color=(200, 200, 100))
|
||||||
dpg.add_separator()
|
dpg.add_separator()
|
||||||
|
with dpg.group(horizontal=True):
|
||||||
|
dpg.add_text("Script:")
|
||||||
|
dpg.add_button(
|
||||||
|
label="[+ Maximize]",
|
||||||
|
user_data=f"{self._tag}_script",
|
||||||
|
callback=lambda s, a, u: _show_text_viewer("Confirm Script", dpg.get_value(u))
|
||||||
|
)
|
||||||
dpg.add_input_text(
|
dpg.add_input_text(
|
||||||
tag=f"{self._tag}_script",
|
tag=f"{self._tag}_script",
|
||||||
default_value=self._script,
|
default_value=self._script,
|
||||||
@@ -702,7 +719,18 @@ class App:
|
|||||||
for i, (script, result) in enumerate(self._tool_log, 1):
|
for i, (script, result) in enumerate(self._tool_log, 1):
|
||||||
with dpg.group(parent="tool_log_scroll"):
|
with dpg.group(parent="tool_log_scroll"):
|
||||||
first_line = script.strip().splitlines()[0][:80] if script.strip() else "(empty)"
|
first_line = script.strip().splitlines()[0][:80] if script.strip() else "(empty)"
|
||||||
dpg.add_text(f"Call #{i}: {first_line}", color=(140, 200, 255))
|
with dpg.group(horizontal=True):
|
||||||
|
dpg.add_text(f"Call #{i}: {first_line}", color=(140, 200, 255))
|
||||||
|
dpg.add_button(
|
||||||
|
label="[+ Script]",
|
||||||
|
user_data=script,
|
||||||
|
callback=lambda s, a, u: _show_text_viewer(f"Call Script", u)
|
||||||
|
)
|
||||||
|
dpg.add_button(
|
||||||
|
label="[+ Output]",
|
||||||
|
user_data=result,
|
||||||
|
callback=lambda s, a, u: _show_text_viewer(f"Call Output", u)
|
||||||
|
)
|
||||||
dpg.add_input_text(
|
dpg.add_input_text(
|
||||||
default_value=result,
|
default_value=result,
|
||||||
multiline=True,
|
multiline=True,
|
||||||
@@ -1738,21 +1766,33 @@ class App:
|
|||||||
label="Last Script Output",
|
label="Last Script Output",
|
||||||
tag="win_script_output",
|
tag="win_script_output",
|
||||||
show=False,
|
show=False,
|
||||||
width=700,
|
width=800,
|
||||||
height=500,
|
height=600,
|
||||||
pos=(100, 100),
|
pos=(100, 100),
|
||||||
no_collapse=True
|
no_collapse=True
|
||||||
):
|
):
|
||||||
dpg.add_text("Script:")
|
with dpg.group(horizontal=True):
|
||||||
|
dpg.add_text("Script:")
|
||||||
|
dpg.add_button(
|
||||||
|
label="[+ Maximize]",
|
||||||
|
user_data="last_script_text",
|
||||||
|
callback=lambda s, a, u: _show_text_viewer("Last Script", dpg.get_value(u))
|
||||||
|
)
|
||||||
dpg.add_input_text(
|
dpg.add_input_text(
|
||||||
tag="last_script_text",
|
tag="last_script_text",
|
||||||
multiline=True,
|
multiline=True,
|
||||||
readonly=True,
|
readonly=True,
|
||||||
width=-1,
|
width=-1,
|
||||||
height=150,
|
height=200,
|
||||||
)
|
)
|
||||||
dpg.add_separator()
|
dpg.add_separator()
|
||||||
dpg.add_text("Output:")
|
with dpg.group(horizontal=True):
|
||||||
|
dpg.add_text("Output:")
|
||||||
|
dpg.add_button(
|
||||||
|
label="[+ Maximize]",
|
||||||
|
user_data="last_script_output",
|
||||||
|
callback=lambda s, a, u: _show_text_viewer("Last Output", dpg.get_value(u))
|
||||||
|
)
|
||||||
dpg.add_input_text(
|
dpg.add_input_text(
|
||||||
tag="last_script_output",
|
tag="last_script_output",
|
||||||
multiline=True,
|
multiline=True,
|
||||||
@@ -1761,6 +1801,24 @@ class App:
|
|||||||
height=-1,
|
height=-1,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# ---- Global Text Viewer Popup ----
|
||||||
|
with dpg.window(
|
||||||
|
label="Text Viewer",
|
||||||
|
tag="win_text_viewer",
|
||||||
|
show=False,
|
||||||
|
width=900,
|
||||||
|
height=700,
|
||||||
|
pos=(150, 150),
|
||||||
|
no_collapse=True
|
||||||
|
):
|
||||||
|
dpg.add_input_text(
|
||||||
|
tag="text_viewer_content",
|
||||||
|
multiline=True,
|
||||||
|
readonly=True,
|
||||||
|
width=-1,
|
||||||
|
height=-1,
|
||||||
|
)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
dpg.create_context()
|
dpg.create_context()
|
||||||
dpg.configure_app(docking=True, docking_space=True, init_file="dpg_layout.ini")
|
dpg.configure_app(docking=True, docking_space=True, init_file="dpg_layout.ini")
|
||||||
|
|||||||
@@ -111,8 +111,8 @@ history = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[discussion.discussions."Misc UX improvements"]
|
[discussion.discussions."Misc UX improvements"]
|
||||||
git_commit = "813297c0994f408e070dc6fc981c42fb09557ec0"
|
git_commit = "954efdec740036b76144af50ce0c7a0553d476d8"
|
||||||
last_updated = "2026-02-21T23:24:38"
|
last_updated = "2026-02-21T23:27:56"
|
||||||
history = [
|
history = [
|
||||||
"@2026-02-21T23:03:51\nUser:\nMake the namespace for the generated markdown file the projet name instead of that specific namespace in the config panel.\nThe ouptut dir can be in the project panel spec (that way we can just remove config panel entirely).",
|
"@2026-02-21T23:03:51\nUser:\nMake the namespace for the generated markdown file the projet name instead of that specific namespace in the config panel.\nThe ouptut dir can be in the project panel spec (that way we can just remove config panel entirely).",
|
||||||
"@2026-02-21T23:04:55\nAI:\nI have applied the changes to streamline the project settings and remove the old Config panel completely:\n\n1. **GUI Layout Changes (`gui.py`)**:\n - The `Config` panel has been completely removed.\n - The **Output Dir** field has been moved into the **Projects** panel (right above the Project Files list).\n - The **Auto-add history** checkbox has been moved to the top of the **Discussion History** panel (directly under the entry toolbar buttons).\n - The **Files** panel was shifted upward to reclaim the space left behind by the old Config panel.\n\n2. **Namespace Management (`aggregate.py` & `project_manager.py`)**:\n - The explicitly defined `namespace` field is gone.\n - Instead, `aggregate.py` now directly infers the output markdown file namespace from the active project's `name` property. (e.g., saving under the `manual_slop` project will just prefix the markdown with `manual_slop_001.md`).\n - `project_manager.py` was updated to no longer scaffold out `namespace` strings into new `.toml` files, and `flat_config` now injects the core `project` dictionary segment so the generators can access the internal name.\n\n3. **`MainContext.md` Updated**:\n - I have updated the markdown file with the latest layout structures and explained that `namespace` is no longer a configurable setting but dynamically determined by the project profile.\n\nYou'll need to restart the application for the GUI layout and DearPyGUI state changes to take effect! Let me know how it looks.",
|
"@2026-02-21T23:04:55\nAI:\nI have applied the changes to streamline the project settings and remove the old Config panel completely:\n\n1. **GUI Layout Changes (`gui.py`)**:\n - The `Config` panel has been completely removed.\n - The **Output Dir** field has been moved into the **Projects** panel (right above the Project Files list).\n - The **Auto-add history** checkbox has been moved to the top of the **Discussion History** panel (directly under the entry toolbar buttons).\n - The **Files** panel was shifted upward to reclaim the space left behind by the old Config panel.\n\n2. **Namespace Management (`aggregate.py` & `project_manager.py`)**:\n - The explicitly defined `namespace` field is gone.\n - Instead, `aggregate.py` now directly infers the output markdown file namespace from the active project's `name` property. (e.g., saving under the `manual_slop` project will just prefix the markdown with `manual_slop_001.md`).\n - `project_manager.py` was updated to no longer scaffold out `namespace` strings into new `.toml` files, and `flat_config` now injects the core `project` dictionary segment so the generators can access the internal name.\n\n3. **`MainContext.md` Updated**:\n - I have updated the markdown file with the latest layout structures and explained that `namespace` is no longer a configurable setting but dynamically determined by the project profile.\n\nYou'll need to restart the application for the GUI layout and DearPyGUI state changes to take effect! Let me know how it looks.",
|
||||||
@@ -120,4 +120,6 @@ history = [
|
|||||||
"@2026-02-21T23:13:12\nAI:\nI have implemented both requests to improve the feedback you receive from the application:\n\n1. **Script Output Popup (`gui.py`)**: \n - I added a new `Last Script Output` window. \n - Whenever the AI runs a PowerShell tool (after you approve it), this window will automatically pop up (or come to the front if it's already open).\n - It contains two scrollable text boxes: one showing the exact script that was executed, and the other showing the stdout/stderr result.\n - The text boxes within this popup will flash a **dim blue** colour a few times to visually alert you that a background script execution just completed.\n\n2. **Dimmer Green Blink (`gui.py`)**: \n - I modified the retro arcade blink effect for the main AI response notification. \n - The alpha (transparency) of the green overlay has been reduced significantly (from `120` down to `50`), making it much softer and less glaring on the eyes.\n\nI have also updated `MainContext.md` to document these new UI feedback features! You will need to restart the application to see the new popup and the updated blink intensities. Let me know if the colours need any further tweaking.",
|
"@2026-02-21T23:13:12\nAI:\nI have implemented both requests to improve the feedback you receive from the application:\n\n1. **Script Output Popup (`gui.py`)**: \n - I added a new `Last Script Output` window. \n - Whenever the AI runs a PowerShell tool (after you approve it), this window will automatically pop up (or come to the front if it's already open).\n - It contains two scrollable text boxes: one showing the exact script that was executed, and the other showing the stdout/stderr result.\n - The text boxes within this popup will flash a **dim blue** colour a few times to visually alert you that a background script execution just completed.\n\n2. **Dimmer Green Blink (`gui.py`)**: \n - I modified the retro arcade blink effect for the main AI response notification. \n - The alpha (transparency) of the green overlay has been reduced significantly (from `120` down to `50`), making it much softer and less glaring on the eyes.\n\nI have also updated `MainContext.md` to document these new UI feedback features! You will need to restart the application to see the new popup and the updated blink intensities. Let me know if the colours need any further tweaking.",
|
||||||
"@2026-02-21T23:15:02\nUser:\nAdd support for web-searching as a tool if not already available. This should be chainable so that the ai agent can utilize info gathered for cloning repos, downloading, content, etc.",
|
"@2026-02-21T23:15:02\nUser:\nAdd support for web-searching as a tool if not already available. This should be chainable so that the ai agent can utilize info gathered for cloning repos, downloading, content, etc.",
|
||||||
"@2026-02-21T23:16:55\nAI:\nI have added support for web searching and URL fetching directly into the AI's toolset. \n\nI implemented this using only Python's standard library (`urllib` and `html.parser`) so you **do not** need to install any extra external packages (like `beautifulsoup4` or `duckduckgo-search`). This keeps the application lightweight and fast.\n\n### Changes made:\n1. **`mcp_client.py` updated with two new tools:**\n - `web_search(query)`: Queries DuckDuckGo's HTML endpoint and returns the top 5 results, including titles, URLs, and text snippets.\n - `fetch_url(url)`: Downloads a webpage, strips out the HTML, scripts, and styling, and returns the raw readable text content. It automatically truncates extremely large pages to prevent token bloat, and handles DDG redirect URLs seamlessly.\n\n2. **`ai_client.py` updated:**\n - I updated the `_SYSTEM_PROMPT` to let the AI know it now has `web access: web_search, fetch_url` alongside the local file tools.\n - Because `ai_client.py` builds the provider tool schemas dynamically from `mcp_client.MCP_TOOL_SPECS`, both Anthropic and Gemini will automatically see and be able to use these new web tools.\n\nYou will need to restart the application for the new tools to be fully registered in the session! \n\nYou can try it out by asking something like: _\"Search the web for the latest LangChain documentation and summarize it.\"_",
|
"@2026-02-21T23:16:55\nAI:\nI have added support for web searching and URL fetching directly into the AI's toolset. \n\nI implemented this using only Python's standard library (`urllib` and `html.parser`) so you **do not** need to install any extra external packages (like `beautifulsoup4` or `duckduckgo-search`). This keeps the application lightweight and fast.\n\n### Changes made:\n1. **`mcp_client.py` updated with two new tools:**\n - `web_search(query)`: Queries DuckDuckGo's HTML endpoint and returns the top 5 results, including titles, URLs, and text snippets.\n - `fetch_url(url)`: Downloads a webpage, strips out the HTML, scripts, and styling, and returns the raw readable text content. It automatically truncates extremely large pages to prevent token bloat, and handles DDG redirect URLs seamlessly.\n\n2. **`ai_client.py` updated:**\n - I updated the `_SYSTEM_PROMPT` to let the AI know it now has `web access: web_search, fetch_url` alongside the local file tools.\n - Because `ai_client.py` builds the provider tool schemas dynamically from `mcp_client.MCP_TOOL_SPECS`, both Anthropic and Gemini will automatically see and be able to use these new web tools.\n\nYou will need to restart the application for the new tools to be fully registered in the session! \n\nYou can try it out by asking something like: _\"Search the web for the latest LangChain documentation and summarize it.\"_",
|
||||||
|
"@2026-02-21T23:24:38\nUser:\n1. Make all script text panels maximizable, or as a main focus window.\n a. This is useful for the comms history so that we can see the full text via scroll easier\n b. Could just be a focused larger panel pop-up that we can close on the fly. Will update with any other text panel maximized of that type.\n2. For the last script run popup, make that input script panel resizable as its kinda scrunched, should also be maximizable between it and output.\n",
|
||||||
|
"@2026-02-21T23:27:41\nAI:\nI have implemented the requested functionality for maximizing text panels.\n\n### 1. Global Text Viewer\nI added a new dedicated global popup called **Text Viewer** (`win_text_viewer`) to DearPyGUI. This popup is large (900x700 by default) and contains a multiline readonly input field explicitly designed for scrolling and reading massive chunks of text or code without constraints.\n\n### 2. Comms History & Text Panels\nEvery significant text field that usually gets clamped into a tiny box now has a `[+]` or `[+ Maximize]` button next to its label:\n- **Comms History**: All large payloads (like JSON text blocks, request prompts, or raw tool strings) have a `[+]` button next to their name.\n- **Tool Calls History**: I added `[+ Script]` and `[+ Output]` next to every command executed in the tool log, so you can easily review the full output of a historic tool call.\n- **Confirm Dialog**: The prompt where you approve PowerShell scripts now has a `[+ Maximize]` button next to \"Script\", so if I generate a massive script, you can easily inspect the whole file before clicking Approve.\n\n### 3. Last Script Output Popup\nI made several quality-of-life adjustments to this popup as requested:\n- **Larger dimensions**: The popup is now 800x600 by default (previously 700x500).\n- **Expanded Input script panel**: The script input box now has a height of 200px (up from 150px) so it's far less scrunched.\n- **Maximizable**: Both the \"Script\" and \"Output\" labels now feature a `[+ Maximize]` button, meaning you can instantly open either pane inside the massive Global Text Viewer.\n\n`MainContext.md` has been successfully updated with the details of these new features. You will need to restart the application to interact with the new maximize buttons and the updated Text Viewer UI! Let me know if any other UI elements need more space.",
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user