Axivion: Fetch issues

Change-Id: Ib33c507c8036fe84291ac3ff3fb08eed46afb07c
Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io>
This commit is contained in:
Christian Stenger
2024-01-19 15:06:34 +01:00
parent d501cb3ad4
commit 3df75b6740
4 changed files with 176 additions and 3 deletions

View File

@@ -8,6 +8,8 @@
#include "dashboard/dto.h" #include "dashboard/dto.h"
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/treemodel.h>
#include <utils/basetreeview.h>
#include <utils/utilsicons.h> #include <utils/utilsicons.h>
#include <QComboBox> #include <QComboBox>
@@ -176,6 +178,8 @@ class IssuesWidget : public QScrollArea
public: public:
explicit IssuesWidget(QWidget *parent = nullptr); explicit IssuesWidget(QWidget *parent = nullptr);
void updateUi(); void updateUi();
void setTableDto(const Dto::TableInfoDto &dto);
void addIssues(const Dto::IssueTableDto &dto);
private: private:
void updateTableView(); void updateTableView();
@@ -190,6 +194,8 @@ private:
QComboBox *m_versionStart = nullptr; QComboBox *m_versionStart = nullptr;
QComboBox *m_versionEnd = nullptr; QComboBox *m_versionEnd = nullptr;
QLineEdit *m_pathGlobFilter = nullptr; // FancyLineEdit instead? QLineEdit *m_pathGlobFilter = nullptr; // FancyLineEdit instead?
Utils::BaseTreeView *m_issuesView = nullptr;
Utils::TreeModel<> *m_issuesModel = nullptr;
}; };
IssuesWidget::IssuesWidget(QWidget *parent) IssuesWidget::IssuesWidget(QWidget *parent)
@@ -231,7 +237,13 @@ IssuesWidget::IssuesWidget(QWidget *parent)
m_pathGlobFilter->setPlaceholderText(Tr::tr("Path globbing")); m_pathGlobFilter->setPlaceholderText(Tr::tr("Path globbing"));
m_filtersLayout->addWidget(m_pathGlobFilter); m_filtersLayout->addWidget(m_pathGlobFilter);
layout->addLayout(m_filtersLayout); layout->addLayout(m_filtersLayout);
// TODO the issues table m_issuesView = new Utils::BaseTreeView(this);
m_issuesView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
m_issuesView->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
m_issuesView->enableColumnHiding();
m_issuesModel = new Utils::TreeModel;
m_issuesView->setModel(m_issuesModel);
layout->addWidget(m_issuesView);
layout->addStretch(1); layout->addStretch(1);
setWidget(widget); setWidget(widget);
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
@@ -273,12 +285,75 @@ void IssuesWidget::updateUi()
// TODO fill owners // TODO fill owners
m_filtersLayout->setEnabled(true); m_filtersLayout->setEnabled(true);
if (info.issueKinds.size())
m_currentPrefix = info.issueKinds.front().prefix;
updateTableView();
}
void IssuesWidget::setTableDto(const Dto::TableInfoDto &dto)
{
m_currentTableInfo.emplace(dto);
// update issues table layout - for now just simple approach
Utils::TreeModel<> *issuesModel = new Utils::TreeModel;
QStringList columnHeaders;
QStringList hiddenColumns;
for (const Dto::ColumnInfoDto &column : dto.columns) {
columnHeaders << column.key;
if (!column.showByDefault)
hiddenColumns << column.key;
}
issuesModel->setHeader(columnHeaders);
auto oldModel = m_issuesModel;
m_issuesModel = issuesModel;
m_issuesView->setModel(issuesModel);
delete oldModel;
int counter = 0;
for (const QString &header : std::as_const(columnHeaders))
m_issuesView->setColumnHidden(counter++, hiddenColumns.contains(header));
// first time lookup... should we cache and maybe represent old data?
IssueListSearch search;
search.kind = m_currentPrefix;
fetchIssues(search);
}
void IssuesWidget::addIssues(const Dto::IssueTableDto &dto)
{
QTC_ASSERT(m_currentTableInfo.has_value(), return);
// handle added/removed/total ?
const std::vector<Dto::ColumnInfoDto> tableColumns = m_currentTableInfo->columns;
// const std::vector<Dto::ColumnInfoDto> columns = dto.columns.value();
const std::vector<std::map<QString, Dto::Any>> rows = dto.rows;
for (auto row : rows) {
QStringList data;
for (auto column : tableColumns) {
auto it = row.find(column.key);
if (it != row.end()) {
if (it->second.isString())
data << it->second.getString();
else if (it->second.isDouble())
data << QString::number(it->second.getDouble());
else if (it->second.isBool())
data << QString("%1").arg(it->second.getBool());
else
data << "not yet";
}
}
Utils::StaticTreeItem *it = new Utils::StaticTreeItem(data);
m_issuesModel->rootItem()->appendChild(it);
}
} }
void IssuesWidget::updateTableView() void IssuesWidget::updateTableView()
{ {
// fetch table dto and apply QTC_ASSERT(!m_currentPrefix.isEmpty(), return);
// on done fetch first data for the selected issues // fetch table dto and apply, on done fetch first data for the selected issues
fetchIssueTableLayout(m_currentPrefix);
} }
AxivionOutputPane::AxivionOutputPane(QObject *parent) AxivionOutputPane::AxivionOutputPane(QObject *parent)
@@ -387,6 +462,18 @@ void AxivionOutputPane::updateDashboard()
} }
} }
void AxivionOutputPane::setTableDto(const Dto::TableInfoDto &dto)
{
if (auto issues = static_cast<IssuesWidget *>(m_outputWidget->widget(1)))
issues->setTableDto(dto);
}
void AxivionOutputPane::addIssues(const Dto::IssueTableDto &dto)
{
if (auto issues = static_cast<IssuesWidget *>(m_outputWidget->widget(1)))
issues->addIssues(dto);
}
void AxivionOutputPane::updateAndShowRule(const QString &ruleHtml) void AxivionOutputPane::updateAndShowRule(const QString &ruleHtml)
{ {
if (auto browser = static_cast<QTextBrowser *>(m_outputWidget->widget(2))) { if (auto browser = static_cast<QTextBrowser *>(m_outputWidget->widget(2))) {

View File

@@ -11,6 +11,11 @@ QT_END_NAMESPACE
namespace Axivion::Internal { namespace Axivion::Internal {
namespace Dto {
class IssueTableDto;
class TableInfoDto;
}
class AxivionOutputPane : public Core::IOutputPane class AxivionOutputPane : public Core::IOutputPane
{ {
Q_OBJECT Q_OBJECT
@@ -33,6 +38,8 @@ public:
void updateDashboard(); void updateDashboard();
void updateAndShowRule(const QString &ruleHtml); void updateAndShowRule(const QString &ruleHtml);
void setTableDto(const Dto::TableInfoDto &dto);
void addIssues(const Dto::IssueTableDto &dto);
private: private:
QStackedWidget *m_outputWidget = nullptr; QStackedWidget *m_outputWidget = nullptr;
}; };

View File

@@ -69,6 +69,16 @@ QIcon iconForIssue(const QString &prefix)
return it.value(); return it.value();
} }
QString IssueListSearch::toQuery() const
{
if (kind.isEmpty())
return {};
QString result;
result.append(QString("?kind=%1&offset=%2&limit=%3").arg(kind).arg(offset).arg(limit));
// TODO other params
return result;
}
class AxivionPluginPrivate : public QObject class AxivionPluginPrivate : public QObject
{ {
public: public:
@@ -76,6 +86,8 @@ public:
void handleSslErrors(QNetworkReply *reply, const QList<QSslError> &errors); void handleSslErrors(QNetworkReply *reply, const QList<QSslError> &errors);
void onStartupProjectChanged(); void onStartupProjectChanged();
void fetchProjectInfo(const QString &projectName); void fetchProjectInfo(const QString &projectName);
void fetchIssueTableLayout(const QString &prefix);
void fetchIssues(const IssueListSearch &search);
void handleOpenedDocs(ProjectExplorer::Project *project); void handleOpenedDocs(ProjectExplorer::Project *project);
void onDocumentOpened(Core::IDocument *doc); void onDocumentOpened(Core::IDocument *doc);
void onDocumentClosed(Core::IDocument * doc); void onDocumentClosed(Core::IDocument * doc);
@@ -127,6 +139,18 @@ void fetchProjectInfo(const QString &projectName)
dd->fetchProjectInfo(projectName); dd->fetchProjectInfo(projectName);
} }
void fetchIssueTableLayout(const QString &prefix)
{
QTC_ASSERT(dd, return);
dd->fetchIssueTableLayout(prefix);
}
void fetchIssues(const IssueListSearch &search)
{
QTC_ASSERT(dd, return);
dd->fetchIssues(search);
}
std::optional<Dto::ProjectInfoDto> projectInfo() std::optional<Dto::ProjectInfoDto> projectInfo()
{ {
QTC_ASSERT(dd, return {}); QTC_ASSERT(dd, return {});
@@ -332,6 +356,45 @@ void AxivionPluginPrivate::fetchProjectInfo(const QString &projectName)
m_taskTreeRunner.start(fetchDataRecipe<Dto::ProjectInfoDto>(url, handler)); m_taskTreeRunner.start(fetchDataRecipe<Dto::ProjectInfoDto>(url, handler));
} }
void AxivionPluginPrivate::fetchIssueTableLayout(const QString &prefix)
{
QTC_ASSERT(m_currentProjectInfo.has_value(), return);
if (m_taskTreeRunner.isRunning()) {
QTimer::singleShot(3000, this, [this, prefix] { fetchIssueTableLayout(prefix); });
return;
}
const QUrl url = urlForProject(m_currentProjectInfo.value().name + '/')
.resolved(QString("issues_meta?kind=" + prefix));
const auto handler = [this](const Dto::TableInfoDto &data) {
m_axivionOutputPane.setTableDto(data);
};
m_taskTreeRunner.start(fetchDataRecipe<Dto::TableInfoDto>(url, handler));
}
void AxivionPluginPrivate::fetchIssues(const IssueListSearch &search)
{
QTC_ASSERT(m_currentProjectInfo.has_value(), return);
if (m_taskTreeRunner.isRunning()) {
QTimer::singleShot(3000, this, [this, search] { fetchIssues(search); });
return;
}
const QString query = search.toQuery();
if (query.isEmpty())
return;
const QUrl url = urlForProject(m_currentProjectInfo.value().name + '/')
.resolved(QString("issues" + query));
const auto handler = [this](const Dto::IssueTableDto &data) {
m_axivionOutputPane.addIssues(data);
};
m_taskTreeRunner.start(fetchDataRecipe<Dto::IssueTableDto>(url, handler));
}
void AxivionPluginPrivate::fetchRuleInfo(const QString &id) void AxivionPluginPrivate::fetchRuleInfo(const QString &id)
{ {
if (m_runningQuery) { if (m_runningQuery) {

View File

@@ -15,8 +15,24 @@ namespace ProjectExplorer { class Project; }
namespace Axivion::Internal { namespace Axivion::Internal {
struct IssueListSearch
{
QString kind;
QString state;
QString versionStart;
QString versionEnd;
QString owner;
QString pathglob;
int offset = 0;
int limit = 30;
QString toQuery() const;
};
void fetchProjectInfo(const QString &projectName); void fetchProjectInfo(const QString &projectName);
std::optional<Dto::ProjectInfoDto> projectInfo(); std::optional<Dto::ProjectInfoDto> projectInfo();
void fetchIssueTableLayout(const QString &prefix);
void fetchIssues(const IssueListSearch &search);
bool handleCertificateIssue(); bool handleCertificateIssue();
QIcon iconForIssue(const QString &prefix); QIcon iconForIssue(const QString &prefix);