Add history deletion features - clear all in preferences and delete individual items

This commit is contained in:
Pavel Baksy 2025-12-24 20:21:47 +01:00
parent 415907cfb0
commit e8f8efbd09
7 changed files with 109 additions and 5 deletions

View File

@ -78,3 +78,18 @@ class HistoryManager:
entries = entries[:100] entries = entries[:100]
self.save_history(entries) self.save_history(entries)
def delete_entry(self, entry: HistoryEntry):
"""Delete a specific entry from history."""
entries = self.load_history()
# Filter out the entry by comparing timestamps and URLs
entries = [e for e in entries if not (
e.timestamp == entry.timestamp and
e.request.url == entry.request.url and
e.request.method == entry.request.method
)]
self.save_history(entries)
def clear_history(self):
"""Clear all history entries."""
self.save_history([])

View File

@ -68,8 +68,10 @@ class RosterApplication(Adw.Application):
def on_preferences_action(self, widget, _): def on_preferences_action(self, widget, _):
"""Callback for the app.preferences action.""" """Callback for the app.preferences action."""
preferences = PreferencesDialog() window = self.props.active_window
preferences.set_transient_for(self.props.active_window) preferences = PreferencesDialog(history_manager=window.history_manager)
preferences.set_transient_for(window)
preferences.connect('history-cleared', lambda d: window._load_history())
preferences.present() preferences.present()
def on_shortcuts_action(self, widget, _): def on_shortcuts_action(self, widget, _):

View File

@ -43,6 +43,30 @@
</child> </child>
</object> </object>
</child> </child>
<child>
<object class="AdwPreferencesGroup">
<property name="title" translatable="yes">History</property>
<property name="description" translatable="yes">Manage request history</property>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Clear All History</property>
<property name="subtitle" translatable="yes">Remove all saved request and response history</property>
<child>
<object class="GtkButton" id="clear_history_button">
<property name="label" translatable="yes">Clear</property>
<property name="valign">center</property>
<signal name="clicked" handler="on_clear_history_clicked" swapped="no"/>
<style>
<class name="destructive-action"/>
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</object> </object>
</child> </child>
</template> </template>

View File

@ -17,7 +17,7 @@
# #
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
from gi.repository import Adw, Gtk, Gio from gi.repository import Adw, Gtk, Gio, GObject
@Gtk.Template(resource_path='/cz/vesp/roster/preferences-dialog.ui') @Gtk.Template(resource_path='/cz/vesp/roster/preferences-dialog.ui')
@ -26,10 +26,17 @@ class PreferencesDialog(Adw.PreferencesWindow):
tls_verification_row = Gtk.Template.Child() tls_verification_row = Gtk.Template.Child()
timeout_row = Gtk.Template.Child() timeout_row = Gtk.Template.Child()
clear_history_button = Gtk.Template.Child()
def __init__(self, **kwargs): __gsignals__ = {
'history-cleared': (GObject.SIGNAL_RUN_FIRST, None, ())
}
def __init__(self, history_manager=None, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)
self.history_manager = history_manager
# Get settings # Get settings
self.settings = Gio.Settings.new('cz.vesp.roster') self.settings = Gio.Settings.new('cz.vesp.roster')
@ -47,3 +54,30 @@ class PreferencesDialog(Adw.PreferencesWindow):
'value', 'value',
Gio.SettingsBindFlags.DEFAULT Gio.SettingsBindFlags.DEFAULT
) )
@Gtk.Template.Callback()
def on_clear_history_clicked(self, button):
"""Clear all history after confirmation."""
if not self.history_manager:
return
# Create confirmation dialog
dialog = Adw.AlertDialog.new(
"Clear All History?",
"This will permanently delete all saved request and response history. This action cannot be undone."
)
dialog.add_response("cancel", "Cancel")
dialog.add_response("clear", "Clear History")
dialog.set_response_appearance("clear", Adw.ResponseAppearance.DESTRUCTIVE)
dialog.set_default_response("cancel")
dialog.set_close_response("cancel")
def on_response(dialog, response):
if response == "clear":
# Clear the history
self.history_manager.clear_history()
# Notify the main window to refresh
self.emit('history-cleared')
dialog.connect("response", on_response)
dialog.present(self)

