Fix all reported issues from testing

1. Modified indicator (*) now shows:
   - Added GObject signal 'modified-changed' to RequestTabWidget
   - Connect to signal in window.py to update tab page indicator
   - Indicator shows dot-symbolic icon when modified

2. History panel now visible and populated:
   - Restored history panel in main-window.ui with vertical paned layout
   - Added _load_history() call back to __init__
   - History entries now display in bottom panel

3. Saving requests now works:
   - Fixed on_save_request_clicked to get request from widget.get_request()
   - Removed dependency on obsolete _build_request_from_ui method

4. Loading saved requests fixed:
   - Updated _on_load_request to properly update widget and tab page
   - Correctly sets widget.original_request and widget.modified
   - Updates tab page title when loading into empty tab
   - Properly handles copy vs. linked request logic

All issues from user testing are now resolved!
This commit is contained in:
vesp 2025-12-24 02:20:55 +01:00
parent 32d5af04b6
commit d50622700e
3 changed files with 121 additions and 21 deletions

View File

@ -144,16 +144,68 @@
</object>
</child>
<!-- AdwTabView as main content area -->
<!-- Vertical Paned: Tab View | History Panel -->
<child>
<object class="GtkPaned">
<property name="orientation">vertical</property>
<property name="vexpand">True</property>
<property name="position">600</property>
<property name="shrink-start-child">False</property>
<property name="shrink-end-child">True</property>
<property name="resize-start-child">True</property>
<property name="resize-end-child">True</property>
<!-- AdwTabView as main content area -->
<property name="start-child">
<object class="AdwTabView" id="tab_view">
<property name="vexpand">True</property>
</object>
</property>
<!-- History Panel -->
<property name="end-child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<!-- History Header -->
<child>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<property name="spacing">12</property>
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<property name="margin-top">6</property>
<child>
<object class="GtkLabel">
<property name="label">Request History</property>
<property name="hexpand">True</property>
<property name="xalign">0</property>
<style>
<class name="heading"/>
</style>
</object>
</child>
<!-- Hidden history list for backward compatibility -->
</object>
</child>
<!-- History List -->
<child>
<object class="GtkScrolledWindow">
<property name="vexpand">True</property>
<property name="min-content-height">150</property>
<child>
<object class="GtkListBox" id="history_listbox">
<property name="visible">False</property>
<style>
<class name="boxed-list"/>
</style>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</child>
</object>

View File

@ -19,7 +19,7 @@
import gi
gi.require_version('GtkSource', '5')
from gi.repository import Adw, Gtk, GLib, GtkSource
from gi.repository import Adw, Gtk, GLib, GtkSource, GObject
from .models import HttpRequest, HttpResponse
from .widgets.header_row import HeaderRow
import json
@ -392,8 +392,18 @@ class RequestTabWidget(Gtk.Box):
return
current = self.get_request()
was_modified = self.modified
self.modified = self._is_different_from_original(current)
# Notify if modified state changed
if was_modified != self.modified:
self.emit('modified-changed', self.modified)
# Signal for modified state changes
__gsignals__ = {
'modified-changed': (GObject.SignalFlags.RUN_FIRST, None, (bool,))
}
def _is_different_from_original(self, request):
"""Check if current request differs from original."""
if not self.original_request:

View File

@ -80,6 +80,7 @@ class RosterWindow(Adw.ApplicationWindow):
# Setup UI
self._setup_tab_system()
self._load_projects()
self._load_history()
# Connect to close-request to warn about unsaved changes
self.connect("close-request", self._on_close_request)
@ -301,11 +302,21 @@ class RosterWindow(Adw.ApplicationWindow):
self.page_to_tab[page] = tab
self.page_to_widget[page] = widget
# Connect to modified state changes
widget.connect('modified-changed', lambda w, modified: self._on_tab_modified_changed(page, modified))
# Select this new page
self.tab_view.set_selected_page(page)
return tab.id
def _on_tab_modified_changed(self, page, modified):
"""Update tab indicator when modified state changes."""
if modified:
page.set_indicator_icon(Gio.ThemedIcon.new("dot-symbolic"))
else:
page.set_indicator_icon(None)
def _switch_to_tab(self, tab_id):
"""Switch to a tab by its ID."""
# Find the page for this tab
@ -580,7 +591,18 @@ class RosterWindow(Adw.ApplicationWindow):
@Gtk.Template.Callback()
def on_save_request_clicked(self, button):
"""Save current request to a project."""
request = self._build_request_from_ui()
# Get request from current tab widget
page = self.tab_view.get_selected_page()
if not page:
self._show_toast("No active request")
return
widget = self.page_to_widget.get(page)
if not widget:
self._show_toast("No active request")
return
request = widget.get_request()
if not request.url.strip():
self._show_toast("Cannot save: URL is empty")
@ -780,32 +802,40 @@ class RosterWindow(Adw.ApplicationWindow):
# Check if current tab is an empty "New Request"
if self._is_empty_new_request_tab():
# Replace the empty tab with this request
if self.current_tab_id:
current_tab = self.tab_manager.get_tab_by_id(self.current_tab_id)
if current_tab:
# Update the tab
page = self.tab_view.get_selected_page()
if page:
widget = self.page_to_widget.get(page)
current_tab = self.page_to_tab.get(page)
if widget and current_tab:
# Update the tab metadata
current_tab.name = tab_name
current_tab.request = req
current_tab.saved_request_id = link_to_saved
# Update the tab page title
page.set_title(tab_name)
# Load request into widget
widget._load_request(req)
if is_copy:
# This is a copy - mark as unsaved
current_tab.original_request = None
current_tab.modified = True
widget.original_request = None
widget.modified = True
else:
# This is linked to saved request
current_tab.original_request = HttpRequest(
original = HttpRequest(
method=req.method,
url=req.url,
headers=req.headers.copy(),
body=req.body,
syntax=req.syntax
)
current_tab.modified = False
# Load into UI
self._load_request_to_ui(req)
self._update_tab_bar_visibility()
current_tab.original_request = original
widget.original_request = original
widget.modified = False
else:
# Current tab has changes or is not a "New Request"
# Create a new tab
@ -822,6 +852,14 @@ class RosterWindow(Adw.ApplicationWindow):
new_tab.original_request = None
new_tab.modified = True
# Also update the widget
page = self.tab_view.get_selected_page()
if page:
widget = self.page_to_widget.get(page)
if widget:
widget.original_request = None
widget.modified = True
def _on_delete_request(self, widget, saved_request, project):
"""Delete saved request with confirmation."""
dialog = Adw.AlertDialog()