From 64e0b2bbeeefff048fa3cc95f5602499af8dbd8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Br=C3=BCbach?= Date: Sat, 19 Sep 2026 07:47:21 +0200 Subject: [PATCH] [DeckStorage] Summarize batch publish failures when the batch drains Each rejected node stacked its own modal dialog, so publishing a ten-deck selection against a rejecting server made the user dismiss ten dialogs one at a time. Failures are now collected while the batch is in flight and shown as a single summary when the visibility refresh timer fires; a reply that lands outside an active batch still reports right away. --- .../widgets/tabs/tab_deck_storage.cpp | 30 +++++++++++++++---- .../interface/widgets/tabs/tab_deck_storage.h | 2 ++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/cockatrice/src/interface/widgets/tabs/tab_deck_storage.cpp b/cockatrice/src/interface/widgets/tabs/tab_deck_storage.cpp index 886693a5b..833dd0430 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_deck_storage.cpp +++ b/cockatrice/src/interface/widgets/tabs/tab_deck_storage.cpp @@ -44,7 +44,8 @@ #include #include -namespace { +namespace +{ // How long to wait after the last visibility change before reading back the // Public/Private column, in milliseconds. constexpr int VISIBILITY_REFRESH_DELAY = 500; @@ -860,6 +861,7 @@ void TabDeckStorage::onShareFromTreeTimeout() void TabDeckStorage::actPublishDeck() { + visibilityFailures.clear(); const auto selection = serverDirView->getCurrentSelection(); for (const auto *node : selection) { Command_DeckSetVisibility cmd; @@ -889,15 +891,33 @@ void TabDeckStorage::actPublishDeck() void TabDeckStorage::setVisibilityFinished(const Response &r, const CommandContainer & /*commandContainer*/) { - if (r.response_code() != Response::RespOk) { - QMessageBox::critical(this, tr("Error"), - tr("Failed to change deck visibility on server (response code %1).") - .arg(QString::number(static_cast(r.response_code())))); + if (r.response_code() == Response::RespOk) { + if (visibilityRefreshStarted) { + visibilityRefreshTimer->start(); + } + return; + } + + // Collect batch failures and surface them once, when publishing quiets + // down, instead of stacking one modal dialog per rejected node. + const QString message = tr("Failed to change deck visibility on server (response code %1).") + .arg(QString::number(static_cast(r.response_code()))); + if (visibilityRefreshStarted) { + visibilityFailures.append(message); + visibilityRefreshTimer->start(); + } else { + QMessageBox::critical(this, tr("Error"), message); } } void TabDeckStorage::onVisibilityRefreshTimeout() { visibilityRefreshStarted = false; + if (!visibilityFailures.isEmpty()) { + QMessageBox::critical( + this, tr("Error"), + tr("Failed to change the visibility of %n selected deck(s).", "", visibilityFailures.size())); + visibilityFailures.clear(); + } serverDirView->refreshTree(); } diff --git a/cockatrice/src/interface/widgets/tabs/tab_deck_storage.h b/cockatrice/src/interface/widgets/tabs/tab_deck_storage.h index af59c46b9..f8d585880 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_deck_storage.h +++ b/cockatrice/src/interface/widgets/tabs/tab_deck_storage.h @@ -11,6 +11,7 @@ #include "../interface/widgets/server/remote/remote_decklist_tree_widget.h" #include "tab.h" +#include #include struct LoadedDeck; @@ -47,6 +48,7 @@ private: QAction *aOpenRemoteDeck, *aDownload, *aShareDecks, *aPublishDeck, *aNewFolder, *aDeleteRemoteDeck; bool visibilityRefreshStarted = false; QTimer *visibilityRefreshTimer; + QStringList visibilityFailures; QString getTargetPath() const; void setRemoteEnabled(bool enabled);