mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-05 01:23:24 -08:00
[Client] Alt investigation entry points and in-tab navigation
TabModeration gains an Open alt graph button plus alts-table double-click, both routing to the User Alts tab. UserContextMenu gains an Investigate alts action. TabAlts gains row double-click navigation with a Back history stack so moderators can walk the alt graph without retyping names.
This commit is contained in:
parent
ff6c0402a8
commit
66ae189a57
6 changed files with 78 additions and 1 deletions
|
|
@ -83,6 +83,7 @@ UserContextMenu::UserContextMenu(TabSupervisor *_tabSupervisor, QWidget *parent,
|
||||||
aDemoteFromDeveloper = new QAction(QString(), this);
|
aDemoteFromDeveloper = new QAction(QString(), this);
|
||||||
aGetAdminNotes = new QAction(QString(), this);
|
aGetAdminNotes = new QAction(QString(), this);
|
||||||
aInvestigateUser = new QAction(QString(), this);
|
aInvestigateUser = new QAction(QString(), this);
|
||||||
|
aInvestigateAlts = new QAction(QString(), this);
|
||||||
|
|
||||||
retranslateUi();
|
retranslateUi();
|
||||||
}
|
}
|
||||||
|
|
@ -111,6 +112,7 @@ void UserContextMenu::retranslateUi()
|
||||||
aDemoteFromDeveloper->setText(tr("Demote user from de&veloper"));
|
aDemoteFromDeveloper->setText(tr("Demote user from de&veloper"));
|
||||||
aGetAdminNotes->setText(tr("View admin notes"));
|
aGetAdminNotes->setText(tr("View admin notes"));
|
||||||
aInvestigateUser->setText(tr("Investigate user"));
|
aInvestigateUser->setText(tr("Investigate user"));
|
||||||
|
aInvestigateAlts->setText(tr("Investigate &alts"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserContextMenu::gamesOfUserReceived(const Response &resp, const CommandContainer &commandContainer)
|
void UserContextMenu::gamesOfUserReceived(const Response &resp, const CommandContainer &commandContainer)
|
||||||
|
|
@ -454,6 +456,7 @@ void UserContextMenu::showContextMenu(const QPoint &pos,
|
||||||
menu->addSeparator();
|
menu->addSeparator();
|
||||||
menu->addAction(aGetAdminNotes);
|
menu->addAction(aGetAdminNotes);
|
||||||
menu->addAction(aInvestigateUser);
|
menu->addAction(aInvestigateUser);
|
||||||
|
menu->addAction(aInvestigateAlts);
|
||||||
|
|
||||||
menu->addSeparator();
|
menu->addSeparator();
|
||||||
if (userLevel.testFlag(ServerInfo_User::IsModerator) &&
|
if (userLevel.testFlag(ServerInfo_User::IsModerator) &&
|
||||||
|
|
@ -499,6 +502,7 @@ void UserContextMenu::showContextMenu(const QPoint &pos,
|
||||||
aBanHistory->setEnabled(anotherUser);
|
aBanHistory->setEnabled(anotherUser);
|
||||||
aGetAdminNotes->setEnabled(anotherUser);
|
aGetAdminNotes->setEnabled(anotherUser);
|
||||||
aInvestigateUser->setEnabled(anotherUser);
|
aInvestigateUser->setEnabled(anotherUser);
|
||||||
|
aInvestigateAlts->setEnabled(anotherUser);
|
||||||
aPromoteToMod->setEnabled(anotherUser);
|
aPromoteToMod->setEnabled(anotherUser);
|
||||||
aDemoteFromMod->setEnabled(anotherUser);
|
aDemoteFromMod->setEnabled(anotherUser);
|
||||||
aPromoteToJudge->setEnabled(anotherUser);
|
aPromoteToJudge->setEnabled(anotherUser);
|
||||||
|
|
@ -553,6 +557,8 @@ void UserContextMenu::showContextMenu(const QPoint &pos,
|
||||||
execAdminNotes(userName);
|
execAdminNotes(userName);
|
||||||
} else if (actionClicked == aInvestigateUser) {
|
} else if (actionClicked == aInvestigateUser) {
|
||||||
execInvestigateUser(userName);
|
execInvestigateUser(userName);
|
||||||
|
} else if (actionClicked == aInvestigateAlts) {
|
||||||
|
execInvestigateAlts(userName);
|
||||||
} else if (actionClicked == aCopyToClipBoard) {
|
} else if (actionClicked == aCopyToClipBoard) {
|
||||||
QClipboard *clipboard = QGuiApplication::clipboard();
|
QClipboard *clipboard = QGuiApplication::clipboard();
|
||||||
clipboard->setText(deckHash);
|
clipboard->setText(deckHash);
|
||||||
|
|
@ -745,6 +751,11 @@ void UserContextMenu::execInvestigateUser(const QString &userName)
|
||||||
tabSupervisor->openTabModeration(userName);
|
tabSupervisor->openTabModeration(userName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UserContextMenu::execInvestigateAlts(const QString &userName)
|
||||||
|
{
|
||||||
|
tabSupervisor->openTabAlts(userName);
|
||||||
|
}
|
||||||
|
|
||||||
void UserContextMenu::execAdjustMod(const QString &userName, bool shouldBeMod)
|
void UserContextMenu::execAdjustMod(const QString &userName, bool shouldBeMod)
|
||||||
{
|
{
|
||||||
Command_AdjustMod cmd;
|
Command_AdjustMod cmd;
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ private:
|
||||||
QAction *aGetAdminNotes;
|
QAction *aGetAdminNotes;
|
||||||
std::function<QList<GameInviteOption>()> gameInviteLinkProvider;
|
std::function<QList<GameInviteOption>()> gameInviteLinkProvider;
|
||||||
QAction *aInvestigateUser;
|
QAction *aInvestigateUser;
|
||||||
|
QAction *aInvestigateAlts;
|
||||||
signals:
|
signals:
|
||||||
void openMessageDialog(const QString &userName, bool focus);
|
void openMessageDialog(const QString &userName, bool focus);
|
||||||
private slots:
|
private slots:
|
||||||
|
|
@ -127,6 +128,7 @@ public:
|
||||||
void execWarnHistory(const QString &userName);
|
void execWarnHistory(const QString &userName);
|
||||||
void execAdminNotes(const QString &userName);
|
void execAdminNotes(const QString &userName);
|
||||||
void execInvestigateUser(const QString &userName);
|
void execInvestigateUser(const QString &userName);
|
||||||
|
void execInvestigateAlts(const QString &userName);
|
||||||
void execAdjustMod(const QString &userName, bool shouldBeMod);
|
void execAdjustMod(const QString &userName, bool shouldBeMod);
|
||||||
void execAdjustJudge(const QString &userName, bool shouldBeJudge);
|
void execAdjustJudge(const QString &userName, bool shouldBeJudge);
|
||||||
void execAdjustDeveloper(const QString &userName, bool shouldBeDeveloper);
|
void execAdjustDeveloper(const QString &userName, bool shouldBeDeveloper);
|
||||||
|
|
|
||||||
|
|
@ -58,9 +58,14 @@ TabAlts::TabAlts(TabSupervisor *_tabSupervisor, AbstractClient *_client, const Q
|
||||||
investigateButton = new QPushButton;
|
investigateButton = new QPushButton;
|
||||||
connect(investigateButton, &QPushButton::clicked, this, &TabAlts::investigateUser);
|
connect(investigateButton, &QPushButton::clicked, this, &TabAlts::investigateUser);
|
||||||
|
|
||||||
|
backButton = new QPushButton;
|
||||||
|
backButton->setEnabled(false);
|
||||||
|
connect(backButton, &QPushButton::clicked, this, &TabAlts::goBack);
|
||||||
|
|
||||||
statusLabel = new QLabel;
|
statusLabel = new QLabel;
|
||||||
|
|
||||||
auto *topBar = new QHBoxLayout;
|
auto *topBar = new QHBoxLayout;
|
||||||
|
topBar->addWidget(backButton);
|
||||||
topBar->addWidget(searchEdit);
|
topBar->addWidget(searchEdit);
|
||||||
topBar->addWidget(depthSpin);
|
topBar->addWidget(depthSpin);
|
||||||
topBar->addWidget(investigateButton);
|
topBar->addWidget(investigateButton);
|
||||||
|
|
@ -73,6 +78,12 @@ TabAlts::TabAlts(TabSupervisor *_tabSupervisor, AbstractClient *_client, const Q
|
||||||
altsTable->setAlternatingRowColors(true);
|
altsTable->setAlternatingRowColors(true);
|
||||||
altsTable->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
altsTable->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||||
altsTable->horizontalHeader()->setStretchLastSection(true);
|
altsTable->horizontalHeader()->setStretchLastSection(true);
|
||||||
|
connect(altsTable, &QTableWidget::cellDoubleClicked, this, [this](int row, int) {
|
||||||
|
auto *userItem = altsTable->item(row, COL_ALTS_USER);
|
||||||
|
if (userItem != nullptr && !userItem->text().isEmpty() && userItem->text() != currentUser) {
|
||||||
|
investigate(userItem->text());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
auto *mainLayout = new QVBoxLayout(centralWidget);
|
auto *mainLayout = new QVBoxLayout(centralWidget);
|
||||||
mainLayout->addLayout(topBar);
|
mainLayout->addLayout(topBar);
|
||||||
|
|
@ -89,6 +100,8 @@ void TabAlts::retranslateUi()
|
||||||
depthSpin->setPrefix(tr("Depth: "));
|
depthSpin->setPrefix(tr("Depth: "));
|
||||||
depthSpin->setToolTip(tr("Search depth: 1 finds direct matches, higher values follow alts of alts."));
|
depthSpin->setToolTip(tr("Search depth: 1 finds direct matches, higher values follow alts of alts."));
|
||||||
investigateButton->setText(tr("Investigate"));
|
investigateButton->setText(tr("Investigate"));
|
||||||
|
backButton->setText(tr("Back"));
|
||||||
|
backButton->setToolTip(tr("Back to the previously investigated user"));
|
||||||
if (currentUser.isEmpty()) {
|
if (currentUser.isEmpty()) {
|
||||||
statusLabel->setText(tr("Enter a user name to investigate."));
|
statusLabel->setText(tr("Enter a user name to investigate."));
|
||||||
}
|
}
|
||||||
|
|
@ -105,9 +118,29 @@ QString TabAlts::formatEpoch(quint64 ts) const
|
||||||
|
|
||||||
void TabAlts::investigate(const QString &userName)
|
void TabAlts::investigate(const QString &userName)
|
||||||
{
|
{
|
||||||
if (userName.isEmpty()) {
|
if (userName.isEmpty() || userName == currentUser) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!currentUser.isEmpty()) {
|
||||||
|
backStack << currentUser;
|
||||||
|
backButton->setEnabled(true);
|
||||||
|
}
|
||||||
|
loadUser(userName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabAlts::goBack()
|
||||||
|
{
|
||||||
|
if (backStack.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const QString previousUser = backStack.takeLast();
|
||||||
|
backButton->setEnabled(!backStack.isEmpty());
|
||||||
|
loadUser(previousUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabAlts::loadUser(const QString &userName)
|
||||||
|
{
|
||||||
|
currentUser = userName;
|
||||||
searchEdit->setText(userName);
|
searchEdit->setText(userName);
|
||||||
investigateUser();
|
investigateUser();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,18 +35,22 @@ public:
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void investigateUser();
|
void investigateUser();
|
||||||
|
void goBack();
|
||||||
void altsResponse(const Response &response);
|
void altsResponse(const Response &response);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void loadUser(const QString &userName);
|
||||||
void requestAlts(const QString &userName, int depth);
|
void requestAlts(const QString &userName, int depth);
|
||||||
[[nodiscard]] QString formatEpoch(quint64 ts) const;
|
[[nodiscard]] QString formatEpoch(quint64 ts) const;
|
||||||
|
|
||||||
AbstractClient *client;
|
AbstractClient *client;
|
||||||
QString currentUser;
|
QString currentUser;
|
||||||
|
QList<QString> backStack;
|
||||||
|
|
||||||
QLineEdit *searchEdit;
|
QLineEdit *searchEdit;
|
||||||
QSpinBox *depthSpin;
|
QSpinBox *depthSpin;
|
||||||
QPushButton *investigateButton;
|
QPushButton *investigateButton;
|
||||||
|
QPushButton *backButton;
|
||||||
QLabel *statusLabel;
|
QLabel *statusLabel;
|
||||||
QTableWidget *altsTable;
|
QTableWidget *altsTable;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#include "libcockatrice/protocol/pb/serverinfo_moderator_login.pb.h"
|
#include "libcockatrice/protocol/pb/serverinfo_moderator_login.pb.h"
|
||||||
#include "libcockatrice/protocol/pb/serverinfo_user_alt.pb.h"
|
#include "libcockatrice/protocol/pb/serverinfo_user_alt.pb.h"
|
||||||
#include "libcockatrice/protocol/pb/serverinfo_user_session.pb.h"
|
#include "libcockatrice/protocol/pb/serverinfo_user_session.pb.h"
|
||||||
|
#include "tab_supervisor.h"
|
||||||
|
|
||||||
#include <QAbstractItemView>
|
#include <QAbstractItemView>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
|
@ -146,7 +147,19 @@ TabModeration::TabModeration(TabSupervisor *_tabSupervisor, AbstractClient *_cli
|
||||||
altsGroup = new QGroupBox;
|
altsGroup = new QGroupBox;
|
||||||
altsTable = new QTableWidget(0, COL_ALTS_COUNT);
|
altsTable = new QTableWidget(0, COL_ALTS_COUNT);
|
||||||
configureTable(altsTable);
|
configureTable(altsTable);
|
||||||
|
connect(altsTable, &QTableWidget::cellDoubleClicked, this, [this](int row, int) {
|
||||||
|
auto *userItem = altsTable->item(row, COL_ALTS_USER);
|
||||||
|
if (userItem != nullptr && !userItem->text().isEmpty()) {
|
||||||
|
getTabSupervisor()->openTabAlts(userItem->text());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
openAltsButton = new QPushButton;
|
||||||
|
connect(openAltsButton, &QPushButton::clicked, this, &TabModeration::openAltsGraph);
|
||||||
|
auto *altsHeader = new QHBoxLayout;
|
||||||
|
altsHeader->addStretch();
|
||||||
|
altsHeader->addWidget(openAltsButton);
|
||||||
auto *altsLayout = new QVBoxLayout(altsGroup);
|
auto *altsLayout = new QVBoxLayout(altsGroup);
|
||||||
|
altsLayout->addLayout(altsHeader);
|
||||||
altsLayout->addWidget(altsTable);
|
altsLayout->addWidget(altsTable);
|
||||||
|
|
||||||
sessionsGroup = new QGroupBox;
|
sessionsGroup = new QGroupBox;
|
||||||
|
|
@ -205,6 +218,8 @@ void TabModeration::retranslateUi()
|
||||||
userInfoNotesLabel->setText(tr("Admin notes:"));
|
userInfoNotesLabel->setText(tr("Admin notes:"));
|
||||||
|
|
||||||
altsGroup->setTitle(tr("Alts"));
|
altsGroup->setTitle(tr("Alts"));
|
||||||
|
openAltsButton->setText(tr("Open alt graph"));
|
||||||
|
openAltsButton->setToolTip(tr("Open this user in the User Alts tab"));
|
||||||
sessionsGroup->setTitle(tr("Sessions"));
|
sessionsGroup->setTitle(tr("Sessions"));
|
||||||
staffGroup->setTitle(tr("Staff Last Logins"));
|
staffGroup->setTitle(tr("Staff Last Logins"));
|
||||||
|
|
||||||
|
|
@ -233,6 +248,7 @@ void TabModeration::clearUserData()
|
||||||
resetPasswordButton->setEnabled(false);
|
resetPasswordButton->setEnabled(false);
|
||||||
removeAvatarButton->setEnabled(false);
|
removeAvatarButton->setEnabled(false);
|
||||||
removeBannerButton->setEnabled(false);
|
removeBannerButton->setEnabled(false);
|
||||||
|
openAltsButton->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabModeration::investigate(const QString &userName)
|
void TabModeration::investigate(const QString &userName)
|
||||||
|
|
@ -254,6 +270,7 @@ void TabModeration::investigateUser()
|
||||||
resetPasswordButton->setEnabled(true);
|
resetPasswordButton->setEnabled(true);
|
||||||
removeAvatarButton->setEnabled(true);
|
removeAvatarButton->setEnabled(true);
|
||||||
removeBannerButton->setEnabled(true);
|
removeBannerButton->setEnabled(true);
|
||||||
|
openAltsButton->setEnabled(true);
|
||||||
altsTable->setRowCount(0);
|
altsTable->setRowCount(0);
|
||||||
sessionsTable->setRowCount(0);
|
sessionsTable->setRowCount(0);
|
||||||
requestUserInfo(userName);
|
requestUserInfo(userName);
|
||||||
|
|
@ -261,6 +278,14 @@ void TabModeration::investigateUser()
|
||||||
requestAlts(userName);
|
requestAlts(userName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TabModeration::openAltsGraph()
|
||||||
|
{
|
||||||
|
if (currentUser.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getTabSupervisor()->openTabAlts(currentUser);
|
||||||
|
}
|
||||||
|
|
||||||
void TabModeration::requestUserInfo(const QString &userName)
|
void TabModeration::requestUserInfo(const QString &userName)
|
||||||
{
|
{
|
||||||
userInfoNameValue->setText(userName);
|
userInfoNameValue->setText(userName);
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ public:
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void investigateUser();
|
void investigateUser();
|
||||||
|
void openAltsGraph();
|
||||||
void userInfoResponse(const Response &response);
|
void userInfoResponse(const Response &response);
|
||||||
void sessionsResponse(const Response &response);
|
void sessionsResponse(const Response &response);
|
||||||
void altsResponse(const Response &response);
|
void altsResponse(const Response &response);
|
||||||
|
|
@ -80,6 +81,7 @@ private:
|
||||||
|
|
||||||
QGroupBox *altsGroup;
|
QGroupBox *altsGroup;
|
||||||
QTableWidget *altsTable;
|
QTableWidget *altsTable;
|
||||||
|
QPushButton *openAltsButton;
|
||||||
QGroupBox *sessionsGroup;
|
QGroupBox *sessionsGroup;
|
||||||
QTableWidget *sessionsTable;
|
QTableWidget *sessionsTable;
|
||||||
QGroupBox *staffGroup;
|
QGroupBox *staffGroup;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue