[Client] Report queue dashboard and status pills

TabReport becomes a dashboard: selected-report identity header (display-size user, bold status, category/time/room subline), Description/Chat/Comments/Reported-user tabbed sections with tab memory, always-visible user context with empty cues, and bold reported users. ReportStatusDelegate paints palette-tinted status pills with paint-through selection, translated status strings, and font/elision handling. report_utils gains formatReportStatus plus an opt-out status-color flag so the delegate owns color in the mod queue while the user dialog keeps its colors. Async responses stay guarded; retranslation re-applies header and comment states.
This commit is contained in:
Lukas Brübach 2026-10-13 22:08:58 +02:00
parent 080798b0e1
commit 31878eb880
7 changed files with 262 additions and 45 deletions

View file

@ -376,6 +376,7 @@ set(cockatrice_SOURCES
src/interface/widgets/tabs/api/edhrec/display/top_tags/edhrec_top_tags_api_response_display_widget.cpp src/interface/widgets/tabs/api/edhrec/display/top_tags/edhrec_top_tags_api_response_display_widget.cpp
src/interface/widgets/tabs/api/edhrec/tab_edhrec.cpp src/interface/widgets/tabs/api/edhrec/tab_edhrec.cpp
src/interface/widgets/tabs/api/edhrec/tab_edhrec_main.cpp src/interface/widgets/tabs/api/edhrec/tab_edhrec_main.cpp
src/interface/widgets/tabs/report_status_delegate.cpp
src/interface/widgets/tabs/tab.cpp src/interface/widgets/tabs/tab.cpp
src/interface/widgets/tabs/tab_account.cpp src/interface/widgets/tabs/tab_account.cpp
src/interface/widgets/tabs/tab_admin.cpp src/interface/widgets/tabs/tab_admin.cpp

View file

@ -0,0 +1,77 @@
#include "report_status_delegate.h"
#include <QApplication>
#include <QPainter>
#include <QPalette>
#include <QStyle>
#include <QStyleOptionViewItem>
namespace
{
constexpr qreal PILL_ALPHA = 0.30;
constexpr int PILL_PAD_X = 10;
constexpr int PILL_PAD_Y = 4;
} // namespace
ReportStatusDelegate::ReportStatusDelegate(QObject *parent) : QStyledItemDelegate(parent)
{
}
void ReportStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
const bool selected = (option.state & QStyle::State_Selected) != 0;
QString status = index.data(Qt::UserRole).toString();
if (status.isEmpty()) {
status = index.data(Qt::DisplayRole).toString();
}
QPalette::ColorRole tintRole = QPalette::NoRole;
if (status == QStringLiteral("open")) {
tintRole = QPalette::Highlight;
} else if (status == QStringLiteral("assigned")) {
tintRole = QPalette::Link;
} else if (status == QStringLiteral("resolved")) {
tintRole = QPalette::PlaceholderText;
}
QStyleOptionViewItem opt(option);
initStyleOption(&opt, index);
painter->setFont(opt.font);
if (tintRole == QPalette::NoRole) {
const QPalette::ColorRole textRole = selected ? QPalette::HighlightedText : QPalette::PlaceholderText;
QStyle *fallbackStyle = opt.widget != nullptr ? opt.widget->style() : QApplication::style();
fallbackStyle->drawItemText(painter, opt.rect, Qt::AlignLeft | Qt::AlignVCenter, opt.palette, true, opt.text,
textRole);
return;
}
const QRect pillRect = opt.rect.adjusted(PILL_PAD_X / 2, PILL_PAD_Y / 2, -PILL_PAD_X / 2, -PILL_PAD_Y / 2);
if (pillRect.width() <= 0 || pillRect.height() <= 0) {
QStyledItemDelegate::paint(painter, opt, index);
return;
}
if (!selected) {
painter->save();
painter->setRenderHint(QPainter::Antialiasing, true);
QColor pill = opt.palette.color(tintRole);
pill.setAlphaF(PILL_ALPHA);
painter->setPen(Qt::NoPen);
painter->setBrush(pill);
painter->drawRoundedRect(pillRect, pillRect.height() / 2.0, pillRect.height() / 2.0);
painter->restore();
}
const QString elided =
opt.fontMetrics.elidedText(opt.text.isEmpty() ? status : opt.text, opt.textElideMode, pillRect.width());
const QPalette::ColorRole textRole = selected ? QPalette::HighlightedText : QPalette::WindowText;
QStyle *style = opt.widget != nullptr ? opt.widget->style() : QApplication::style();
style->drawItemText(painter, pillRect, Qt::AlignCenter, opt.palette, true, elided, textRole);
}
QSize ReportStatusDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
const QSize hint = QStyledItemDelegate::sizeHint(option, index);
return hint + QSize(PILL_PAD_X, PILL_PAD_Y);
}

View file

@ -0,0 +1,22 @@
#ifndef REPORT_STATUS_DELEGATE_H
#define REPORT_STATUS_DELEGATE_H
#include <QStyledItemDelegate>
#include <qtmetamacros.h>
/**
* Status pill for the report queue table. Paints the status text on a
* translucent badge tinted with a palette role per status, so the colors
* always follow the active theme. Falls back to default painting for
* selected rows and unknown statuses.
*/
class ReportStatusDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit ReportStatusDelegate(QObject *parent = nullptr);
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
[[nodiscard]] QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
};
#endif // REPORT_STATUS_DELEGATE_H

View file

@ -4,6 +4,7 @@
#include "../utility/report_utils.h" #include "../utility/report_utils.h"
#include "abstract_client.h" #include "abstract_client.h"
#include "libcockatrice/protocol/pb/response.pb.h" #include "libcockatrice/protocol/pb/response.pb.h"
#include "report_status_delegate.h"
#include "tab_supervisor.h" #include "tab_supervisor.h"
#include <QAbstractItemView> #include <QAbstractItemView>
@ -22,7 +23,7 @@
#include <QPushButton> #include <QPushButton>
#include <QSharedPointer> #include <QSharedPointer>
#include <QSignalBlocker> #include <QSignalBlocker>
#include <QSplitter> #include <QTabWidget>
#include <QTableWidget> #include <QTableWidget>
#include <QTableWidgetItem> #include <QTableWidgetItem>
#include <QTextCursor> #include <QTextCursor>
@ -124,25 +125,42 @@ TabReport::TabReport(TabSupervisor *_tabSupervisor, AbstractClient *_client) : T
connect(table, &QTableWidget::itemSelectionChanged, this, &TabReport::onSelectionChanged); connect(table, &QTableWidget::itemSelectionChanged, this, &TabReport::onSelectionChanged);
table->setContextMenuPolicy(Qt::CustomContextMenu); table->setContextMenuPolicy(Qt::CustomContextMenu);
connect(table, &QTableWidget::customContextMenuRequested, this, &TabReport::showTableContextMenu); connect(table, &QTableWidget::customContextMenuRequested, this, &TabReport::showTableContextMenu);
table->setItemDelegateForColumn(COL_STATUS, new ReportStatusDelegate(table));
userContextMenu = new UserContextMenu(tabSupervisor, this); userContextMenu = new UserContextMenu(tabSupervisor, this);
connect(userContextMenu, &UserContextMenu::openMessageDialog, this, &TabReport::openMessageDialog); connect(userContextMenu, &UserContextMenu::openMessageDialog, this, &TabReport::openMessageDialog);
descGroup = new QGroupBox; reportHeaderName = new QLabel;
QFont displayFont = reportHeaderName->font();
displayFont.setPointSize(displayFont.pointSize() + 6);
displayFont.setBold(true);
reportHeaderName->setFont(displayFont);
reportHeaderStatus = new QLabel;
QFont statusFont = reportHeaderStatus->font();
statusFont.setBold(true);
reportHeaderStatus->setFont(statusFont);
reportHeaderSubline = new QLabel;
auto *reportIdentityRow = new QHBoxLayout;
reportIdentityRow->addWidget(reportHeaderName);
reportIdentityRow->addStretch();
reportIdentityRow->addWidget(reportHeaderStatus);
auto *descPage = new QWidget;
descriptionEdit = new QTextEdit; descriptionEdit = new QTextEdit;
descriptionEdit->setReadOnly(true); descriptionEdit->setReadOnly(true);
auto *descLayout = new QVBoxLayout(descGroup); auto *descLayout = new QVBoxLayout(descPage);
descLayout->setContentsMargins(4, 4, 4, 4); descLayout->setContentsMargins(4, 4, 4, 4);
descLayout->addWidget(descriptionEdit); descLayout->addWidget(descriptionEdit);
chatGroup = new QGroupBox; auto *chatPage = new QWidget;
chatLogEdit = new QTextEdit; chatLogEdit = new QTextEdit;
chatLogEdit->setReadOnly(true); chatLogEdit->setReadOnly(true);
chatLogEdit->setFont(QtUtils::monospaceFont()); chatLogEdit->setFont(QtUtils::monospaceFont());
auto *chatLayout = new QVBoxLayout(chatGroup); auto *chatLayout = new QVBoxLayout(chatPage);
chatLayout->setContentsMargins(4, 4, 4, 4); chatLayout->setContentsMargins(4, 4, 4, 4);
chatLayout->addWidget(chatLogEdit); chatLayout->addWidget(chatLogEdit);
commentsGroup = new QGroupBox; auto *commentsPage = new QWidget;
commentsEdit = new QTextEdit; commentsEdit = new QTextEdit;
commentsEdit->setReadOnly(true); commentsEdit->setReadOnly(true);
auto *commentInputRow = new QHBoxLayout; auto *commentInputRow = new QHBoxLayout;
@ -153,12 +171,12 @@ TabReport::TabReport(TabSupervisor *_tabSupervisor, AbstractClient *_client) : T
connect(commentInput, &QLineEdit::returnPressed, this, &TabReport::addComment); connect(commentInput, &QLineEdit::returnPressed, this, &TabReport::addComment);
commentInputRow->addWidget(commentInput); commentInputRow->addWidget(commentInput);
commentInputRow->addWidget(commentButton); commentInputRow->addWidget(commentButton);
auto *commentsLayout = new QVBoxLayout(commentsGroup); auto *commentsLayout = new QVBoxLayout(commentsPage);
commentsLayout->setContentsMargins(4, 4, 4, 4); commentsLayout->setContentsMargins(4, 4, 4, 4);
commentsLayout->addWidget(commentsEdit); commentsLayout->addWidget(commentsEdit);
commentsLayout->addLayout(commentInputRow); commentsLayout->addLayout(commentInputRow);
userContextGroup = new QGroupBox; auto *userPage = new QWidget;
userContextName = new QLabel; userContextName = new QLabel;
userContextAccountAge = new QLabel; userContextAccountAge = new QLabel;
userContextReports = new QLabel; userContextReports = new QLabel;
@ -177,7 +195,7 @@ TabReport::TabReport(TabSupervisor *_tabSupervisor, AbstractClient *_client) : T
userContextWarnsLabel = new QLabel; userContextWarnsLabel = new QLabel;
userContextNotesLabel = new QLabel; userContextNotesLabel = new QLabel;
userContextRecentReportsLabel = new QLabel; userContextRecentReportsLabel = new QLabel;
auto *ucLayout = new QGridLayout(userContextGroup); auto *ucLayout = new QGridLayout(userPage);
ucLayout->setContentsMargins(8, 8, 8, 8); ucLayout->setContentsMargins(8, 8, 8, 8);
ucLayout->addWidget(userContextUserLabel, 0, 0); ucLayout->addWidget(userContextUserLabel, 0, 0);
ucLayout->addWidget(userContextName, 0, 1, 1, 3); ucLayout->addWidget(userContextName, 0, 1, 1, 3);
@ -193,7 +211,6 @@ TabReport::TabReport(TabSupervisor *_tabSupervisor, AbstractClient *_client) : T
ucLayout->addWidget(userContextNotes, 3, 1, 1, 3); ucLayout->addWidget(userContextNotes, 3, 1, 1, 3);
ucLayout->addWidget(userContextRecentReportsLabel, 4, 0, 1, 4); ucLayout->addWidget(userContextRecentReportsLabel, 4, 0, 1, 4);
ucLayout->addWidget(userContextRecentReports, 5, 0, 1, 4); ucLayout->addWidget(userContextRecentReports, 5, 0, 1, 4);
userContextGroup->setVisible(false);
statsGroup = new QGroupBox; statsGroup = new QGroupBox;
statsGroup->setCheckable(true); statsGroup->setCheckable(true);
@ -220,13 +237,11 @@ TabReport::TabReport(TabSupervisor *_tabSupervisor, AbstractClient *_client) : T
} }
}); });
detailSplitter = new QSplitter(Qt::Vertical); detailTabs = new QTabWidget;
detailSplitter->addWidget(descGroup); detailTabs->addTab(descPage, QString());
detailSplitter->addWidget(chatGroup); detailTabs->addTab(chatPage, QString());
detailSplitter->addWidget(commentsGroup); detailTabs->addTab(commentsPage, QString());
detailSplitter->setStretchFactor(0, 1); detailTabs->addTab(userPage, QString());
detailSplitter->setStretchFactor(1, 1);
detailSplitter->setStretchFactor(2, 2);
assignButton = new QPushButton; assignButton = new QPushButton;
resolveButton = new QPushButton; resolveButton = new QPushButton;
@ -258,12 +273,14 @@ TabReport::TabReport(TabSupervisor *_tabSupervisor, AbstractClient *_client) : T
layout->addLayout(topBar); layout->addLayout(topBar);
layout->addWidget(statsLabel); layout->addWidget(statsLabel);
layout->addWidget(table, 2); layout->addWidget(table, 2);
layout->addWidget(detailSplitter, 1); layout->addLayout(reportIdentityRow);
layout->addWidget(userContextGroup); layout->addWidget(reportHeaderSubline);
layout->addWidget(detailTabs, 2);
layout->addWidget(statsGroup); layout->addWidget(statsGroup);
layout->addLayout(actionBar); layout->addLayout(actionBar);
retranslateUi(); retranslateUi();
clearReportHeader();
setActionsEnabled(false); setActionsEnabled(false);
refreshList(); refreshList();
@ -285,18 +302,18 @@ void TabReport::retranslateUi()
table->setHorizontalHeaderLabels({tr("#"), tr("Time"), tr("Reporter"), tr("Reported User"), tr("Category"), table->setHorizontalHeaderLabels({tr("#"), tr("Time"), tr("Reporter"), tr("Reported User"), tr("Category"),
tr("Game ID"), tr("Status"), tr("Assigned To"), tr("Replay"), tr("Room")}); tr("Game ID"), tr("Status"), tr("Assigned To"), tr("Replay"), tr("Room")});
descGroup->setTitle(tr("Description")); detailTabs->setTabText(0, tr("Description"));
chatGroup->setTitle(tr("Chat Log Context")); detailTabs->setTabText(1, tr("Chat Log Context"));
chatGroup->setToolTip( detailTabs->setTabToolTip(1, tr("Chat log attached by the reporter. It is captured from their client and may be "
tr("Chat log attached by the reporter. It is captured from their client and may be incomplete or edited.")); "incomplete or edited."));
commentsGroup->setTitle(tr("Comments / Thread")); detailTabs->setTabText(2, tr("Comments / Thread"));
detailTabs->setTabText(3, tr("Reported User"));
descriptionEdit->setPlaceholderText(tr("No description.")); descriptionEdit->setPlaceholderText(tr("No description."));
chatLogEdit->setPlaceholderText(tr("No chat log attached.")); chatLogEdit->setPlaceholderText(tr("No chat log attached."));
commentsEdit->setPlaceholderText(tr("No comments yet.")); commentsEdit->setPlaceholderText(tr("No comments yet."));
commentInput->setPlaceholderText(tr("Type a reply...")); commentInput->setPlaceholderText(tr("Type a reply..."));
commentButton->setText(tr("Send")); commentButton->setText(tr("Send"));
userContextGroup->setTitle(tr("Reported User Context"));
userContextUserLabel->setText(tr("User:")); userContextUserLabel->setText(tr("User:"));
userContextAgeLabel->setText(tr("Account Age:")); userContextAgeLabel->setText(tr("Account Age:"));
userContextReportsLabel->setText(tr("Reports:")); userContextReportsLabel->setText(tr("Reports:"));
@ -304,10 +321,18 @@ void TabReport::retranslateUi()
userContextWarnsLabel->setText(tr("Warns:")); userContextWarnsLabel->setText(tr("Warns:"));
userContextNotesLabel->setText(tr("Admin Notes:")); userContextNotesLabel->setText(tr("Admin Notes:"));
userContextRecentReportsLabel->setText(tr("Recent Reports Against User:")); userContextRecentReportsLabel->setText(tr("Recent Reports Against User:"));
userContextAccountAge->setText(QString());
userContextReports->setText(QString()); if (headerReportId >= 0) {
userContextBans->setText(QString()); for (const ServerInfo_Report &r : filteredReports) {
userContextWarns->setText(QString()); if (r.report_id() == headerReportId) {
updateReportHeader(r);
const QString status = QString::fromStdString(r.status());
const bool canComment = (status == "open" || status == "assigned");
commentInput->setPlaceholderText(canComment ? tr("Type a reply...") : tr("This report is closed."));
break;
}
}
}
statsGroup->setTitle(tr("Report Statistics")); statsGroup->setTitle(tr("Report Statistics"));
@ -400,7 +425,8 @@ void TabReport::reportListResponse(const Response &response)
chatLogEdit->clear(); chatLogEdit->clear();
commentsEdit->clear(); commentsEdit->clear();
setActionsEnabled(false); setActionsEnabled(false);
userContextGroup->setVisible(false); clearReportHeader();
clearUserContext();
} }
} }
@ -441,7 +467,7 @@ void TabReport::applyFilters()
const ServerInfo_Report &r = filteredReports[row]; const ServerInfo_Report &r = filteredReports[row];
report_utils::fillReportTableRow(table, row, r, COL_ID, COL_TIME, COL_REPORTED, COL_CATEGORY, COL_GAMEID, report_utils::fillReportTableRow(table, row, r, COL_ID, COL_TIME, COL_REPORTED, COL_CATEGORY, COL_GAMEID,
COL_STATUS, COL_ASSIGNED); COL_STATUS, COL_ASSIGNED, false);
table->setItem(row, COL_REPORTER, new QTableWidgetItem(QString::fromStdString(r.reporter_name()))); table->setItem(row, COL_REPORTER, new QTableWidgetItem(QString::fromStdString(r.reporter_name())));
@ -452,10 +478,32 @@ void TabReport::applyFilters()
new QTableWidgetItem(r.has_room_id() && r.room_id() > 0 ? QString::number(r.room_id()) : "")); new QTableWidgetItem(r.has_room_id() && r.room_id() > 0 ? QString::number(r.room_id()) : ""));
} }
QFont reportedFont = table->font();
reportedFont.setBold(true);
for (int row = 0; row < filteredReports.size(); ++row) {
if (auto *reportedItem = table->item(row, COL_REPORTED)) {
reportedItem->setFont(reportedFont);
}
}
table->setSortingEnabled(true); table->setSortingEnabled(true);
table->resizeColumnsToContents(); table->resizeColumnsToContents();
table->horizontalHeader()->setSectionResizeMode(COL_REPORTED, QHeaderView::Stretch); table->horizontalHeader()->setSectionResizeMode(COL_REPORTED, QHeaderView::Stretch);
if (headerReportId >= 0) {
bool stillVisible = false;
for (const ServerInfo_Report &r : filteredReports) {
if (r.report_id() == headerReportId) {
stillVisible = true;
break;
}
}
if (!stillVisible) {
clearReportHeader();
clearUserContext();
}
}
statusLabel->setText(tr("%1 report(s)").arg(filteredReports.size())); statusLabel->setText(tr("%1 report(s)").arg(filteredReports.size()));
} }
@ -482,6 +530,31 @@ void TabReport::updateStats()
.arg(dismissed)); .arg(dismissed));
} }
void TabReport::updateReportHeader(const ServerInfo_Report &report)
{
reportHeaderName->setText(QString::fromStdString(report.reported_user_name()));
reportHeaderStatus->setText(report_utils::formatReportStatus(QString::fromStdString(report.status())));
QStringList parts;
parts << QString::fromStdString(report.category());
parts << QDateTime::fromSecsSinceEpoch(report.report_time()).toLocalTime().toString("yyyy-MM-dd HH:mm");
if (report.has_room_id() && report.room_id() > 0) {
parts << tr("Room %1").arg(report.room_id());
}
if (report.game_id() > 0) {
parts << tr("Game %1").arg(report.game_id());
}
reportHeaderSubline->setText(parts.join(QStringLiteral(" · ")));
}
void TabReport::clearReportHeader()
{
headerReportId = -1;
reportHeaderName->setText(tr("Select a report to inspect."));
reportHeaderStatus->clear();
reportHeaderSubline->clear();
}
void TabReport::onSelectionChanged() void TabReport::onSelectionChanged()
{ {
const int row = table->currentRow(); const int row = table->currentRow();
@ -492,7 +565,8 @@ void TabReport::onSelectionChanged()
commentInput->clear(); commentInput->clear();
commentButton->setEnabled(false); commentButton->setEnabled(false);
setActionsEnabled(false); setActionsEnabled(false);
userContextGroup->setVisible(false); clearReportHeader();
clearUserContext();
return; return;
} }
@ -501,6 +575,18 @@ void TabReport::onSelectionChanged()
updateActionStates(); updateActionStates();
} }
void TabReport::clearUserContext()
{
lastRequestedUser.clear();
userContextName->setText(tr("—"));
userContextAccountAge->clear();
userContextReports->clear();
userContextBans->clear();
userContextWarns->clear();
userContextNotes->setPlainText(tr("Select a report to inspect."));
userContextRecentReports->clear();
}
void TabReport::showTableContextMenu(const QPoint &pos) void TabReport::showTableContextMenu(const QPoint &pos)
{ {
QTableWidgetItem *clickedItem = table->itemAt(pos); QTableWidgetItem *clickedItem = table->itemAt(pos);
@ -538,12 +624,17 @@ void TabReport::loadReportDetails(int reportId)
for (const ServerInfo_Report &r : filteredReports) { for (const ServerInfo_Report &r : filteredReports) {
if (r.report_id() == reportId) { if (r.report_id() == reportId) {
descriptionEdit->setPlainText(QString::fromStdString(r.description())); descriptionEdit->setPlainText(QString::fromStdString(r.description()));
updateReportHeader(r);
if (headerReportId != reportId) {
headerReportId = reportId;
detailTabs->setCurrentIndex(0);
}
QString reportedUser = QString::fromStdString(r.reported_user_name()); QString reportedUser = QString::fromStdString(r.reported_user_name());
if (!reportedUser.isEmpty()) { if (!reportedUser.isEmpty()) {
requestUserInfo(reportedUser); requestUserInfo(reportedUser);
} else { } else {
userContextGroup->setVisible(false); clearUserContext();
} }
QString status = QString::fromStdString(r.status()); QString status = QString::fromStdString(r.status());
@ -863,12 +954,11 @@ void TabReport::addCommentResponse(const Response &response)
void TabReport::requestUserInfo(const QString &userName) void TabReport::requestUserInfo(const QString &userName)
{ {
if (userName.isEmpty()) { if (userName.isEmpty()) {
userContextGroup->setVisible(false); clearUserContext();
return; return;
} }
lastRequestedUser = userName; lastRequestedUser = userName;
userContextGroup->setVisible(true);
userContextName->setText(userName); userContextName->setText(userName);
userContextAccountAge->setText(tr("Loading...")); userContextAccountAge->setText(tr("Loading..."));
userContextReports->clear(); userContextReports->clear();

View file

@ -16,8 +16,8 @@ class QGroupBox;
class QLabel; class QLabel;
class QLineEdit; class QLineEdit;
class QPushButton; class QPushButton;
class QSplitter;
class QTableWidget; class QTableWidget;
class QTabWidget;
class QTextEdit; class QTextEdit;
class QTimer; class QTimer;
class GameReplay; class GameReplay;
@ -71,6 +71,9 @@ private:
void applyFilters(); void applyFilters();
void updateStats(); void updateStats();
void loadReportDetails(int reportId); void loadReportDetails(int reportId);
void updateReportHeader(const ServerInfo_Report &report);
void clearReportHeader();
void clearUserContext();
AbstractClient *client; AbstractClient *client;
@ -80,10 +83,10 @@ private:
QPushButton *refreshButton; QPushButton *refreshButton;
QLabel *statsLabel; QLabel *statsLabel;
QTableWidget *table; QTableWidget *table;
QSplitter *detailSplitter; QLabel *reportHeaderName;
QGroupBox *descGroup; QLabel *reportHeaderStatus;
QGroupBox *chatGroup; QLabel *reportHeaderSubline;
QGroupBox *commentsGroup; QTabWidget *detailTabs;
QTextEdit *descriptionEdit; QTextEdit *descriptionEdit;
QTextEdit *chatLogEdit; QTextEdit *chatLogEdit;
QTextEdit *commentsEdit; QTextEdit *commentsEdit;
@ -99,7 +102,6 @@ private:
QTimer *refreshTimer; QTimer *refreshTimer;
UserContextMenu *userContextMenu; UserContextMenu *userContextMenu;
QGroupBox *userContextGroup;
QLabel *userContextName; QLabel *userContextName;
QLabel *userContextAccountAge; QLabel *userContextAccountAge;
QLabel *userContextReports; QLabel *userContextReports;
@ -124,6 +126,7 @@ private:
QList<ServerInfo_Report> allReports; QList<ServerInfo_Report> allReports;
QList<ServerInfo_Report> filteredReports; QList<ServerInfo_Report> filteredReports;
int headerReportId = -1;
int detailsRequestedReportId = -1; int detailsRequestedReportId = -1;
int detailsRequestSeq = 0; int detailsRequestSeq = 0;
int selectedReportIdBeforeRefresh = -1; int selectedReportIdBeforeRefresh = -1;

View file

@ -64,6 +64,23 @@ QString formatReportTime(qint64 secondsSinceEpoch)
return dt.toString("yyyy-MM-dd hh:mm"); return dt.toString("yyyy-MM-dd hh:mm");
} }
QString formatReportStatus(const QString &status)
{
if (status == QStringLiteral("open")) {
return QObject::tr("Open");
}
if (status == QStringLiteral("assigned")) {
return QObject::tr("Assigned");
}
if (status == QStringLiteral("resolved")) {
return QObject::tr("Resolved");
}
if (status == QStringLiteral("dismissed")) {
return QObject::tr("Dismissed");
}
return status;
}
void fillReportTableRow(QTableWidget *table, void fillReportTableRow(QTableWidget *table,
int row, int row,
const ServerInfo_Report &report, const ServerInfo_Report &report,
@ -73,7 +90,8 @@ void fillReportTableRow(QTableWidget *table,
int categoryColumn, int categoryColumn,
int gameIdColumn, int gameIdColumn,
int statusColumn, int statusColumn,
int assignedColumn) int assignedColumn,
bool colorizeStatus)
{ {
auto *idItem = new QTableWidgetItem(QString::number(report.report_id())); auto *idItem = new QTableWidgetItem(QString::number(report.report_id()));
idItem->setData(Qt::UserRole, report.report_id()); idItem->setData(Qt::UserRole, report.report_id());
@ -86,8 +104,12 @@ void fillReportTableRow(QTableWidget *table,
table->setItem(row, gameIdColumn, table->setItem(row, gameIdColumn,
new QTableWidgetItem(report.game_id() > 0 ? QString::number(report.game_id()) : QString())); new QTableWidgetItem(report.game_id() > 0 ? QString::number(report.game_id()) : QString()));
auto *statusItem = new QTableWidgetItem(QString::fromStdString(report.status())); const QString rawStatus = QString::fromStdString(report.status());
setReportStatusItemColor(statusItem, QString::fromStdString(report.status())); auto *statusItem = new QTableWidgetItem(formatReportStatus(rawStatus));
statusItem->setData(Qt::UserRole, rawStatus);
if (colorizeStatus) {
setReportStatusItemColor(statusItem, rawStatus);
}
table->setItem(row, statusColumn, statusItem); table->setItem(row, statusColumn, statusItem);
table->setItem(row, assignedColumn, new QTableWidgetItem(QString::fromStdString(report.assigned_mod_name()))); table->setItem(row, assignedColumn, new QTableWidgetItem(QString::fromStdString(report.assigned_mod_name())));

View file

@ -13,6 +13,7 @@ namespace report_utils
QString formatReportCategory(const QString &category); QString formatReportCategory(const QString &category);
QString formatReportTime(qint64 secondsSinceEpoch); QString formatReportTime(qint64 secondsSinceEpoch);
QString formatReportStatus(const QString &status);
void fillReportTableRow(QTableWidget *table, void fillReportTableRow(QTableWidget *table,
int row, int row,
@ -23,7 +24,8 @@ void fillReportTableRow(QTableWidget *table,
int categoryColumn, int categoryColumn,
int gameIdColumn, int gameIdColumn,
int statusColumn, int statusColumn,
int assignedColumn); int assignedColumn,
bool colorizeStatus = true);
void renderReportDetails(QTextEdit *chatLogEdit, void renderReportDetails(QTextEdit *chatLogEdit,
QTextEdit *commentsEdit, QTextEdit *commentsEdit,