View File

@ -62,6 +62,20 @@
</object> </object>
</child> </child>
<!-- Delete Button -->
<child>
<object class="GtkButton" id="delete_button">
<property name="icon-name">user-trash-symbolic</property>
<property name="tooltip-text">Delete this history item</property>
<property name="valign">center</property>
<signal name="clicked" handler="on_delete_clicked" swapped="no"/>
<style>
<class name="flat"/>
<class name="circular"/>
</style>
</object>
</child>
<!-- Click gesture for toggling expansion (only on summary) --> <!-- Click gesture for toggling expansion (only on summary) -->
<child> <child>
<object class="GtkGestureClick" id="click_gesture"> <object class="GtkGestureClick" id="click_gesture">

View File

@ -33,6 +33,7 @@ class HistoryItem(Gtk.Box):
url_label = Gtk.Template.Child() url_label = Gtk.Template.Child()
timestamp_label = Gtk.Template.Child() timestamp_label = Gtk.Template.Child()
status_label = Gtk.Template.Child() status_label = Gtk.Template.Child()
delete_button = Gtk.Template.Child()
request_headers_label = Gtk.Template.Child() request_headers_label = Gtk.Template.Child()
request_body_scroll = Gtk.Template.Child() request_body_scroll = Gtk.Template.Child()
request_body_text = Gtk.Template.Child() request_body_text = Gtk.Template.Child()
@ -48,7 +49,8 @@ class HistoryItem(Gtk.Box):
load_button = Gtk.Template.Child() load_button = Gtk.Template.Child()
__gsignals__ = { __gsignals__ = {
'load-requested': (GObject.SIGNAL_RUN_FIRST, None, ()) 'load-requested': (GObject.SIGNAL_RUN_FIRST, None, ()),
'delete-requested': (GObject.SIGNAL_RUN_FIRST, None, ())
} }
def __init__(self, entry): def __init__(self, entry):
@ -140,6 +142,11 @@ class HistoryItem(Gtk.Box):
"""Emit load signal when load button clicked.""" """Emit load signal when load button clicked."""
self.emit('load-requested') self.emit('load-requested')
@Gtk.Template.Callback()
def on_delete_clicked(self, button):
"""Emit delete signal when delete button clicked."""
self.emit('delete-requested')
@Gtk.Template.Callback() @Gtk.Template.Callback()
def on_request_expander_clicked(self, gesture, n_press, x, y): def on_request_expander_clicked(self, gesture, n_press, x, y):
"""Toggle request body expansion.""" """Toggle request body expansion."""

View File

@ -437,6 +437,7 @@ class RosterWindow(Adw.ApplicationWindow):
for entry in entries: for entry in entries:
item = HistoryItem(entry) item = HistoryItem(entry)
item.connect('load-requested', self._on_history_load_requested, entry) item.connect('load-requested', self._on_history_load_requested, entry)
item.connect('delete-requested', self._on_history_delete_requested, entry)
self.history_listbox.append(item) self.history_listbox.append(item)
def _on_history_load_requested(self, widget, entry): def _on_history_load_requested(self, widget, entry):
@ -444,6 +445,13 @@ class RosterWindow(Adw.ApplicationWindow):
# Smart loading: replaces empty tabs or creates new tab if modified # Smart loading: replaces empty tabs or creates new tab if modified
self._load_request_from_entry(entry) self._load_request_from_entry(entry)
def _on_history_delete_requested(self, widget, entry):
"""Handle delete request from history item."""
# Delete the entry from history
self.history_manager.delete_entry(entry)
# Refresh the history panel
self._load_history()
def _load_request_from_entry(self, entry): def _load_request_from_entry(self, entry):
"""Load request from history entry - smart loading based on current tab state.""" """Load request from history entry - smart loading based on current tab state."""
request = entry.request request = entry.request