Fix variable indicators and add project caching
This commit is contained in:
parent
79c2f3c944
commit
51263816f3
@ -42,25 +42,44 @@ class ProjectManager:
|
||||
self.projects_file = self.data_dir / 'requests.json'
|
||||
self._ensure_data_dir()
|
||||
|
||||
# In-memory cache for projects to reduce disk I/O
|
||||
self._projects_cache: Optional[List[Project]] = None
|
||||
|
||||
def _ensure_data_dir(self):
|
||||
"""Create data directory if it doesn't exist."""
|
||||
self.data_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def load_projects(self) -> List[Project]:
|
||||
"""Load projects from JSON file."""
|
||||
def load_projects(self, force_reload: bool = False) -> List[Project]:
|
||||
"""
|
||||
Load projects from JSON file with in-memory caching.
|
||||
|
||||
Args:
|
||||
force_reload: If True, bypass cache and reload from disk
|
||||
|
||||
Returns:
|
||||
List of Project objects
|
||||
"""
|
||||
# Return cached data if available and not forcing reload
|
||||
if self._projects_cache is not None and not force_reload:
|
||||
return self._projects_cache
|
||||
|
||||
# Load from disk
|
||||
if not self.projects_file.exists():
|
||||
self._projects_cache = []
|
||||
return []
|
||||
|
||||
try:
|
||||
with open(self.projects_file, 'r') as f:
|
||||
data = json.load(f)
|
||||
return [Project.from_dict(p) for p in data.get('projects', [])]
|
||||
self._projects_cache = [Project.from_dict(p) for p in data.get('projects', [])]
|
||||
return self._projects_cache
|
||||
except Exception as e:
|
||||
logger.error(f"Error loading projects: {e}")
|
||||
self._projects_cache = []
|
||||
return []
|
||||
|
||||
def save_projects(self, projects: List[Project]):
|
||||
"""Save projects to JSON file."""
|
||||
"""Save projects to JSON file and update cache."""
|
||||
try:
|
||||
data = {
|
||||
'version': 1,
|
||||
@ -68,6 +87,9 @@ class ProjectManager:
|
||||
}
|
||||
with open(self.projects_file, 'w') as f:
|
||||
json.dump(data, f, indent=2)
|
||||
|
||||
# Update cache with the saved data
|
||||
self._projects_cache = projects
|
||||
except Exception as e:
|
||||
logger.error(f"Error saving projects: {e}")
|
||||
|
||||
|
||||
@ -60,6 +60,7 @@ class RequestTabWidget(Gtk.Box):
|
||||
self.env_separator: Optional[Gtk.Separator] = None
|
||||
self.undefined_variables: Set[str] = set()
|
||||
self._update_indicators_timeout_id: Optional[int] = None
|
||||
self._is_programmatically_changing_environment: bool = False
|
||||
|
||||
# Build the UI
|
||||
self._build_ui()
|
||||
@ -819,6 +820,10 @@ class RequestTabWidget(Gtk.Box):
|
||||
if request.syntax in syntax_options:
|
||||
self.body_language_dropdown.set_selected(syntax_options.index(request.syntax))
|
||||
|
||||
# Update variable indicators after loading the request (if project is set)
|
||||
if self.project_id:
|
||||
self._update_variable_indicators()
|
||||
|
||||
def get_request(self) -> HttpRequest:
|
||||
"""Build and return HttpRequest from current UI state."""
|
||||
method = self.method_dropdown.get_selected_item().get_string()
|
||||
@ -1152,8 +1157,8 @@ class RequestTabWidget(Gtk.Box):
|
||||
self.environment_dropdown.set_enable_search(False)
|
||||
self.environment_dropdown.set_tooltip_text("Select environment for variable substitution")
|
||||
|
||||
# Connect signal
|
||||
self.environment_dropdown.connect("notify::selected", self._on_environment_changed)
|
||||
# Connect signal handler
|
||||
self._env_change_handler_id = self.environment_dropdown.connect("notify::selected", self._on_environment_changed)
|
||||
|
||||
# Add to container at the beginning (left side)
|
||||
container.prepend(self.environment_dropdown)
|
||||
@ -1178,31 +1183,40 @@ class RequestTabWidget(Gtk.Box):
|
||||
if not project:
|
||||
return
|
||||
|
||||
# Build string list with "None" + environment names
|
||||
string_list = Gtk.StringList()
|
||||
string_list.append("None")
|
||||
# Set flag to indicate we're programmatically changing the dropdown
|
||||
# This prevents the signal handler from triggering indicator updates during initialization
|
||||
self._is_programmatically_changing_environment = True
|
||||
|
||||
# Track environment IDs (index 0 is None)
|
||||
self.environment_ids = [None]
|
||||
try:
|
||||
# Build string list with "None" + environment names
|
||||
string_list = Gtk.StringList()
|
||||
string_list.append("None")
|
||||
|
||||
for env in project.environments:
|
||||
string_list.append(env.name)
|
||||
self.environment_ids.append(env.id)
|
||||
# Track environment IDs (index 0 is None)
|
||||
self.environment_ids = [None]
|
||||
|
||||
self.environment_dropdown.set_model(string_list)
|
||||
for env in project.environments:
|
||||
string_list.append(env.name)
|
||||
self.environment_ids.append(env.id)
|
||||
|
||||
# Select current environment
|
||||
if self.selected_environment_id:
|
||||
try:
|
||||
index = self.environment_ids.index(self.selected_environment_id)
|
||||
self.environment_dropdown.set_selected(index)
|
||||
except ValueError:
|
||||
self.environment_dropdown.set_model(string_list)
|
||||
|
||||
# Select current environment
|
||||
if self.selected_environment_id:
|
||||
try:
|
||||
index = self.environment_ids.index(self.selected_environment_id)
|
||||
self.environment_dropdown.set_selected(index)
|
||||
except ValueError:
|
||||
self.environment_dropdown.set_selected(0) # Default to "None"
|
||||
else:
|
||||
self.environment_dropdown.set_selected(0) # Default to "None"
|
||||
else:
|
||||
self.environment_dropdown.set_selected(0) # Default to "None"
|
||||
|
||||
# Update indicators after environment is set
|
||||
self._update_variable_indicators()
|
||||
finally:
|
||||
# Always clear the flag
|
||||
self._is_programmatically_changing_environment = False
|
||||
|
||||
# Note: Don't update indicators here as the request might not be loaded yet
|
||||
# Indicators will be updated when environment changes or request is loaded
|
||||
|
||||
def _show_environment_selector(self):
|
||||
"""Show environment selector (create if it doesn't exist)."""
|
||||
@ -1226,17 +1240,29 @@ class RequestTabWidget(Gtk.Box):
|
||||
# Populate if project_manager is available
|
||||
if self.project_manager:
|
||||
self._populate_environment_dropdown()
|
||||
# Update indicators after environment selector is shown
|
||||
self._update_variable_indicators()
|
||||
|
||||
def _on_environment_changed(self, dropdown, _param):
|
||||
"""Handle environment selection change."""
|
||||
# If we're programmatically changing the environment during population, skip this
|
||||
if self._is_programmatically_changing_environment:
|
||||
return
|
||||
|
||||
if not hasattr(self, 'environment_ids'):
|
||||
logger.warning("Environment changed but environment_ids not initialized")
|
||||
return
|
||||
|
||||
selected_index = dropdown.get_selected()
|
||||
|
||||
if selected_index < len(self.environment_ids):
|
||||
self.selected_environment_id = self.environment_ids[selected_index]
|
||||
# Update visual indicators when environment changes
|
||||
self._update_variable_indicators()
|
||||
else:
|
||||
logger.warning(f"Environment index {selected_index} out of range (max {len(self.environment_ids)-1})")
|
||||
self.selected_environment_id = None
|
||||
|
||||
# Always update visual indicators when environment changes
|
||||
self._update_variable_indicators()
|
||||
|
||||
def get_selected_environment(self):
|
||||
"""Get the currently selected environment object."""
|
||||
@ -1303,6 +1329,10 @@ class RequestTabWidget(Gtk.Box):
|
||||
|
||||
def _update_variable_indicators(self):
|
||||
"""Update visual indicators for undefined variables."""
|
||||
# Only update if we have a project (variables only make sense in project context)
|
||||
if not self.project_id:
|
||||
return
|
||||
|
||||
# Detect undefined variables
|
||||
self.undefined_variables = self._detect_undefined_variables()
|
||||
|
||||
|
||||
@ -64,8 +64,11 @@ class VariableSubstitution:
|
||||
var_name = match.group(1)
|
||||
if var_name in variables:
|
||||
value = variables[var_name]
|
||||
# Replace with value or empty string if value is None/empty
|
||||
return value if value else ""
|
||||
# Check if value is empty/None - treat as undefined for warning purposes
|
||||
if not value:
|
||||
undefined_vars.append(var_name)
|
||||
return ""
|
||||
return value
|
||||
else:
|
||||
# Variable not defined - track it and replace with empty string
|
||||
undefined_vars.append(var_name)
|
||||
|
||||
@ -950,7 +950,8 @@ class RosterWindow(Adw.ApplicationWindow):
|
||||
|
||||
def _on_manage_environments(self, widget, project):
|
||||
"""Show environments management dialog."""
|
||||
# Reload project from disk to get latest data (including variables created by scripts)
|
||||
# Get latest project data (includes variables created by scripts)
|
||||
# Note: load_projects() uses cached data that's kept up-to-date by save operations
|
||||
projects = self.project_manager.load_projects()
|
||||
fresh_project = None
|
||||
for p in projects:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user