Skip to content

feat(qt): persist filter preferences in masternode list#7148

Merged
PastaPastaPasta merged 2 commits intodashpay:developfrom
kwvg:mnlist_filter
Feb 17, 2026
Merged

feat(qt): persist filter preferences in masternode list#7148
PastaPastaPasta merged 2 commits intodashpay:developfrom
kwvg:mnlist_filter

Conversation

@kwvg
Copy link
Collaborator

@kwvg kwvg commented Feb 15, 2026

Additional Information

In response to community feedback to the UI changes done in dash#7116, the following changes have been implemented

  • Banned masternodes are no longer hidden by default (to aid MNOs in knowing the status of their nodes at immediate glance)
  • Persisting filter preferences across restarts (the new layout introduced four different filter options and they'll now be remembered across restarts)

Breaking Changes

None expected.

Checklist

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas (note: N/A)
  • I have added or updated relevant unit/integration/functional/e2e tests (note: N/A)
  • I have made corresponding changes to the documentation (note: N/A)
  • I have assigned this pull request to a milestone (for repository code-owners and collaborators only)

@kwvg kwvg added this to the 24 milestone Feb 15, 2026
@github-actions
Copy link

github-actions bot commented Feb 15, 2026

✅ No Merge Conflicts Detected

This PR currently has no conflicts with other open PRs.

@kwvg kwvg marked this pull request as ready for review February 16, 2026 11:48
@coderabbitai
Copy link

coderabbitai bot commented Feb 16, 2026

Walkthrough

The changes add persistent storage of MasternodeList UI filter preferences using QSettings. The MasternodeList constructor loads saved settings (HideBanned, TypeFilter, FilterText, OwnedOnly) and applies them to the UI and proxy model on startup. Handlers for filter text, type filter, hide-banned, and owned-only now save updates to QSettings. The default m_hide_banned value (and the "Hide banned" checkbox default) is changed from true to false.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as MasternodeList UI
    participant Model as MasternodeListSortFilterProxyModel
    participant Settings as QSettings
    participant Wallet as WalletModel

    User->>UI: Open Masternode list
    UI->>Settings: read(HideBanned, TypeFilter, FilterText, OwnedOnly)
    Settings-->>UI: return saved values
    UI->>Model: apply filters (HideBanned, TypeFilter, FilterText, OwnedOnly)
    UI->>UI: update checkbox/text controls

    alt WalletModel present
        Wallet->>UI: setWalletModel()
        UI->>Settings: read(OwnedOnly)
        Settings-->>UI: return OwnedOnly
        UI->>Model: apply OwnedOnly
    end

    User->>UI: change filter controls
    UI->>Model: update filter
    UI->>Settings: write(updated filter values)
    Settings-->>UI: confirm write
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (94 files):

⚔️ ci/dash/lint-tidy.sh (content)
⚔️ ci/test/04_install.sh (content)
⚔️ doc/descriptors.md (content)
⚔️ src/Makefile.am (content)
⚔️ src/active/context.cpp (content)
⚔️ src/active/context.h (content)
⚔️ src/bench/addrman.cpp (content)
⚔️ src/bench/base58.cpp (content)
⚔️ src/bench/bech32.cpp (content)
⚔️ src/bench/bench.h (content)
⚔️ src/bench/bip324_ecdh.cpp (content)
⚔️ src/bench/block_assemble.cpp (content)
⚔️ src/bench/bls.cpp (content)
⚔️ src/bench/bls_dkg.cpp (content)
⚔️ src/bench/bls_pubkey_agg.cpp (content)
⚔️ src/bench/ccoins_caching.cpp (content)
⚔️ src/bench/chacha20.cpp (content)
⚔️ src/bench/checkblock.cpp (content)
⚔️ src/bench/checkqueue.cpp (content)
⚔️ src/bench/coin_selection.cpp (content)
⚔️ src/bench/crypto_hash.cpp (content)
⚔️ src/bench/duplicate_inputs.cpp (content)
⚔️ src/bench/ecdsa.cpp (content)
⚔️ src/bench/ellswift.cpp (content)
⚔️ src/bench/examples.cpp (content)
⚔️ src/bench/gcs_filter.cpp (content)
⚔️ src/bench/hashpadding.cpp (content)
⚔️ src/bench/load_external.cpp (content)
⚔️ src/bench/lockedpool.cpp (content)
⚔️ src/bench/logging.cpp (content)
⚔️ src/bench/mempool_eviction.cpp (content)
⚔️ src/bench/mempool_stress.cpp (content)
⚔️ src/bench/merkle_root.cpp (content)
⚔️ src/bench/peer_eviction.cpp (content)
⚔️ src/bench/poly1305.cpp (content)
⚔️ src/bench/pool.cpp (content)
⚔️ src/bench/pow_hash.cpp (content)
⚔️ src/bench/prevector.cpp (content)
⚔️ src/bench/rollingbloom.cpp (content)
⚔️ src/bench/rpc_blockchain.cpp (content)
⚔️ src/bench/rpc_mempool.cpp (content)
⚔️ src/bench/strencodings.cpp (content)
⚔️ src/bench/string_cast.cpp (content)
⚔️ src/bench/util_time.cpp (content)
⚔️ src/bench/verify_script.cpp (content)
⚔️ src/bench/wallet_balance.cpp (content)
⚔️ src/bench/wallet_create.cpp (content)
⚔️ src/bench/wallet_loading.cpp (content)
⚔️ src/bitcoin-cli.cpp (content)
⚔️ src/bitcoin-wallet.cpp (content)
⚔️ src/bitcoind.cpp (content)
⚔️ src/init.cpp (content)
⚔️ src/interfaces/chain.h (content)
⚔️ src/llmq/ehf_signals.cpp (content)
⚔️ src/llmq/net_signing.cpp (content)
⚔️ src/llmq/net_signing.h (content)
⚔️ src/llmq/signing_shares.cpp (content)
⚔️ src/llmq/signing_shares.h (content)
⚔️ src/logging.cpp (content)
⚔️ src/logging.h (content)
⚔️ src/net_processing.cpp (content)
⚔️ src/net_processing.h (content)
⚔️ src/node/interfaces.cpp (content)
⚔️ src/qt/forms/masternodelist.ui (content)
⚔️ src/qt/main.cpp (content)
⚔️ src/qt/masternodelist.cpp (content)
⚔️ src/qt/masternodelist.h (content)
⚔️ src/rpc/client.cpp (content)
⚔️ src/rpc/mempool.cpp (content)
⚔️ src/test/fuzz/process_message.cpp (content)
⚔️ src/test/fuzz/process_messages.cpp (content)
⚔️ src/test/fuzz/rpc.cpp (content)
⚔️ src/test/fuzz/string.cpp (content)
⚔️ src/test/util/net.h (content)
⚔️ src/test/util/setup_common.cpp (content)
⚔️ src/util/error.cpp (content)
⚔️ src/util/error.h (content)
⚔️ src/wallet/rpc/backup.cpp (content)
⚔️ src/wallet/rpc/transactions.cpp (content)
⚔️ src/wallet/rpc/util.cpp (content)
⚔️ src/wallet/rpc/wallet.cpp (content)
⚔️ src/wallet/scriptpubkeyman.cpp (content)
⚔️ src/wallet/scriptpubkeyman.h (content)
⚔️ src/wallet/wallet.cpp (content)
⚔️ test/functional/mempool_package_limits.py (content)
⚔️ test/functional/mempool_packages.py (content)
⚔️ test/functional/rpc_getblockfrompeer.py (content)
⚔️ test/functional/rpc_packages.py (content)
⚔️ test/functional/test_framework/util.py (content)
⚔️ test/functional/test_framework/wallet.py (content)
⚔️ test/functional/test_runner.py (content)
⚔️ test/functional/wallet_listsinceblock.py (content)
⚔️ test/functional/wallet_listtransactions.py (content)
⚔️ test/lint/lint-circular-dependencies.py (content)

These conflicts must be resolved before merging into develop.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: persisting filter preferences in the masternode list. It directly relates to the primary objective of the pull request.
Description check ✅ Passed The description is directly related to the changeset, explaining both key changes: unhiding banned nodes by default and persisting filter preferences across restarts.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
⚔️ Resolve merge conflicts (beta)
  • Auto-commit resolved conflicts to branch mnlist_filter
  • Post resolved changes as copyable diffs in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/qt/masternodelist.cpp (1)

336-338: Consider debouncing the QSettings write for filter text.

on_filterText_textChanged fires on every keystroke, creating a QSettings instance and writing each time. While Qt typically batches filesystem writes, this is still unnecessary churn. The other filters (checkbox/combobox) change infrequently, so they're fine — but text input can generate rapid-fire calls.

A lightweight alternative: save the filter text in the destructor or on a short timer, rather than on every character.

@UdjinM6 UdjinM6 modified the milestones: 24, 23.1.1 Feb 16, 2026
Copy link

@UdjinM6 UdjinM6 left a comment

Choose a reason for hiding this comment

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

"hide banned" behavior is a bit broken, pls see bf03f0f

@kwvg kwvg requested a review from UdjinM6 February 16, 2026 15:22
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
src/qt/masternodelist.cpp (3)

143-148: Consider defining settings key names as constants to avoid duplication.

The same string literals ("mnListHideBanned", "mnListTypeFilter", "mnListFilterText", "mnListOwnedOnly") appear in both the load (here) and save (in each handler) paths. Extracting them to constexpr / const variables in the anonymous namespace would prevent silent typo-induced bugs.

Example
namespace {
constexpr int MASTERNODELIST_UPDATE_SECONDS{3};
const QString SETTINGS_KEY_HIDE_BANNED{"mnListHideBanned"};
const QString SETTINGS_KEY_TYPE_FILTER{"mnListTypeFilter"};
const QString SETTINGS_KEY_FILTER_TEXT{"mnListFilterText"};
const QString SETTINGS_KEY_OWNED_ONLY{"mnListOwnedOnly"};
} // anonymous namespace

147-147: Clamp the persisted type-filter index before applying.

QComboBox::setCurrentIndex silently accepts out-of-range values (sets selection to -1). While the downstream slot guards against negative/overflow indices, loading a corrupted setting would leave the combo box with no visible selection. A quick clamp at load time is more defensive.

Proposed fix
-    ui->comboBoxType->setCurrentIndex(settings.value("mnListTypeFilter", 0).toInt());
+    const int type_filter = settings.value("mnListTypeFilter", 0).toInt();
+    if (type_filter >= 0 && type_filter < static_cast<int>(MasternodeListSortFilterProxyModel::TypeFilter::COUNT)) {
+        ui->comboBoxType->setCurrentIndex(type_filter);
+    }

336-338: Filter text is saved on every keystroke.

on_filterText_textChanged fires per character. This is fine for QSettings (writes are cheap and batched on most platforms), but if this ever becomes a concern, debouncing the save — or saving only on focus-out / window close — would be an option.

Copy link

@UdjinM6 UdjinM6 left a comment

Choose a reason for hiding this comment

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

light ACK a653b26

@PastaPastaPasta PastaPastaPasta merged commit 88021a8 into dashpay:develop Feb 17, 2026
43 of 46 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants