Add Tabbed interface
- Add New Request Button - Implement Tab Management System - Opening saved requests from sidebar creates new tabs - Response Tracking
This commit is contained in:
parent
c9a01bf31e
commit
16a1e0e7ca
@ -96,7 +96,33 @@
|
|||||||
<!-- Main Header Bar -->
|
<!-- Main Header Bar -->
|
||||||
<child>
|
<child>
|
||||||
<object class="AdwHeaderBar">
|
<object class="AdwHeaderBar">
|
||||||
|
<!-- Tab bar container on the left (hidden when only 1 tab) -->
|
||||||
|
<child type="start">
|
||||||
|
<object class="GtkBox" id="tab_bar_container">
|
||||||
|
<property name="orientation">horizontal</property>
|
||||||
|
<property name="spacing">0</property>
|
||||||
|
<property name="visible">False</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<!-- Right side buttons -->
|
||||||
<child type="end">
|
<child type="end">
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="spacing">6</property>
|
||||||
|
|
||||||
|
<!-- New Request Button -->
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="new_request_button">
|
||||||
|
<property name="icon-name">list-add-symbolic</property>
|
||||||
|
<property name="tooltip-text">New Request (Ctrl+T)</property>
|
||||||
|
<style>
|
||||||
|
<class name="flat"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<!-- Main Menu -->
|
||||||
|
<child>
|
||||||
<object class="GtkMenuButton">
|
<object class="GtkMenuButton">
|
||||||
<property name="primary">True</property>
|
<property name="primary">True</property>
|
||||||
<property name="icon-name">open-menu-symbolic</property>
|
<property name="icon-name">open-menu-symbolic</property>
|
||||||
@ -106,6 +132,8 @@
|
|||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
<!-- Main Content -->
|
<!-- Main Content -->
|
||||||
<child>
|
<child>
|
||||||
|
|||||||
@ -34,6 +34,7 @@ roster_sources = [
|
|||||||
'http_client.py',
|
'http_client.py',
|
||||||
'history_manager.py',
|
'history_manager.py',
|
||||||
'project_manager.py',
|
'project_manager.py',
|
||||||
|
'tab_manager.py',
|
||||||
'constants.py',
|
'constants.py',
|
||||||
'icon_picker_dialog.py',
|
'icon_picker_dialog.py',
|
||||||
]
|
]
|
||||||
|
|||||||
@ -150,3 +150,54 @@ class Project:
|
|||||||
created_at=data['created_at'],
|
created_at=data['created_at'],
|
||||||
icon=data.get('icon', 'folder-symbolic') # Default for old data
|
icon=data.get('icon', 'folder-symbolic') # Default for old data
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class RequestTab:
|
||||||
|
"""Represents an open request tab in the UI."""
|
||||||
|
id: str # UUID for tab identification
|
||||||
|
name: str # Display name (from SavedRequest or URL)
|
||||||
|
request: HttpRequest # Current request state
|
||||||
|
response: Optional[HttpResponse] = None # Last response (if sent)
|
||||||
|
saved_request_id: Optional[str] = None # ID if from SavedRequest
|
||||||
|
modified: bool = False # True if has unsaved changes
|
||||||
|
original_request: Optional[HttpRequest] = None # For change detection
|
||||||
|
|
||||||
|
def is_modified(self) -> bool:
|
||||||
|
"""Check if current request differs from original."""
|
||||||
|
if not self.original_request:
|
||||||
|
# New unsaved request - consider modified if has content
|
||||||
|
return bool(self.request.url or self.request.body or self.request.headers)
|
||||||
|
|
||||||
|
return (
|
||||||
|
self.request.method != self.original_request.method or
|
||||||
|
self.request.url != self.original_request.url or
|
||||||
|
self.request.headers != self.original_request.headers or
|
||||||
|
self.request.body != self.original_request.body or
|
||||||
|
self.request.syntax != self.original_request.syntax
|
||||||
|
)
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
"""Convert to dictionary for JSON serialization (for session persistence)."""
|
||||||
|
return {
|
||||||
|
'id': self.id,
|
||||||
|
'name': self.name,
|
||||||
|
'request': self.request.to_dict(),
|
||||||
|
'response': self.response.to_dict() if self.response else None,
|
||||||
|
'saved_request_id': self.saved_request_id,
|
||||||
|
'modified': self.modified,
|
||||||
|
'original_request': self.original_request.to_dict() if self.original_request else None
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, data):
|
||||||
|
"""Create instance from dictionary (for session restoration)."""
|
||||||
|
return cls(
|
||||||
|
id=data['id'],
|
||||||
|
name=data['name'],
|
||||||
|
request=HttpRequest.from_dict(data['request']),
|
||||||
|
response=HttpResponse.from_dict(data['response']) if data.get('response') else None,
|
||||||
|
saved_request_id=data.get('saved_request_id'),
|
||||||
|
modified=data.get('modified', False),
|
||||||
|
original_request=HttpRequest.from_dict(data['original_request']) if data.get('original_request') else None
|
||||||
|
)
|
||||||
|
|||||||
143
src/tab_manager.py
Normal file
143
src/tab_manager.py
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
# tab_manager.py
|
||||||
|
#
|
||||||
|
# Copyright 2025 Pavel Baksy
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
from typing import List, Optional
|
||||||
|
import uuid
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from .models import RequestTab, HttpRequest, HttpResponse
|
||||||
|
|
||||||
|
|
||||||
|
class TabManager:
|
||||||
|
"""Manages open request tabs."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.tabs: List[RequestTab] = []
|
||||||
|
self.active_tab_id: Optional[str] = None
|
||||||
|
|
||||||
|
def create_tab(self, name: str, request: HttpRequest,
|
||||||
|
saved_request_id: Optional[str] = None,
|
||||||
|
response: Optional[HttpResponse] = None) -> RequestTab:
|
||||||
|
"""Create a new tab and add it to the collection."""
|
||||||
|
tab_id = str(uuid.uuid4())
|
||||||
|
|
||||||
|
# Store original request for change detection
|
||||||
|
# Make a copy to avoid reference issues
|
||||||
|
original_request = HttpRequest(
|
||||||
|
method=request.method,
|
||||||
|
url=request.url,
|
||||||
|
headers=request.headers.copy(),
|
||||||
|
body=request.body,
|
||||||
|
syntax=request.syntax
|
||||||
|
) if saved_request_id else None
|
||||||
|
|
||||||
|
tab = RequestTab(
|
||||||
|
id=tab_id,
|
||||||
|
name=name,
|
||||||
|
request=request,
|
||||||
|
response=response,
|
||||||
|
saved_request_id=saved_request_id,
|
||||||
|
modified=False,
|
||||||
|
original_request=original_request
|
||||||
|
)
|
||||||
|
|
||||||
|
self.tabs.append(tab)
|
||||||
|
self.active_tab_id = tab_id
|
||||||
|
|
||||||
|
return tab
|
||||||
|
|
||||||
|
def close_tab(self, tab_id: str) -> bool:
|
||||||
|
"""Close a tab by ID. Returns True if successful."""
|
||||||
|
tab = self.get_tab_by_id(tab_id)
|
||||||
|
if not tab:
|
||||||
|
return False
|
||||||
|
|
||||||
|
self.tabs.remove(tab)
|
||||||
|
|
||||||
|
# Update active tab if we closed the active one
|
||||||
|
if self.active_tab_id == tab_id:
|
||||||
|
if self.tabs:
|
||||||
|
self.active_tab_id = self.tabs[-1].id # Switch to last tab
|
||||||
|
else:
|
||||||
|
self.active_tab_id = None
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get_active_tab(self) -> Optional[RequestTab]:
|
||||||
|
"""Get the currently active tab."""
|
||||||
|
if not self.active_tab_id:
|
||||||
|
return None
|
||||||
|
return self.get_tab_by_id(self.active_tab_id)
|
||||||
|
|
||||||
|
def set_active_tab(self, tab_id: str) -> None:
|
||||||
|
"""Set the active tab by ID."""
|
||||||
|
if self.get_tab_by_id(tab_id):
|
||||||
|
self.active_tab_id = tab_id
|
||||||
|
|
||||||
|
def get_tab_by_id(self, tab_id: str) -> Optional[RequestTab]:
|
||||||
|
"""Get a tab by its ID."""
|
||||||
|
for tab in self.tabs:
|
||||||
|
if tab.id == tab_id:
|
||||||
|
return tab
|
||||||
|
return None
|
||||||
|
|
||||||
|
def has_modified_tabs(self) -> bool:
|
||||||
|
"""Check if any tabs have unsaved changes."""
|
||||||
|
return any(tab.is_modified() for tab in self.tabs)
|
||||||
|
|
||||||
|
def get_tab_index(self, tab_id: str) -> int:
|
||||||
|
"""Get the index of a tab by ID. Returns -1 if not found."""
|
||||||
|
for i, tab in enumerate(self.tabs):
|
||||||
|
if tab.id == tab_id:
|
||||||
|
return i
|
||||||
|
return -1
|
||||||
|
|
||||||
|
def save_session(self, filepath: str) -> None:
|
||||||
|
"""Save all tabs to a JSON file for session persistence."""
|
||||||
|
session_data = {
|
||||||
|
'tabs': [tab.to_dict() for tab in self.tabs],
|
||||||
|
'active_tab_id': self.active_tab_id
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ensure directory exists
|
||||||
|
path = Path(filepath)
|
||||||
|
path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
with open(filepath, 'w') as f:
|
||||||
|
json.dump(session_data, f, indent=2)
|
||||||
|
|
||||||
|
def load_session(self, filepath: str) -> None:
|
||||||
|
"""Load tabs from a JSON file to restore session."""
|
||||||
|
try:
|
||||||
|
with open(filepath, 'r') as f:
|
||||||
|
session_data = json.load(f)
|
||||||
|
|
||||||
|
self.tabs = [RequestTab.from_dict(tab_data) for tab_data in session_data.get('tabs', [])]
|
||||||
|
self.active_tab_id = session_data.get('active_tab_id')
|
||||||
|
|
||||||
|
# Validate active_tab_id still exists
|
||||||
|
if self.active_tab_id and not self.get_tab_by_id(self.active_tab_id):
|
||||||
|
self.active_tab_id = self.tabs[0].id if self.tabs else None
|
||||||
|
|
||||||
|
except (FileNotFoundError, json.JSONDecodeError, KeyError) as e:
|
||||||
|
# If session file is invalid, start fresh
|
||||||
|
print(f"Failed to load session: {e}")
|
||||||
|
self.tabs = []
|
||||||
|
self.active_tab_id = None
|
||||||
163
src/window.py
163
src/window.py
@ -20,10 +20,11 @@
|
|||||||
import gi
|
import gi
|
||||||
gi.require_version('GtkSource', '5')
|
gi.require_version('GtkSource', '5')
|
||||||
from gi.repository import Adw, Gtk, GLib, Gio, GtkSource
|
from gi.repository import Adw, Gtk, GLib, Gio, GtkSource
|
||||||
from .models import HttpRequest, HttpResponse, HistoryEntry
|
from .models import HttpRequest, HttpResponse, HistoryEntry, RequestTab
|
||||||
from .http_client import HttpClient
|
from .http_client import HttpClient
|
||||||
from .history_manager import HistoryManager
|
from .history_manager import HistoryManager
|
||||||
from .project_manager import ProjectManager
|
from .project_manager import ProjectManager
|
||||||
|
from .tab_manager import TabManager
|
||||||
from .icon_picker_dialog import IconPickerDialog
|
from .icon_picker_dialog import IconPickerDialog
|
||||||
from .widgets.header_row import HeaderRow
|
from .widgets.header_row import HeaderRow
|
||||||
from .widgets.history_item import HistoryItem
|
from .widgets.history_item import HistoryItem
|
||||||
@ -32,6 +33,7 @@ from datetime import datetime
|
|||||||
import threading
|
import threading
|
||||||
import json
|
import json
|
||||||
import xml.dom.minidom
|
import xml.dom.minidom
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
|
||||||
@Gtk.Template(resource_path='/cz/vesp/roster/main-window.ui')
|
@Gtk.Template(resource_path='/cz/vesp/roster/main-window.ui')
|
||||||
@ -42,6 +44,8 @@ class RosterWindow(Adw.ApplicationWindow):
|
|||||||
method_dropdown = Gtk.Template.Child()
|
method_dropdown = Gtk.Template.Child()
|
||||||
url_entry = Gtk.Template.Child()
|
url_entry = Gtk.Template.Child()
|
||||||
send_button = Gtk.Template.Child()
|
send_button = Gtk.Template.Child()
|
||||||
|
new_request_button = Gtk.Template.Child()
|
||||||
|
tab_bar_container = Gtk.Template.Child()
|
||||||
|
|
||||||
# Panes
|
# Panes
|
||||||
main_pane = Gtk.Template.Child()
|
main_pane = Gtk.Template.Child()
|
||||||
@ -69,6 +73,13 @@ class RosterWindow(Adw.ApplicationWindow):
|
|||||||
self.http_client = HttpClient()
|
self.http_client = HttpClient()
|
||||||
self.history_manager = HistoryManager()
|
self.history_manager = HistoryManager()
|
||||||
self.project_manager = ProjectManager()
|
self.project_manager = ProjectManager()
|
||||||
|
self.tab_manager = TabManager()
|
||||||
|
|
||||||
|
# Tab tracking - maps tab_id to UI state
|
||||||
|
self.tab_notebook = Gtk.Notebook()
|
||||||
|
self.tab_notebook.set_show_tabs(False) # We'll use custom tab bar
|
||||||
|
self.tab_notebook.set_show_border(False)
|
||||||
|
self.current_tab_id = None
|
||||||
|
|
||||||
# Create window actions
|
# Create window actions
|
||||||
self._create_actions()
|
self._create_actions()
|
||||||
@ -77,6 +88,7 @@ class RosterWindow(Adw.ApplicationWindow):
|
|||||||
self._setup_method_dropdown()
|
self._setup_method_dropdown()
|
||||||
self._setup_request_tabs()
|
self._setup_request_tabs()
|
||||||
self._setup_response_tabs()
|
self._setup_response_tabs()
|
||||||
|
self._setup_tab_system()
|
||||||
self._load_history()
|
self._load_history()
|
||||||
self._load_projects()
|
self._load_projects()
|
||||||
|
|
||||||
@ -86,6 +98,9 @@ class RosterWindow(Adw.ApplicationWindow):
|
|||||||
# Set split pane position to center after window is shown
|
# Set split pane position to center after window is shown
|
||||||
self.connect("map", self._on_window_mapped)
|
self.connect("map", self._on_window_mapped)
|
||||||
|
|
||||||
|
# Create first tab
|
||||||
|
self._create_new_tab()
|
||||||
|
|
||||||
def _on_window_mapped(self, widget):
|
def _on_window_mapped(self, widget):
|
||||||
"""Set split pane position to center when window is mapped."""
|
"""Set split pane position to center when window is mapped."""
|
||||||
# Use idle_add to ensure the widget is fully allocated
|
# Use idle_add to ensure the widget is fully allocated
|
||||||
@ -162,9 +177,109 @@ class RosterWindow(Adw.ApplicationWindow):
|
|||||||
language = language_manager.get_language('xml')
|
language = language_manager.get_language('xml')
|
||||||
buffer.set_language(language)
|
buffer.set_language(language)
|
||||||
|
|
||||||
|
def _setup_tab_system(self):
|
||||||
|
"""Set up the tab system."""
|
||||||
|
# Connect new request button
|
||||||
|
self.new_request_button.connect("clicked", self._on_new_request_clicked)
|
||||||
|
|
||||||
|
def _create_new_tab(self, name="New Request", request=None, saved_request_id=None):
|
||||||
|
"""Create a new tab (simplified version - just clears current request for now)."""
|
||||||
|
# Create tab in tab manager
|
||||||
|
if not request:
|
||||||
|
request = HttpRequest(method="GET", url="", headers={}, body="", syntax="RAW")
|
||||||
|
|
||||||
|
tab = self.tab_manager.create_tab(name, request, saved_request_id)
|
||||||
|
self.current_tab_id = tab.id
|
||||||
|
|
||||||
|
# For simplified version, just load this request into UI
|
||||||
|
self._load_request_to_ui(request)
|
||||||
|
|
||||||
|
# Update tab bar visibility
|
||||||
|
self._update_tab_bar_visibility()
|
||||||
|
|
||||||
|
return tab.id
|
||||||
|
|
||||||
|
def _update_tab_bar_visibility(self):
|
||||||
|
"""Show/hide tab bar based on number of tabs."""
|
||||||
|
num_tabs = len(self.tab_manager.tabs)
|
||||||
|
# Show tab bar only if we have 2 or more tabs
|
||||||
|
self.tab_bar_container.set_visible(num_tabs >= 2)
|
||||||
|
|
||||||
|
# Update tab bar with buttons (simplified - just show count for now)
|
||||||
|
if num_tabs >= 2:
|
||||||
|
# Clear existing children
|
||||||
|
child = self.tab_bar_container.get_first_child()
|
||||||
|
while child:
|
||||||
|
next_child = child.get_next_sibling()
|
||||||
|
self.tab_bar_container.remove(child)
|
||||||
|
child = next_child
|
||||||
|
|
||||||
|
# Add simple tab buttons
|
||||||
|
for tab in self.tab_manager.tabs:
|
||||||
|
tab_btn = Gtk.Button(label=tab.name[:20]) # Truncate long names
|
||||||
|
tab_btn.add_css_class("flat")
|
||||||
|
if tab.id == self.current_tab_id:
|
||||||
|
tab_btn.add_css_class("suggested-action")
|
||||||
|
tab_btn.connect("clicked", lambda btn, tid=tab.id: self._switch_to_tab(tid))
|
||||||
|
self.tab_bar_container.append(tab_btn)
|
||||||
|
|
||||||
|
def _switch_to_tab(self, tab_id):
|
||||||
|
"""Switch to a different tab."""
|
||||||
|
# Save current tab state
|
||||||
|
if self.current_tab_id:
|
||||||
|
current_tab = self.tab_manager.get_tab_by_id(self.current_tab_id)
|
||||||
|
if current_tab:
|
||||||
|
current_tab.request = self._build_request_from_ui()
|
||||||
|
|
||||||
|
# Load new tab
|
||||||
|
tab = self.tab_manager.get_tab_by_id(tab_id)
|
||||||
|
if tab:
|
||||||
|
self.current_tab_id = tab_id
|
||||||
|
self._load_request_to_ui(tab.request)
|
||||||
|
if tab.response:
|
||||||
|
self._display_response(tab.response)
|
||||||
|
self._update_tab_bar_visibility()
|
||||||
|
|
||||||
|
def _load_request_to_ui(self, request):
|
||||||
|
"""Load a request into the UI."""
|
||||||
|
# Set method
|
||||||
|
methods = ["GET", "POST", "PUT", "DELETE"]
|
||||||
|
if request.method in methods:
|
||||||
|
self.method_dropdown.set_selected(methods.index(request.method))
|
||||||
|
|
||||||
|
# Set URL
|
||||||
|
self.url_entry.set_text(request.url)
|
||||||
|
|
||||||
|
# Clear and set headers
|
||||||
|
while child := self.headers_listbox.get_first_child():
|
||||||
|
self.headers_listbox.remove(child)
|
||||||
|
|
||||||
|
for key, value in request.headers.items():
|
||||||
|
self._add_header_row(key, value)
|
||||||
|
|
||||||
|
if not request.headers:
|
||||||
|
self._add_header_row()
|
||||||
|
|
||||||
|
# Set body
|
||||||
|
buffer = self.body_sourceview.get_buffer()
|
||||||
|
buffer.set_text(request.body)
|
||||||
|
|
||||||
|
# Set syntax
|
||||||
|
syntax_options = ["RAW", "JSON", "XML"]
|
||||||
|
if request.syntax in syntax_options:
|
||||||
|
self.body_language_dropdown.set_selected(syntax_options.index(request.syntax))
|
||||||
|
|
||||||
|
def _on_new_request_clicked(self, button):
|
||||||
|
"""Handle New Request button click."""
|
||||||
|
self._create_new_tab()
|
||||||
|
|
||||||
def _create_actions(self):
|
def _create_actions(self):
|
||||||
"""Create window-level actions."""
|
"""Create window-level actions."""
|
||||||
pass
|
# New tab shortcut
|
||||||
|
action = Gio.SimpleAction.new("new-tab", None)
|
||||||
|
action.connect("activate", lambda a, p: self._on_new_request_clicked(None))
|
||||||
|
self.add_action(action)
|
||||||
|
self.get_application().set_accels_for_action("win.new-tab", ["<Control>t"])
|
||||||
|
|
||||||
def _setup_method_dropdown(self):
|
def _setup_method_dropdown(self):
|
||||||
"""Populate HTTP method dropdown."""
|
"""Populate HTTP method dropdown."""
|
||||||
@ -377,6 +492,12 @@ class RosterWindow(Adw.ApplicationWindow):
|
|||||||
self.send_button.set_sensitive(True)
|
self.send_button.set_sensitive(True)
|
||||||
self.send_button.set_label("Send")
|
self.send_button.set_label("Send")
|
||||||
|
|
||||||
|
# Save response to current tab
|
||||||
|
if self.current_tab_id:
|
||||||
|
current_tab = self.tab_manager.get_tab_by_id(self.current_tab_id)
|
||||||
|
if current_tab:
|
||||||
|
current_tab.response = response
|
||||||
|
|
||||||
# Create history entry
|
# Create history entry
|
||||||
entry = HistoryEntry(
|
entry = HistoryEntry(
|
||||||
timestamp=datetime.now().isoformat(),
|
timestamp=datetime.now().isoformat(),
|
||||||
@ -839,39 +960,15 @@ class RosterWindow(Adw.ApplicationWindow):
|
|||||||
dialog.present(self)
|
dialog.present(self)
|
||||||
|
|
||||||
def _on_load_request(self, widget, saved_request):
|
def _on_load_request(self, widget, saved_request):
|
||||||
"""Load saved request into UI (direct load, no warning)."""
|
"""Load saved request in new tab."""
|
||||||
req = saved_request.request
|
req = saved_request.request
|
||||||
|
|
||||||
# Set method
|
# Create a new tab with this request
|
||||||
methods = ["GET", "POST", "PUT", "DELETE"]
|
self._create_new_tab(
|
||||||
if req.method in methods:
|
name=saved_request.name,
|
||||||
self.method_dropdown.set_selected(methods.index(req.method))
|
request=req,
|
||||||
|
saved_request_id=saved_request.id
|
||||||
# Set URL
|
)
|
||||||
self.url_entry.set_text(req.url)
|
|
||||||
|
|
||||||
# Clear headers
|
|
||||||
while child := self.headers_listbox.get_first_child():
|
|
||||||
self.headers_listbox.remove(child)
|
|
||||||
|
|
||||||
# Set headers
|
|
||||||
for key, value in req.headers.items():
|
|
||||||
self._add_header_row(key, value)
|
|
||||||
|
|
||||||
if not req.headers:
|
|
||||||
self._add_header_row()
|
|
||||||
|
|
||||||
# Set body
|
|
||||||
buffer = self.body_sourceview.get_buffer()
|
|
||||||
buffer.set_text(req.body)
|
|
||||||
|
|
||||||
# Restore syntax selection
|
|
||||||
syntax_options = ["RAW", "JSON", "XML"]
|
|
||||||
syntax = getattr(req, 'syntax', 'RAW') # Default to RAW for old requests
|
|
||||||
if syntax in syntax_options:
|
|
||||||
self.body_language_dropdown.set_selected(syntax_options.index(syntax))
|
|
||||||
else:
|
|
||||||
self.body_language_dropdown.set_selected(0) # Default to RAW
|
|
||||||
|
|
||||||
# Switch to headers tab
|
# Switch to headers tab
|
||||||
self.request_stack.set_visible_child_name("headers")
|
self.request_stack.set_visible_child_name("headers")
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user