Skip to content

refactor(misc): move settings filtering into store/ helper#2514

Merged
m3nu merged 1 commit into
borgbase:masterfrom
ebuzerdrmz44:refactor/misc-tab
Jun 8, 2026
Merged

refactor(misc): move settings filtering into store/ helper#2514
m3nu merged 1 commit into
borgbase:masterfrom
ebuzerdrmz44:refactor/misc-tab

Conversation

@ebuzerdrmz44

Copy link
Copy Markdown
Contributor

Description

This PR addresses the ViewModel extraction for the MiscTab and introduces structural organization for future ViewModels.

Related Issue

#2361 Phase 5 Partially

Motivation and Context

This is part of the ongoing architectural effort to decouple UI from data access logic. Moving the filtering and database logic into ViewModels makes the tabs easier to test without a full PyQt GUI context and reduces code duplication. Creating the viewmodels directory ensures the codebase remains organized as the remaining tabs are refactored during GSoC.

How Has This Been Tested?

Added complete unit tests for MiscTabViewModel in tests/unit/test_misc_tab_viewmodel.py to ensure it successfully retrieves groups, saves settings, and filters legacy keys correctly.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • I have read the CONTRIBUTING guide.
  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

I provide my contribution under the terms of the license of this repository and I affirm the Developer Certificate of Origin.

@ebuzerdrmz44

Copy link
Copy Markdown
Contributor Author

@m3nu could you let me know if this structure looks okay? If so, I'll go ahead and refactor the bigger tabs the same way.

@m3nu m3nu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for picking this up — the Phase 5 direction is right, and getting a clean ViewModel pattern established here is exactly what will make the bigger tabs tractable. Since you're planning to use this as the template for the rest, I'd like to nail the shape before we replicate it. A few things to address:

1. Let the ViewModel own the data/policy logic — not just relay queries.
Right now get_settings_groups() returns the raw Peewee query and save_setting() is unchanged, so the only thing that really moved is the filter loop. Meanwhile the one genuinely data-driven decision — sys.platform != 'darwin' and group.group == 'Updates' — is still in the view. That's the kind of logic the VM should own. Ideally the view asks the VM "what should I render?" and gets back prepared, platform-correct groups + settings, with no DB queries or sys.platform checks left in populate(). That's what makes the abstraction earn its keep (and what makes it testable without a widget).

2. Let's settle what "ViewModel" means in Vorta before it spreads.
As written this is closer to a stateless repository/service than an MVVM ViewModel (no exposed state/commands). That's a legitimate choice — but whichever we pick becomes the convention for ArchiveTab & co., so let's be deliberate. Either lean into a real VM (owns presentation state, exposes the prepared data above), or name it for what it is. Happy to hear your preference.

3. Reconcile with the existing BaseTab persistence helpers.
BaseTab already provides save_profile_attr / bind_profile_attr etc. (from the earlier #2361 work). Adding a separate VM path for settings persistence gives us two mechanisms for "persist a user change." Before the larger tabs get migrated, let's make sure the VM layer composes with BaseTab rather than competing with it.

If you can fold the platform filtering into the VM and make the tests isolated, this becomes a solid template and the bigger refactors will go much more smoothly. Appreciate the work here.

@m3nu

m3nu commented May 31, 2026

Copy link
Copy Markdown
Contributor

Update: the "what does a ViewModel mean here" question from points 1–2 is resolved on #2361 — we're dropping views/viewmodels/ rather than growing it. The substance stands: pull the platform Updates skip + legacy-key filter out of populate() so the view just renders prepared, platform-correct groups — but the home for that is a store/ query helper, not a MiscTabViewModel. So this PR would become: delete the VM class, move that filtering into store/ (near get_misc_settings()), and have the view call it. Details in the #2361 comment above.

@ebuzerdrmz44 ebuzerdrmz44 changed the title Refactor MiscTab to MVVM and reorganize ViewModels refactor(misc): move settings filtering into store/ helper May 31, 2026
@ebuzerdrmz44

Copy link
Copy Markdown
Contributor Author

Thanks , reshaped per your feedback

One judgment call I'd like your read on: I kept save_setting() as a 2-line direct ORM call in the view (the pre-branch pattern). Since it has no behavior beyond get().save(), wrapping it on BaseTab felt like symmetry for its own sake . happy to lift it as save_setting/bind_setting if you'd prefer it unified.

@ebuzerdrmz44 ebuzerdrmz44 requested a review from m3nu May 31, 2026 10:40
Move checkbox grouping, legacy-key filtering, and platform-specific
Updates handling out of MiscTab.populate() into get_grouped_checkbox_settings()
in store/settings.py, with isolated unit tests for the helper.

@m3nu m3nu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔍 Review — move misc settings filtering into a store/ helper

This is exactly the redirect from #2361 (drop the VM, move the platform Updates skip + legacy-key filter into a store/ helper), and it's a faithful extraction. I verified each behavior against the old populate():

  • Legacy-key filter preserved, now O(1) set membership (key not in valid_keys) instead of the linear search(...).
  • Updates-off-darwin behaves identically — get_misc_settings() declares check_for_updates/updates_include_beta only under if sys.platform == 'darwin' (settings.py:144), so off-darwin those keys aren't in valid_keys, the group empties out and is dropped. The platform gating is now data-driven in get_misc_settings() rather than a hardcoded group-name check in the view — cleaner, and the helper docstring documents it.
  • Group order (order_by(group.asc())) preserved; empty/all-legacy groups are now dropped rather than rendered as bare headers (an improvement).

Tests cover alpha order, legacy filtering, Updates-off-darwin, and declared-keys-only. Approving — this supersedes my earlier (pre-reshape) change request.

Re your open question (save_setting)

"I kept save_setting() as a 2-line direct ORM call in the view… happy to lift it as save_setting/bind_setting on BaseTab if you'd prefer."

Keep it in the view — don't lift to BaseTab. The get()/.value=/.save() pattern has no second caller: every other settings write in the views uses a different idiom (SettingsModel.update(...).where(...), e.g. main_window.py:351-354, source_tab.py:264-267). Lifting a single-use method to the base class would be symmetry for its own sake. If a unifying abstraction is ever wanted, the better home is a setter in store/settings.py that reconciles the get().save() vs update().where() split — but that's out of scope here. Non-blocking either way.

@m3nu m3nu merged commit 4a7b0a8 into borgbase:master Jun 8, 2026
4 checks passed
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.

2 participants