Replace magic numbers with named constants

This commit is contained in:
vesp 2026-01-05 11:56:23 +01:00
parent ad80ea66f1
commit c4795b4508
5 changed files with 69 additions and 22 deletions

View File

@ -17,6 +17,34 @@
# #
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
# UI Layout Constants
UI_PANE_REQUEST_RESPONSE_POSITION = 510 # Initial position for request/response split
UI_PANE_RESPONSE_DETAILS_POSITION = 400 # Initial position for response body/headers split
UI_PANE_RESULTS_PANEL_POSITION = 120 # Initial position for script results panel
UI_PANE_SCRIPTS_POSITION = 300 # Initial position for scripts tab panes
UI_SCRIPT_RESULTS_PANEL_HEIGHT = 150 # Height reserved for script results panel
UI_TOAST_TIMEOUT_SECONDS = 3 # Duration to show toast notifications
# Debounce/Delay Timeouts (milliseconds)
DEBOUNCE_VARIABLE_INDICATORS_MS = 500 # Delay before updating variable indicators
DELAY_TAB_CREATION_MS = 50 # Delay before creating new tab after last one closes
# Data Display Limits
DISPLAY_VARIABLE_MAX_LENGTH = 50 # Max characters to display for variable values
DISPLAY_VARIABLE_TRUNCATE_SUFFIX = "..." # Suffix for truncated variable values
DISPLAY_URL_NAME_MAX_LENGTH = 30 # Max characters for URL in generated tab names
# Data Storage Limits
HISTORY_MAX_ENTRIES = 100 # Maximum number of history entries to keep
PROJECT_NAME_MAX_LENGTH = 100 # Maximum length for project names
REQUEST_NAME_MAX_LENGTH = 200 # Maximum length for request names
# HTTP Client Settings
HTTP_DEFAULT_TIMEOUT_SECONDS = 30 # Default timeout for HTTP requests
# Script Execution Settings
SCRIPT_EXECUTION_TIMEOUT_SECONDS = 5 # Maximum execution time for scripts
# 36 symbolic icons for projects (6x6 grid) # 36 symbolic icons for projects (6x6 grid)
PROJECT_ICONS = [ PROJECT_ICONS = [
# Row 1: Folders & Organization # Row 1: Folders & Organization

View File

@ -26,6 +26,7 @@ import gi
gi.require_version('GLib', '2.0') gi.require_version('GLib', '2.0')
from gi.repository import GLib from gi.repository import GLib
from .models import HistoryEntry from .models import HistoryEntry
from .constants import HISTORY_MAX_ENTRIES
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -77,8 +78,8 @@ class HistoryManager:
entries = self.load_history() entries = self.load_history()
entries.insert(0, entry) # Most recent first entries.insert(0, entry) # Most recent first
# Limit history size to 100 entries # Limit history size
entries = entries[:100] entries = entries[:HISTORY_MAX_ENTRIES]
self.save_history(entries) self.save_history(entries)

View File

@ -24,6 +24,16 @@ from typing import Optional, Set, Dict, List
import logging import logging
from .models import HttpRequest, HttpResponse from .models import HttpRequest, HttpResponse
from .widgets.header_row import HeaderRow from .widgets.header_row import HeaderRow
from .constants import (
UI_PANE_REQUEST_RESPONSE_POSITION,
UI_PANE_RESPONSE_DETAILS_POSITION,
UI_PANE_RESULTS_PANEL_POSITION,
UI_PANE_SCRIPTS_POSITION,
UI_SCRIPT_RESULTS_PANEL_HEIGHT,
DEBOUNCE_VARIABLE_INDICATORS_MS,
DISPLAY_VARIABLE_MAX_LENGTH,
DISPLAY_VARIABLE_TRUNCATE_SUFFIX,
)
import json import json
import xml.dom.minidom import xml.dom.minidom
@ -118,7 +128,7 @@ class RequestTabWidget(Gtk.Box):
# Horizontal Split: Request | Response # Horizontal Split: Request | Response
split_pane = Gtk.Paned(orientation=Gtk.Orientation.HORIZONTAL) split_pane = Gtk.Paned(orientation=Gtk.Orientation.HORIZONTAL)
split_pane.set_vexpand(True) split_pane.set_vexpand(True)
split_pane.set_position(510) split_pane.set_position(UI_PANE_REQUEST_RESPONSE_POSITION)
split_pane.set_shrink_start_child(False) split_pane.set_shrink_start_child(False)
split_pane.set_shrink_end_child(False) split_pane.set_shrink_end_child(False)
split_pane.set_resize_start_child(True) split_pane.set_resize_start_child(True)
@ -164,7 +174,7 @@ class RequestTabWidget(Gtk.Box):
# Create a vertical paned for response stack and result panels # Create a vertical paned for response stack and result panels
self.response_main_paned = Gtk.Paned(orientation=Gtk.Orientation.VERTICAL) self.response_main_paned = Gtk.Paned(orientation=Gtk.Orientation.VERTICAL)
self.response_main_paned.set_vexpand(True) self.response_main_paned.set_vexpand(True)
self.response_main_paned.set_position(400) self.response_main_paned.set_position(UI_PANE_RESPONSE_DETAILS_POSITION)
self.response_main_paned.set_shrink_start_child(False) self.response_main_paned.set_shrink_start_child(False)
# Don't allow results panels to shrink below their minimum size # Don't allow results panels to shrink below their minimum size
self.response_main_paned.set_shrink_end_child(False) self.response_main_paned.set_shrink_end_child(False)
@ -228,7 +238,7 @@ class RequestTabWidget(Gtk.Box):
# Create a second paned for preprocessing and script results # Create a second paned for preprocessing and script results
self.results_paned = Gtk.Paned(orientation=Gtk.Orientation.VERTICAL) self.results_paned = Gtk.Paned(orientation=Gtk.Orientation.VERTICAL)
self.results_paned.set_vexpand(True) self.results_paned.set_vexpand(True)
self.results_paned.set_position(120) self.results_paned.set_position(UI_PANE_RESULTS_PANEL_POSITION)
# Don't allow children to shrink below their minimum size # Don't allow children to shrink below their minimum size
self.results_paned.set_shrink_start_child(False) self.results_paned.set_shrink_start_child(False)
self.results_paned.set_shrink_end_child(False) self.results_paned.set_shrink_end_child(False)
@ -474,7 +484,7 @@ class RequestTabWidget(Gtk.Box):
# Vertical paned to separate preprocessing and postprocessing # Vertical paned to separate preprocessing and postprocessing
paned = Gtk.Paned(orientation=Gtk.Orientation.VERTICAL) paned = Gtk.Paned(orientation=Gtk.Orientation.VERTICAL)
paned.set_position(300) paned.set_position(UI_PANE_SCRIPTS_POSITION)
paned.set_vexpand(True) paned.set_vexpand(True)
# Preprocessing Section # Preprocessing Section
@ -942,7 +952,7 @@ class RequestTabWidget(Gtk.Box):
output_text += "\n--- Variables Set ---" output_text += "\n--- Variables Set ---"
for var_name, var_value in script_result.variable_updates.items(): for var_name, var_value in script_result.variable_updates.items():
# Truncate long values for display # Truncate long values for display
display_value = var_value if len(var_value) <= 50 else var_value[:47] + "..." display_value = var_value if len(var_value) <= DISPLAY_VARIABLE_MAX_LENGTH else var_value[:DISPLAY_VARIABLE_MAX_LENGTH - 3] + DISPLAY_VARIABLE_TRUNCATE_SUFFIX
output_text += f"\n>>> {var_name} = '{display_value}'" output_text += f"\n>>> {var_name} = '{display_value}'"
# Append warnings to output # Append warnings to output
@ -983,14 +993,14 @@ class RequestTabWidget(Gtk.Box):
main_height = self.response_main_paned.get_height() main_height = self.response_main_paned.get_height()
if main_height > 200: if main_height > 200:
# Set position to show ~150px of results at the bottom # Set position to show ~150px of results at the bottom
self.response_main_paned.set_position(main_height - 150) self.response_main_paned.set_position(main_height - UI_SCRIPT_RESULTS_PANEL_HEIGHT)
# Adjust results paned to show script output (bottom panel) # Adjust results paned to show script output (bottom panel)
results_height = self.results_paned.get_height() results_height = self.results_paned.get_height()
if results_height > 150: if results_height > 150:
# If preprocessing is visible, share space # If preprocessing is visible, share space
if self.preprocessing_results_container.get_visible(): if self.preprocessing_results_container.get_visible():
self.results_paned.set_position(120) # Give preprocessing minimal space self.results_paned.set_position(UI_PANE_RESULTS_PANEL_POSITION) # Give preprocessing minimal space
# If only script results, the paned will show it automatically # If only script results, the paned will show it automatically
return False # Don't repeat return False # Don't repeat
@ -1023,7 +1033,7 @@ class RequestTabWidget(Gtk.Box):
output_text += "\n--- Variables Set ---" output_text += "\n--- Variables Set ---"
for var_name, var_value in preprocessing_result.variable_updates.items(): for var_name, var_value in preprocessing_result.variable_updates.items():
# Truncate long values for display # Truncate long values for display
display_value = var_value if len(var_value) <= 50 else var_value[:47] + "..." display_value = var_value if len(var_value) <= DISPLAY_VARIABLE_MAX_LENGTH else var_value[:DISPLAY_VARIABLE_MAX_LENGTH - 3] + DISPLAY_VARIABLE_TRUNCATE_SUFFIX
output_text += f"\n>>> {var_name} = '{display_value}'" output_text += f"\n>>> {var_name} = '{display_value}'"
# Append warnings to output # Append warnings to output
@ -1071,7 +1081,7 @@ class RequestTabWidget(Gtk.Box):
main_height = self.response_main_paned.get_height() main_height = self.response_main_paned.get_height()
if main_height > 200: if main_height > 200:
# Set position to show ~150px of results at the bottom # Set position to show ~150px of results at the bottom
self.response_main_paned.set_position(main_height - 150) self.response_main_paned.set_position(main_height - UI_SCRIPT_RESULTS_PANEL_HEIGHT)
# Adjust results paned to show preprocessing output (top panel) # Adjust results paned to show preprocessing output (top panel)
results_height = self.results_paned.get_height() results_height = self.results_paned.get_height()
@ -1283,7 +1293,7 @@ class RequestTabWidget(Gtk.Box):
GLib.source_remove(self._update_indicators_timeout_id) GLib.source_remove(self._update_indicators_timeout_id)
# Schedule new update after 500ms # Schedule new update after 500ms
self._update_indicators_timeout_id = GLib.timeout_add(500, self._update_variable_indicators_timeout) self._update_indicators_timeout_id = GLib.timeout_add(DEBOUNCE_VARIABLE_INDICATORS_MS, self._update_variable_indicators_timeout)
def _update_variable_indicators_timeout(self): def _update_variable_indicators_timeout(self):
"""Timeout callback for updating indicators.""" """Timeout callback for updating indicators."""

View File

@ -24,6 +24,7 @@ import re
from pathlib import Path from pathlib import Path
from typing import Tuple, Optional, Dict, List, TYPE_CHECKING from typing import Tuple, Optional, Dict, List, TYPE_CHECKING
from dataclasses import dataclass, field from dataclasses import dataclass, field
from .constants import SCRIPT_EXECUTION_TIMEOUT_SECONDS
if TYPE_CHECKING: if TYPE_CHECKING:
from .project_manager import ProjectManager from .project_manager import ProjectManager
@ -52,7 +53,7 @@ class ScriptContext:
class ScriptExecutor: class ScriptExecutor:
"""Executes JavaScript code using gjs (GNOME JavaScript).""" """Executes JavaScript code using gjs (GNOME JavaScript)."""
TIMEOUT_SECONDS = 5 TIMEOUT_SECONDS = SCRIPT_EXECUTION_TIMEOUT_SECONDS
@staticmethod @staticmethod
def execute_postprocessing_script( def execute_postprocessing_script(

View File

@ -23,6 +23,13 @@ from gi.repository import Adw, Gtk, GLib, Gio, GtkSource
from typing import Dict, Optional from typing import Dict, Optional
import logging import logging
from .models import HttpRequest, HttpResponse, HistoryEntry, RequestTab from .models import HttpRequest, HttpResponse, HistoryEntry, RequestTab
from .constants import (
UI_TOAST_TIMEOUT_SECONDS,
DELAY_TAB_CREATION_MS,
DISPLAY_URL_NAME_MAX_LENGTH,
PROJECT_NAME_MAX_LENGTH,
REQUEST_NAME_MAX_LENGTH,
)
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
@ -239,7 +246,7 @@ class RosterWindow(Adw.ApplicationWindow):
remaining_tabs = len(self.page_to_tab) remaining_tabs = len(self.page_to_tab)
if remaining_tabs == 0: if remaining_tabs == 0:
# Schedule creating exactly one new tab # Schedule creating exactly one new tab
GLib.timeout_add(50, self._create_new_tab_once) GLib.timeout_add(DELAY_TAB_CREATION_MS, self._create_new_tab_once)
# Close the page # Close the page
tab_view.close_page_finish(page, True) tab_view.close_page_finish(page, True)
@ -601,7 +608,7 @@ class RosterWindow(Adw.ApplicationWindow):
# Generate name from method and URL # Generate name from method and URL
url_parts = request.url.split('/') url_parts = request.url.split('/')
url_name = url_parts[-1] if url_parts else request.url url_name = url_parts[-1] if url_parts else request.url
name = f"{request.method} {url_name[:30]}" if url_name else f"{request.method} Request" name = f"{request.method} {url_name[:DISPLAY_URL_NAME_MAX_LENGTH]}" if url_name else f"{request.method} Request"
# Check if current tab is an empty "New Request" # Check if current tab is an empty "New Request"
if self._is_empty_new_request_tab(): if self._is_empty_new_request_tab():
@ -756,7 +763,7 @@ class RosterWindow(Adw.ApplicationWindow):
"""Show a toast notification.""" """Show a toast notification."""
toast = Adw.Toast() toast = Adw.Toast()
toast.set_title(message) toast.set_title(message)
toast.set_timeout(3) toast.set_timeout(UI_TOAST_TIMEOUT_SECONDS)
self.toast_overlay.add_toast(toast) self.toast_overlay.add_toast(toast)
# Project Management Methods # Project Management Methods
@ -775,9 +782,9 @@ class RosterWindow(Adw.ApplicationWindow):
if not name or not name.strip(): if not name or not name.strip():
return False, "Project name cannot be empty" return False, "Project name cannot be empty"
# Check length (max 100 characters) # Check length
if len(name) > 100: if len(name) > PROJECT_NAME_MAX_LENGTH:
return False, "Project name is too long (max 100 characters)" return False, f"Project name is too long (max {PROJECT_NAME_MAX_LENGTH} characters)"
# Check for invalid characters (file system unsafe characters) # Check for invalid characters (file system unsafe characters)
invalid_chars = ['/', '\\', ':', '*', '?', '"', '<', '>', '|', '\0'] invalid_chars = ['/', '\\', ':', '*', '?', '"', '<', '>', '|', '\0']
@ -805,9 +812,9 @@ class RosterWindow(Adw.ApplicationWindow):
if not name or not name.strip(): if not name or not name.strip():
return False, "Request name cannot be empty" return False, "Request name cannot be empty"
# Check length (max 200 characters) # Check length
if len(name) > 200: if len(name) > REQUEST_NAME_MAX_LENGTH:
return False, "Request name is too long (max 200 characters)" return False, f"Request name is too long (max {REQUEST_NAME_MAX_LENGTH} characters)"
# Check for invalid characters (file system unsafe characters) # Check for invalid characters (file system unsafe characters)
invalid_chars = ['/', '\\', ':', '*', '?', '"', '<', '>', '|', '\0'] invalid_chars = ['/', '\\', ':', '*', '?', '"', '<', '>', '|', '\0']