Axivion: Fetch the DashboardData via task tree

Enrich the DashboardInfo structure.
Use dashboardInfoRecipe() for fetching the project list.

Change-Id: Ibbc14d0fae31a8930cec6051e412af15bec71fea
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
Jarek Kobus
2024-01-23 22:29:59 +01:00
parent 6215206a06
commit 2d9f8805dc
6 changed files with 86 additions and 100 deletions

View File

@@ -268,7 +268,7 @@ void IssuesWidget::updateUi()
return;
// for now just a start..
const Dto::AnalysisVersionDto &last = info.versions.back();
// const Dto::AnalysisVersionDto &last = info.versions.back();
const std::vector<Dto::IssueKindInfoDto> &issueKinds = info.issueKinds;
for (const Dto::IssueKindInfoDto &kind : issueKinds) {

View File

@@ -33,13 +33,11 @@
#include <utils/algorithm.h>
#include <utils/async.h>
#include <utils/expected.h>
#include <utils/networkaccessmanager.h>
#include <utils/qtcassert.h>
#include <utils/utilsicons.h>
#include <QAction>
#include <QFutureWatcher>
#include <QMessageBox>
#include <QNetworkAccessManager>
#include <QNetworkReply>
@@ -97,6 +95,7 @@ public:
NetworkAccessManager m_networkAccessManager;
AxivionOutputPane m_axivionOutputPane;
std::optional<DashboardInfo> m_dashboardInfo;
std::optional<Dto::ProjectInfoDto> m_currentProjectInfo;
bool m_runningQuery = false;
TaskTreeRunner m_taskTreeRunner;
@@ -324,6 +323,54 @@ static Group fetchDataRecipe(const QUrl &url,
return recipe;
}
static DashboardInfo toDashboardInfo(const QUrl &source, const Dto::DashboardInfoDto &infoDto)
{
const QVersionNumber versionNumber = infoDto.dashboardVersionNumber
? QVersionNumber::fromString(*infoDto.dashboardVersionNumber) : QVersionNumber();
QStringList projects;
QHash<QString, QUrl> projectUrls;
if (infoDto.projects) {
for (const Dto::ProjectReferenceDto &project : *infoDto.projects) {
projects.push_back(project.name);
projectUrls.insert(project.name, project.url);
}
}
return {source, versionNumber, projects, projectUrls, infoDto.checkCredentialsUrl};
}
Group dashboardInfoRecipe(const DashboardInfoHandler &handler)
{
const auto onSetup = [handler] {
if (dd->m_dashboardInfo) {
if (handler)
handler(*dd->m_dashboardInfo);
return SetupResult::StopWithSuccess;
}
return SetupResult::Continue;
};
const auto onDone = [handler](DoneWith result) {
if (result == DoneWith::Error && handler)
handler(make_unexpected(QString("Error"))); // TODO: Collect error message in the storage.
};
const QUrl url(settings().server.dashboard);
const auto resultHandler = [handler, url](const Dto::DashboardInfoDto &data) {
dd->m_dashboardInfo = toDashboardInfo(url, data);
if (handler)
handler(*dd->m_dashboardInfo);
};
const Group root {
onGroupSetup(onSetup), // Stops if cache exists.
fetchDataRecipe<Dto::DashboardInfoDto>(url, resultHandler),
onGroupDone(onDone) // TODO: Pass CallDoneIf::Error, write task tree autotest.
};
return root;
}
void AxivionPluginPrivate::fetchProjectInfo(const QString &projectName)
{
if (m_taskTreeRunner.isRunning()) { // TODO: cache in queue and run when task tree finished

View File

@@ -5,6 +5,12 @@
#include "dashboard/dto.h"
#include <utils/expected.h>
#include <QHash>
#include <QUrl>
#include <QVersionNumber>
#include <memory>
QT_BEGIN_NAMESPACE
@@ -13,6 +19,8 @@ QT_END_NAMESPACE
namespace ProjectExplorer { class Project; }
namespace Tasking { class Group; }
namespace Axivion::Internal {
struct IssueListSearch
@@ -29,6 +37,19 @@ struct IssueListSearch
QString toQuery() const;
};
class DashboardInfo
{
public:
QUrl source;
QVersionNumber versionNumber;
QStringList projects;
QHash<QString, QUrl> projectUrls;
std::optional<QUrl> checkCredentialsUrl;
};
using DashboardInfoHandler = std::function<void(const Utils::expected_str<DashboardInfo> &)>;
Tasking::Group dashboardInfoRecipe(const DashboardInfoHandler &handler = {});
void fetchProjectInfo(const QString &projectName);
std::optional<Dto::ProjectInfoDto> projectInfo();
void fetchIssueTableLayout(const QString &prefix);

View File

@@ -4,8 +4,6 @@
#include "axivionprojectsettings.h"
#include "axivionplugin.h"
#include "axivionquery.h"
#include "axivionresultparser.h"
#include "axivionsettings.h"
#include "axiviontr.h"
@@ -13,6 +11,8 @@
#include <projectexplorer/projectpanelfactory.h>
#include <projectexplorer/projectsettingswidget.h>
#include <solutions/tasking/tasktreerunner.h>
#include <utils/infolabel.h>
#include <utils/qtcassert.h>
@@ -21,6 +21,7 @@
#include <QVBoxLayout>
using namespace ProjectExplorer;
using namespace Tasking;
using namespace Utils;
namespace Axivion::Internal {
@@ -96,7 +97,6 @@ public:
private:
void fetchProjects();
void onDashboardInfoReceived(const DashboardInfo &info);
void onSettingsChanged();
void linkProject();
void unlinkProject();
@@ -110,6 +110,7 @@ private:
QPushButton *m_link = nullptr;
QPushButton *m_unlink = nullptr;
Utils::InfoLabel *m_infoLabel = nullptr;
TaskTreeRunner m_taskTreeRunner;
};
AxivionProjectSettingsWidget::AxivionProjectSettingsWidget(ProjectExplorer::Project *project)
@@ -166,30 +167,20 @@ void AxivionProjectSettingsWidget::fetchProjects()
m_dashboardProjects->clear();
m_fetchProjects->setEnabled(false);
m_infoLabel->setVisible(false);
// TODO perform query and populate m_dashboardProjects
const AxivionQuery query(AxivionQuery::DashboardInfo);
AxivionQueryRunner *runner = new AxivionQueryRunner(query, this);
connect(runner, &AxivionQueryRunner::resultRetrieved,
this, [this](const QByteArray &result){
onDashboardInfoReceived(ResultParser::parseDashboardInfo(result));
});
connect(runner, &AxivionQueryRunner::finished, this, [runner]{ runner->deleteLater(); });
runner->start();
}
void AxivionProjectSettingsWidget::onDashboardInfoReceived(const DashboardInfo &info)
{
if (!info.error.isEmpty()) {
m_infoLabel->setText(info.error);
m_infoLabel->setType(Utils::InfoLabel::Error);
m_infoLabel->setVisible(true);
const auto onDashboardInfo = [this](const expected_str<DashboardInfo> &info) {
if (!info) {
m_infoLabel->setText(info.error());
m_infoLabel->setType(Utils::InfoLabel::Error);
m_infoLabel->setVisible(true);
} else {
for (const QString &project : info->projects)
new QTreeWidgetItem(m_dashboardProjects, {project});
}
updateEnabledStates();
return;
}
};
for (const Project &project : info.projects)
new QTreeWidgetItem(m_dashboardProjects, {project.name});
updateEnabledStates();
m_taskTreeRunner.start(dashboardInfoRecipe(onDashboardInfo));
}
void AxivionProjectSettingsWidget::onSettingsChanged()

View File

@@ -5,14 +5,8 @@
#include <utils/qtcassert.h>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QRegularExpression>
#include <stdexcept>
#include <utility>
namespace Axivion::Internal {
static std::pair<QByteArray, QByteArray> splitHeaderAndBody(const QByteArray &input)
@@ -58,67 +52,8 @@ static BaseResult prehandleHeader(const QByteArray &header, const QByteArray &bo
return result;
}
static std::pair<BaseResult, QJsonDocument> prehandleHeaderAndBody(const QByteArray &header,
const QByteArray &body)
{
BaseResult result = prehandleHeader(header, body);
if (!result.error.isEmpty())
return {result, {}};
QJsonParseError error;
const QJsonDocument doc = QJsonDocument::fromJson(body, &error);
if (error.error != QJsonParseError::NoError) {
result.error = error.errorString();
return {result, doc};
}
if (!doc.isObject()) {
result.error = "Not an object.";
return {result, {}};
}
return {result, doc};
}
namespace ResultParser {
DashboardInfo parseDashboardInfo(const QByteArray &input)
{
DashboardInfo result;
auto [header, body] = splitHeaderAndBody(input);
auto [error, doc] = prehandleHeaderAndBody(header, body);
if (!error.error.isEmpty()) {
result.error = error.error;
return result;
}
const QJsonObject object = doc.object();
result.mainUrl = object.value("mainUrl").toString();
if (!object.contains("projects")) {
result.error = "Missing projects information.";
return result;
}
const QJsonValue projects = object.value("projects");
if (!projects.isArray()) {
result.error = "Projects information not an array.";
return result;
}
const QJsonArray array = projects.toArray();
for (const QJsonValue &val : array) {
if (!val.isObject())
continue;
const QJsonObject projectObject = val.toObject();
Project project;
project.name = projectObject.value("name").toString();
project.url = projectObject.value("url").toString();
if (project.name.isEmpty() || project.url.isEmpty())
continue;
result.projects.append(project);
}
return result;
}
static QRegularExpression issueCsvLineRegex(const QByteArray &firstCsvLine)
{
QString pattern = "^";

View File

@@ -22,13 +22,6 @@ public:
QString url;
};
class DashboardInfo : public BaseResult
{
public:
QString mainUrl;
QList<Project> projects;
};
class ShortIssue : public BaseResult
{
public:
@@ -50,7 +43,6 @@ public:
namespace ResultParser {
DashboardInfo parseDashboardInfo(const QByteArray &input);
IssuesList parseIssuesList(const QByteArray &input);
QString parseRuleInfo(const QByteArray &input);