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
# 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)
PROJECT_ICONS = [
# Row 1: Folders & Organization

View File

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

View File

@ -24,6 +24,16 @@ from typing import Optional, Set, Dict, List
import logging
from .models import HttpRequest, HttpResponse
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 xml.dom.minidom
@ -118,7 +128,7 @@ class RequestTabWidget(Gtk.Box):
# Horizontal Split: Request | Response
split_pane = Gtk.Paned(orientation=Gtk.Orientation.HORIZONTAL)
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_end_child(False)
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
self.response_main_paned = Gtk.Paned(orientation=Gtk.Orientation.VERTICAL)
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)
# Don't allow results panels to shrink below their minimum size
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
self.results_paned = Gtk.Paned(orientation=Gtk.Orientation.VERTICAL)
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
self.results_paned.set_shrink_start_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
paned = Gtk.Paned(orientation=Gtk.Orientation.VERTICAL)
paned.set_position(300)
paned.set_position(UI_PANE_SCRIPTS_POSITION)
paned.set_vexpand(True)
# Preprocessing Section
@ -942,7 +952,7 @@ class RequestTabWidget(Gtk.Box):
output_text += "\n--- Variables Set ---"
for var_name, var_value in script_result.variable_updates.items():
# 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}'"
# Append warnings to output
@ -983,14 +993,14 @@ class RequestTabWidget(Gtk.Box):
main_height = self.response_main_paned.get_height()
if main_height > 200:
# 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)
results_height = self.results_paned.get_height()
if results_height > 150:
# If preprocessing is visible, share space
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
return False # Don't repeat
@ -1023,7 +1033,7 @@ class RequestTabWidget(Gtk.Box):
output_text += "\n--- Variables Set ---"
for var_name, var_value in preprocessing_result.variable_updates.items():
# 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}'"
# Append warnings to output
@ -1071,7 +1081,7 @@ class RequestTabWidget(Gtk.Box):
main_height = self.response_main_paned.get_height()
if main_height > 200:
# 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)
results_height = self.results_paned.get_height()
@ -1283,7 +1293,7 @@ class RequestTabWidget(Gtk.Box):
GLib.source_remove(self._update_indicators_timeout_id)
# 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):
"""Timeout callback for updating indicators."""

View File

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

View File

@ -23,6 +23,13 @@ from gi.repository import Adw, Gtk, GLib, Gio, GtkSource
from typing import Dict, Optional
import logging
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 .history_manager import HistoryManager
from .project_manager import ProjectManager
@ -239,7 +246,7 @@ class RosterWindow(Adw.ApplicationWindow):
remaining_tabs = len(self.page_to_tab)
if remaining_tabs == 0:
# 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
tab_view.close_page_finish(page, True)
@ -601,7 +608,7 @@ class RosterWindow(Adw.ApplicationWindow):
# Generate name from method and URL
url_parts = request.url.split('/')
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"
if self._is_empty_new_request_tab():
@ -756,7 +763,7 @@ class RosterWindow(Adw.ApplicationWindow):
"""Show a toast notification."""
toast = Adw.Toast()
toast.set_title(message)
toast.set_timeout(3)
toast.set_timeout(UI_TOAST_TIMEOUT_SECONDS)
self.toast_overlay.add_toast(toast)
# Project Management Methods
@ -775,9 +782,9 @@ class RosterWindow(Adw.ApplicationWindow):
if not name or not name.strip():
return False, "Project name cannot be empty"
# Check length (max 100 characters)
if len(name) > 100:
return False, "Project name is too long (max 100 characters)"
# Check length
if len(name) > PROJECT_NAME_MAX_LENGTH:
return False, f"Project name is too long (max {PROJECT_NAME_MAX_LENGTH} characters)"
# Check for invalid characters (file system unsafe characters)
invalid_chars = ['/', '\\', ':', '*', '?', '"', '<', '>', '|', '\0']
@ -805,9 +812,9 @@ class RosterWindow(Adw.ApplicationWindow):
if not name or not name.strip():
return False, "Request name cannot be empty"
# Check length (max 200 characters)
if len(name) > 200:
return False, "Request name is too long (max 200 characters)"
# Check length
if len(name) > REQUEST_NAME_MAX_LENGTH:
return False, f"Request name is too long (max {REQUEST_NAME_MAX_LENGTH} characters)"
# Check for invalid characters (file system unsafe characters)
invalid_chars = ['/', '\\', ':', '*', '?', '"', '<', '>', '|', '\0']