Skip to content

Implement Save as Preset functionality - #62

Merged
SeamusMullan merged 2 commits into
mainfrom
copilot/implement-preset-save-functionality
Apr 4, 2026
Merged

Implement Save as Preset functionality#62
SeamusMullan merged 2 commits into
mainfrom
copilot/implement-preset-save-functionality

Conversation

Copilot AI commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

save_current_as_preset was a no-op stub — it collected config but never persisted it, always emitting a misleading "Preset saved" status message.

Changes

src/ui/dialogs/save_preset_dialog.py (new)

  • SavePresetDialog: prompts for a preset name (required) and optional description
  • Validates on OK click; shows inline error label for empty/whitespace names
  • preset_name() / description() accessors return trimmed text

src/ui/main_window.py

  • Replaces the stub with the full save flow:
    1. Open SavePresetDialog; early-return on Cancel
    2. collect_configuration() → attach meta dict (name + description)
    3. ConfigManager.save_preset() → XML in ~/.plugin_configurator/presets/
    4. Status bar success message, or QMessageBox.critical on ValueError/unexpected error

src/ui/dialogs/__init__.py

  • Exports SavePresetDialog

tests/test_save_preset_dialog.py (new)

  • 14 tests covering init state, name validation, and accessors
# Before: stub that never saved anything
def save_current_as_preset(self):
    self.collect_configuration()
    self.status_bar.showMessage("Preset saved")

# After: full dialog → validate → serialize → persist flow
def save_current_as_preset(self):
    dialog = SavePresetDialog(parent=self)
    if dialog.exec() != QDialog.DialogCode.Accepted:
        return
    config = self.collect_configuration()
    config["meta"] = {"name": dialog.preset_name(), "description": dialog.description()}
    try:
        self._config_manager.save_preset(config, dialog.preset_name())
        self.status_bar.showMessage(f'Preset "{dialog.preset_name()}" saved successfully')
    except ValueError as exc:
        QMessageBox.critical(self, "Save Failed", f"Could not save preset:\n{exc}")

Copilot AI linked an issue Apr 3, 2026 that may be closed by this pull request
5 tasks
@github-actions

github-actions Bot commented Apr 3, 2026

Copy link
Copy Markdown

📊 PR Summary

Changes Overview

  • Files Changed: 0
  • Python Files: 0
  • Test Files: 0
  • Documentation: 0
  • Added: 0
  • Deleted: 0

CI Checks

This PR will trigger the following checks:

Please ensure all checks pass before merging.

Copilot AI changed the title [WIP] Add functionality to save current configuration as preset Implement Save as Preset functionality Apr 3, 2026
Copilot AI requested a review from SeamusMullan April 3, 2026 18:54
@github-actions

github-actions Bot commented Apr 4, 2026

Copy link
Copy Markdown

📊 PR Summary

Changes Overview

  • Files Changed: 4
  • Python Files: 4
  • Test Files: 1
  • Documentation: 0
  • Added: 2
  • Deleted: 0

CI Checks

This PR will trigger the following checks:

  • ✅ Linting (ruff, isort, black)
  • ✅ Type Checking (mypy)
  • ✅ Tests (pytest)

Please ensure all checks pass before merging.

@SeamusMullan
SeamusMullan marked this pull request as ready for review April 4, 2026 10:10
Copilot AI review requested due to automatic review settings April 4, 2026 10:10
@SeamusMullan
SeamusMullan merged commit 9557530 into main Apr 4, 2026
9 of 11 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements an actual “Save as Preset” workflow in the UI by introducing a dedicated dialog to capture preset metadata and wiring MainWindow.save_current_as_preset() to persist the collected configuration via ConfigManager.save_preset().

Changes:

  • Added SavePresetDialog to collect/validate preset name + optional description.
  • Replaced the previous no-op save_current_as_preset stub with dialog → collect config → persist → user feedback flow.
  • Added a focused test suite for SavePresetDialog validation and accessors.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/ui/dialogs/save_preset_dialog.py New dialog for preset name/description capture and validation.
src/ui/main_window.py Hooks up Save-as-Preset flow to ConfigManager.save_preset() and adds error handling.
src/ui/dialogs/__init__.py Exposes SavePresetDialog from the dialogs package.
tests/test_save_preset_dialog.py Adds tests for dialog initialization, validation behavior, and trimmed accessors.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +80 to +86
def _on_accept(self) -> None:
"""Validate the name field before accepting the dialog."""
if not self._name_edit.text().strip():
self._error_label.setText("Preset name cannot be empty.")
self._error_label.setVisible(True)
self._name_edit.setFocus()
return

Copilot AI Apr 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The preset name is later used as part of the filename (via ConfigManager.save_preset), but the dialog currently only checks for non-empty text. This allows path separators (/, \\) or traversal segments (..) and OS-invalid characters, which can lead to saving outside the presets directory or save failures on some platforms. Add validation to reject/normalize to a safe file stem (e.g., disallow separators and reserved characters) and surface a clear error message to the user.

Copilot uses AI. Check for mistakes.
Comment thread src/ui/main_window.py
Comment on lines +234 to +240
config = self.collect_configuration()
config["meta"] = {"name": preset_name, "description": description}

try:
self._config_manager.save_preset(config, preset_name)
self.status_bar.showMessage(f'Preset "{preset_name}" saved successfully')
except ValueError as exc:

Copilot AI Apr 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Saving a preset will overwrite an existing *.xml with the same name without any confirmation (ElementTree write() overwrites). This is inconsistent with the overwrite confirmation used in PresetManagementDialog._on_import and can cause silent data loss. Before calling save_preset, check whether the target preset file already exists and prompt the user to confirm overwrite (or offer a rename).

Copilot uses AI. Check for mistakes.
@SeamusMullan
SeamusMullan deleted the copilot/implement-preset-save-functionality branch April 4, 2026 10:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[EPIC] Implement Preset Save Functionality

3 participants