forked from qt-creator/qt-creator
Axivion: Use DTO for ProjectInfo deserialization
This is a proof of concept that the DTOs can be used to deserialize and access the data the Axivion Dashboard returns. In future, this is going to replace all manual deserialization and manually written Dashboard interface classes. Change-Id: Ic3c997f6aca7fcb179cd19fa9b5107fe7d4dec03 Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -4,8 +4,8 @@
|
||||
#include "axivionoutputpane.h"
|
||||
|
||||
#include "axivionplugin.h"
|
||||
#include "axivionresultparser.h"
|
||||
#include "axiviontr.h"
|
||||
#include "dashboard/dto.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/utilsicons.h>
|
||||
@@ -18,6 +18,9 @@
|
||||
#include <QTextBrowser>
|
||||
#include <QToolButton>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
namespace Axivion::Internal {
|
||||
|
||||
class DashboardWidget : public QScrollArea
|
||||
@@ -58,7 +61,7 @@ DashboardWidget::DashboardWidget(QWidget *parent)
|
||||
setWidgetResizable(true);
|
||||
}
|
||||
|
||||
static QPixmap trendIcon(int added, int removed)
|
||||
static QPixmap trendIcon(qint64 added, qint64 removed)
|
||||
{
|
||||
static const QPixmap unchanged = Utils::Icons::NEXT.pixmap();
|
||||
static const QPixmap increased = Utils::Icon(
|
||||
@@ -70,10 +73,20 @@ static QPixmap trendIcon(int added, int removed)
|
||||
return added < removed ? decreased : increased;
|
||||
}
|
||||
|
||||
static qint64 extract_value(const std::map<QString, Dto::Any> &map, const QString &key)
|
||||
{
|
||||
const auto search = map.find(key);
|
||||
if (search == map.end())
|
||||
return 0;
|
||||
const Dto::Any &value = search->second;
|
||||
if (!value.isDouble())
|
||||
return 0;
|
||||
return static_cast<qint64>(value.getDouble());
|
||||
}
|
||||
|
||||
void DashboardWidget::updateUi()
|
||||
{
|
||||
const ProjectInfo &info = AxivionPlugin::projectInfo();
|
||||
m_project->setText(info.name);
|
||||
m_project->setText({});
|
||||
m_loc->setText({});
|
||||
m_timestamp->setText({});
|
||||
QLayoutItem *child;
|
||||
@@ -81,60 +94,77 @@ void DashboardWidget::updateUi()
|
||||
delete child->widget();
|
||||
delete child;
|
||||
}
|
||||
|
||||
if (info.versions.isEmpty())
|
||||
std::shared_ptr<const Dto::ProjectInfoDto> info = AxivionPlugin::projectInfo();
|
||||
if (!info)
|
||||
return;
|
||||
m_project->setText(info->name);
|
||||
if (info->versions.empty())
|
||||
return;
|
||||
|
||||
const ResultVersion &last = info.versions.last();
|
||||
m_loc->setText(QString::number(last.linesOfCode));
|
||||
const QDateTime timeStamp = QDateTime::fromString(last.timeStamp, Qt::ISODate);
|
||||
m_timestamp->setText(timeStamp.isValid() ? timeStamp.toString("yyyy-MM-dd HH:mm:ss")
|
||||
const Dto::AnalysisVersionDto &last = info->versions.back();
|
||||
if (last.linesOfCode.has_value())
|
||||
m_loc->setText(QString::number(last.linesOfCode.value()));
|
||||
const QDateTime timeStamp = QDateTime::fromString(last.date, Qt::ISODate);
|
||||
m_timestamp->setText(timeStamp.isValid() ? timeStamp.toString("yyyy-MM-dd HH:mm:ss t")
|
||||
: Tr::tr("unknown"));
|
||||
|
||||
const QList<IssueKind> &issueKinds = info.issueKinds;
|
||||
const std::vector<Dto::IssueKindInfoDto> &issueKinds = info->issueKinds;
|
||||
auto toolTip = [issueKinds](const QString &prefix){
|
||||
for (const IssueKind &kind : issueKinds) {
|
||||
for (const Dto::IssueKindInfoDto &kind : issueKinds) {
|
||||
if (kind.prefix == prefix)
|
||||
return kind.nicePlural;
|
||||
return kind.nicePluralName;
|
||||
}
|
||||
return prefix;
|
||||
};
|
||||
auto addValuesWidgets = [this, &toolTip](const IssueCount &issueCount, int row){
|
||||
const QString currentToolTip = toolTip(issueCount.issueKind);
|
||||
QLabel *label = new QLabel(issueCount.issueKind, this);
|
||||
auto addValuesWidgets = [this, &toolTip](const QString &issueKind, qint64 total, qint64 added, qint64 removed, int row) {
|
||||
const QString currentToolTip = toolTip(issueKind);
|
||||
QLabel *label = new QLabel(issueKind, this);
|
||||
label->setToolTip(currentToolTip);
|
||||
m_gridLayout->addWidget(label, row, 0);
|
||||
label = new QLabel(QString::number(issueCount.total), this);
|
||||
label = new QLabel(QString::number(total), this);
|
||||
label->setToolTip(currentToolTip);
|
||||
label->setAlignment(Qt::AlignRight);
|
||||
m_gridLayout->addWidget(label, row, 1);
|
||||
label = new QLabel(this);
|
||||
label->setPixmap(trendIcon(issueCount.added, issueCount.removed));
|
||||
label->setPixmap(trendIcon(added, removed));
|
||||
label->setToolTip(currentToolTip);
|
||||
m_gridLayout->addWidget(label, row, 2);
|
||||
label = new QLabel('+' + QString::number(issueCount.added));
|
||||
label = new QLabel('+' + QString::number(added));
|
||||
label->setAlignment(Qt::AlignRight);
|
||||
label->setToolTip(currentToolTip);
|
||||
m_gridLayout->addWidget(label, row, 3);
|
||||
label = new QLabel("/");
|
||||
label->setToolTip(currentToolTip);
|
||||
m_gridLayout->addWidget(label, row, 4);
|
||||
label = new QLabel('-' + QString::number(issueCount.removed));
|
||||
label = new QLabel('-' + QString::number(removed));
|
||||
label->setAlignment(Qt::AlignRight);
|
||||
label->setToolTip(currentToolTip);
|
||||
m_gridLayout->addWidget(label, row, 5);
|
||||
};
|
||||
int allTotal = 0, allAdded = 0, allRemoved = 0, row = 0;
|
||||
for (auto issueCount : std::as_const(last.issueCounts)) {
|
||||
allTotal += issueCount.total;
|
||||
allAdded += issueCount.added;
|
||||
allRemoved += issueCount.removed;
|
||||
addValuesWidgets(issueCount, row);
|
||||
++row;
|
||||
qint64 allTotal = 0;
|
||||
qint64 allAdded = 0;
|
||||
qint64 allRemoved = 0;
|
||||
qint64 row = 0;
|
||||
// This code is overly complex because of a heedlessness in the
|
||||
// Axivion Dashboard API definition. Other Axivion IDE plugins do
|
||||
// not use the issue counts, thus the QtCreator Axivion Plugin
|
||||
// is going to stop using them, too.
|
||||
if (last.issueCounts.isMap()) {
|
||||
for (const auto &issueCount : last.issueCounts.getMap()) {
|
||||
if (issueCount.second.isMap()) {
|
||||
const auto &counts = issueCount.second.getMap();
|
||||
qint64 total = extract_value(counts, QStringLiteral(u"Total"));
|
||||
allTotal += total;
|
||||
qint64 added = extract_value(counts, QStringLiteral(u"Added"));
|
||||
allAdded += added;
|
||||
qint64 removed = extract_value(counts, QStringLiteral(u"Removed"));
|
||||
allRemoved += removed;
|
||||
addValuesWidgets(issueCount.first, total, added, removed, row);
|
||||
++row;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const IssueCount total{{}, Tr::tr("Total:"), allTotal, allAdded, allRemoved};
|
||||
addValuesWidgets(total, row);
|
||||
addValuesWidgets(Tr::tr("Total:"), allTotal, allAdded, allRemoved, row);
|
||||
}
|
||||
|
||||
AxivionOutputPane::AxivionOutputPane(QObject *parent)
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#include "axivionquery.h"
|
||||
#include "axivionresultparser.h"
|
||||
#include "axiviontr.h"
|
||||
#include "dashboard/dto.h"
|
||||
|
||||
#include <coreplugin/editormanager/documentmodel.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
@@ -24,12 +25,16 @@
|
||||
#include <texteditor/texteditor.h>
|
||||
#include <texteditor/textmark.h>
|
||||
|
||||
#include <utils/expected.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/utilsicons.h>
|
||||
|
||||
#include <QAction>
|
||||
#include <QTimer>
|
||||
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
|
||||
constexpr char AxivionTextMarkId[] = "AxivionTextMark";
|
||||
|
||||
namespace Axivion::Internal {
|
||||
@@ -39,7 +44,7 @@ class AxivionPluginPrivate : public QObject
|
||||
public:
|
||||
void onStartupProjectChanged();
|
||||
void fetchProjectInfo(const QString &projectName);
|
||||
void handleProjectInfo(const ProjectInfo &info);
|
||||
void handleProjectInfo(const QByteArray &result);
|
||||
void handleOpenedDocs(ProjectExplorer::Project *project);
|
||||
void onDocumentOpened(Core::IDocument *doc);
|
||||
void onDocumentClosed(Core::IDocument * doc);
|
||||
@@ -48,7 +53,7 @@ public:
|
||||
void fetchRuleInfo(const QString &id);
|
||||
|
||||
AxivionOutputPane m_axivionOutputPane;
|
||||
ProjectInfo m_currentProjectInfo;
|
||||
std::shared_ptr<const Dto::ProjectInfoDto> m_currentProjectInfo;
|
||||
bool m_runningQuery = false;
|
||||
};
|
||||
|
||||
@@ -113,7 +118,7 @@ void AxivionPlugin::fetchProjectInfo(const QString &projectName)
|
||||
dd->fetchProjectInfo(projectName);
|
||||
}
|
||||
|
||||
ProjectInfo AxivionPlugin::projectInfo()
|
||||
std::shared_ptr<const Dto::ProjectInfoDto> AxivionPlugin::projectInfo()
|
||||
{
|
||||
QTC_ASSERT(dd, return {});
|
||||
return dd->m_currentProjectInfo;
|
||||
@@ -124,7 +129,7 @@ void AxivionPluginPrivate::onStartupProjectChanged()
|
||||
ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject();
|
||||
if (!project) {
|
||||
clearAllMarks();
|
||||
m_currentProjectInfo = ProjectInfo();
|
||||
m_currentProjectInfo = {};
|
||||
m_axivionOutputPane.updateDashboard();
|
||||
return;
|
||||
}
|
||||
@@ -141,7 +146,7 @@ void AxivionPluginPrivate::fetchProjectInfo(const QString &projectName)
|
||||
}
|
||||
clearAllMarks();
|
||||
if (projectName.isEmpty()) {
|
||||
m_currentProjectInfo = ProjectInfo();
|
||||
m_currentProjectInfo = {};
|
||||
m_axivionOutputPane.updateDashboard();
|
||||
return;
|
||||
}
|
||||
@@ -150,7 +155,7 @@ void AxivionPluginPrivate::fetchProjectInfo(const QString &projectName)
|
||||
AxivionQuery query(AxivionQuery::ProjectInfo, {projectName});
|
||||
AxivionQueryRunner *runner = new AxivionQueryRunner(query, this);
|
||||
connect(runner, &AxivionQueryRunner::resultRetrieved, this, [this](const QByteArray &result){
|
||||
handleProjectInfo(ResultParser::parseProjectInfo(result));
|
||||
handleProjectInfo(result);
|
||||
});
|
||||
connect(runner, &AxivionQueryRunner::finished, [runner]{ runner->deleteLater(); });
|
||||
runner->start();
|
||||
@@ -196,20 +201,16 @@ void AxivionPluginPrivate::clearAllMarks()
|
||||
onDocumentClosed(doc);
|
||||
}
|
||||
|
||||
void AxivionPluginPrivate::handleProjectInfo(const ProjectInfo &info)
|
||||
void AxivionPluginPrivate::handleProjectInfo(const QByteArray &result)
|
||||
{
|
||||
Utils::expected_str<Dto::ProjectInfoDto> raw_info = ResultParser::parseProjectInfo(result);
|
||||
m_runningQuery = false;
|
||||
if (!info.error.isEmpty()) {
|
||||
Core::MessageManager::writeFlashing("Axivion: " + info.error);
|
||||
if (!raw_info) {
|
||||
Core::MessageManager::writeFlashing(QStringLiteral(u"Axivion: ") + raw_info.error());
|
||||
return;
|
||||
}
|
||||
|
||||
m_currentProjectInfo = info;
|
||||
m_currentProjectInfo = std::make_shared<const Dto::ProjectInfoDto>(std::move(raw_info.value()));
|
||||
m_axivionOutputPane.updateDashboard();
|
||||
|
||||
if (m_currentProjectInfo.name.isEmpty())
|
||||
return;
|
||||
|
||||
// handle already opened documents
|
||||
if (auto buildSystem = ProjectExplorer::ProjectManager::startupBuildSystem();
|
||||
!buildSystem || !buildSystem->isParsing()) {
|
||||
@@ -223,7 +224,7 @@ void AxivionPluginPrivate::handleProjectInfo(const ProjectInfo &info)
|
||||
|
||||
void AxivionPluginPrivate::onDocumentOpened(Core::IDocument *doc)
|
||||
{
|
||||
if (m_currentProjectInfo.name.isEmpty()) // we do not have a project info (yet)
|
||||
if (!m_currentProjectInfo) // we do not have a project info (yet)
|
||||
return;
|
||||
|
||||
ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject();
|
||||
@@ -232,7 +233,7 @@ void AxivionPluginPrivate::onDocumentOpened(Core::IDocument *doc)
|
||||
|
||||
Utils::FilePath relative = doc->filePath().relativeChildPath(project->projectDirectory());
|
||||
// for now only style violations
|
||||
AxivionQuery query(AxivionQuery::IssuesForFileList, {m_currentProjectInfo.name, "SV",
|
||||
AxivionQuery query(AxivionQuery::IssuesForFileList, {m_currentProjectInfo->name, "SV",
|
||||
relative.path() } );
|
||||
AxivionQueryRunner *runner = new AxivionQueryRunner(query, this);
|
||||
connect(runner, &AxivionQueryRunner::resultRetrieved, this, [this](const QByteArray &result){
|
||||
|
@@ -3,8 +3,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "dashboard/dto.h"
|
||||
|
||||
#include <extensionsystem/iplugin.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace ProjectExplorer { class Project; }
|
||||
|
||||
namespace Axivion::Internal {
|
||||
@@ -22,7 +26,7 @@ public:
|
||||
~AxivionPlugin() final;
|
||||
|
||||
static void fetchProjectInfo(const QString &projectName);
|
||||
static ProjectInfo projectInfo();
|
||||
static std::shared_ptr<const Dto::ProjectInfoDto> projectInfo();
|
||||
|
||||
private:
|
||||
void initialize() final;
|
||||
|
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "axivionresultparser.h"
|
||||
#include "dashboard/dto.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
@@ -10,6 +11,7 @@
|
||||
#include <QJsonObject>
|
||||
#include <QRegularExpression>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
namespace Axivion::Internal {
|
||||
@@ -79,124 +81,6 @@ static std::pair<BaseResult, QJsonDocument> prehandleHeaderAndBody(const QByteAr
|
||||
return {result, doc};
|
||||
}
|
||||
|
||||
static User::UserType userTypeForString(const QString &type)
|
||||
{
|
||||
if (type == "DASHBOARD_USER")
|
||||
return User::Dashboard;
|
||||
if (type == "VIRTUAL_USER")
|
||||
return User::Virtual;
|
||||
return User::Unknown;
|
||||
}
|
||||
|
||||
static User userFromJson(const QJsonObject &object)
|
||||
{
|
||||
User result;
|
||||
if (object.isEmpty()) {
|
||||
result.error = "Not a user object.";
|
||||
return result;
|
||||
}
|
||||
result.name = object.value("name").toString();
|
||||
result.displayName = object.value("displayName").toString();
|
||||
result.type = userTypeForString(object.value("type").toString());
|
||||
return result;
|
||||
}
|
||||
|
||||
static QList<User> usersFromJson(const QJsonArray &array)
|
||||
{
|
||||
QList<User> result;
|
||||
for (const QJsonValue &value : array) {
|
||||
User user = userFromJson(value.toObject());
|
||||
if (!user.error.isEmpty()) // add this error to result.error?
|
||||
continue;
|
||||
result.append(user);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static IssueCount issueCountFromJson(const QJsonObject &object)
|
||||
{
|
||||
IssueCount result;
|
||||
if (object.isEmpty()) {
|
||||
result.error = "Not an issue count object.";
|
||||
return result;
|
||||
}
|
||||
result.added = object.value("Added").toInt();
|
||||
result.removed = object.value("Removed").toInt();
|
||||
result.total = object.value("Total").toInt();
|
||||
return result;
|
||||
}
|
||||
|
||||
static QList<IssueCount> issueCountsFromJson(const QJsonObject &object)
|
||||
{
|
||||
QList<IssueCount> result;
|
||||
|
||||
const QStringList keys = object.keys();
|
||||
for (const QString &k : keys) {
|
||||
IssueCount issue = issueCountFromJson(object.value(k).toObject());
|
||||
if (!issue.error.isEmpty()) // add this error to result.error?
|
||||
continue;
|
||||
issue.issueKind = k;
|
||||
result.append(issue);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static ResultVersion versionFromJson(const QJsonObject &object)
|
||||
{
|
||||
ResultVersion result;
|
||||
if (object.isEmpty()) {
|
||||
result.error = "Not a version object.";
|
||||
return result;
|
||||
}
|
||||
const QJsonValue issuesValue = object.value("issueCounts");
|
||||
if (!issuesValue.isObject()) {
|
||||
result.error = "Not an object (issueCounts).";
|
||||
return result;
|
||||
}
|
||||
result.issueCounts = issueCountsFromJson(issuesValue.toObject());
|
||||
result.timeStamp = object.value("date").toString();
|
||||
result.name = object.value("name").toString();
|
||||
result.linesOfCode = object.value("linesOfCode").toInt();
|
||||
return result;
|
||||
}
|
||||
|
||||
static QList<ResultVersion> versionsFromJson(const QJsonArray &array)
|
||||
{
|
||||
QList<ResultVersion> result;
|
||||
for (const QJsonValue &value : array) {
|
||||
ResultVersion version = versionFromJson(value.toObject());
|
||||
if (!version.error.isEmpty()) // add this error to result.error?
|
||||
continue;
|
||||
result.append(version);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static IssueKind issueKindFromJson(const QJsonObject &object)
|
||||
{
|
||||
IssueKind result;
|
||||
if (object.isEmpty()) {
|
||||
result.error = "Not an issue kind object.";
|
||||
return result;
|
||||
}
|
||||
result.prefix = object.value("prefix").toString();
|
||||
result.niceSingular = object.value("niceSingularName").toString();
|
||||
result.nicePlural = object.value("nicePluralName").toString();
|
||||
return result;
|
||||
}
|
||||
|
||||
static QList<IssueKind> issueKindsFromJson(const QJsonArray &array)
|
||||
{
|
||||
QList<IssueKind> result;
|
||||
for (const QJsonValue &value : array) {
|
||||
IssueKind kind = issueKindFromJson(value.toObject());
|
||||
if (!kind.error.isEmpty()) // add this error to result.error?
|
||||
continue;
|
||||
result.append(kind);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace ResultParser {
|
||||
|
||||
DashboardInfo parseDashboardInfo(const QByteArray &input)
|
||||
@@ -236,41 +120,18 @@ DashboardInfo parseDashboardInfo(const QByteArray &input)
|
||||
return result;
|
||||
}
|
||||
|
||||
ProjectInfo parseProjectInfo(const QByteArray &input)
|
||||
Utils::expected_str<Dto::ProjectInfoDto> parseProjectInfo(const QByteArray &input)
|
||||
{
|
||||
ProjectInfo result;
|
||||
|
||||
auto [header, body] = splitHeaderAndBody(input);
|
||||
auto [error, doc] = prehandleHeaderAndBody(header, body);
|
||||
if (!error.error.isEmpty()) {
|
||||
result.error = error.error;
|
||||
return result;
|
||||
if (!error.error.isEmpty())
|
||||
return tl::make_unexpected(std::move(error.error));
|
||||
try
|
||||
{
|
||||
return { Dto::ProjectInfoDto::deserialize(body) };
|
||||
} catch (const Dto::invalid_dto_exception &e) {
|
||||
return tl::make_unexpected(QString::fromUtf8(e.what()));
|
||||
}
|
||||
|
||||
const QJsonObject object = doc.object();
|
||||
result.name = object.value("name").toString();
|
||||
|
||||
const QJsonValue usersValue = object.value("users");
|
||||
if (!usersValue.isArray()) {
|
||||
result.error = "Malformed json response (users).";
|
||||
return result;
|
||||
}
|
||||
result.users = usersFromJson(usersValue.toArray());
|
||||
|
||||
const QJsonValue versionsValue = object.value("versions");
|
||||
if (!versionsValue.isArray()) {
|
||||
result.error = "Malformed json response (versions).";
|
||||
return result;
|
||||
}
|
||||
result.versions = versionsFromJson(versionsValue.toArray());
|
||||
|
||||
const QJsonValue issueKindsValue = object.value("issueKinds");
|
||||
if (!issueKindsValue.isArray()) {
|
||||
result.error = "Malformed json response (issueKinds).";
|
||||
return result;
|
||||
}
|
||||
result.issueKinds = issueKindsFromJson(issueKindsValue.toArray());
|
||||
return result;
|
||||
}
|
||||
|
||||
static QRegularExpression issueCsvLineRegex(const QByteArray &firstCsvLine)
|
||||
|
@@ -3,6 +3,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "dashboard/dto.h"
|
||||
|
||||
#include <utils/expected.h>
|
||||
|
||||
#include <QList>
|
||||
|
||||
namespace Axivion::Internal {
|
||||
@@ -27,49 +31,6 @@ public:
|
||||
QList<Project> projects;
|
||||
};
|
||||
|
||||
class User : public BaseResult
|
||||
{
|
||||
public:
|
||||
QString name;
|
||||
QString displayName;
|
||||
enum UserType { Dashboard, Virtual, Unknown } type;
|
||||
};
|
||||
|
||||
class IssueKind : public BaseResult
|
||||
{
|
||||
public:
|
||||
QString prefix;
|
||||
QString niceSingular;
|
||||
QString nicePlural;
|
||||
};
|
||||
|
||||
class IssueCount : public BaseResult
|
||||
{
|
||||
public:
|
||||
QString issueKind;
|
||||
int total = 0;
|
||||
int added = 0;
|
||||
int removed = 0;
|
||||
};
|
||||
|
||||
class ResultVersion : public BaseResult
|
||||
{
|
||||
public:
|
||||
QString name;
|
||||
QString timeStamp;
|
||||
QList<IssueCount> issueCounts;
|
||||
int linesOfCode = 0;
|
||||
};
|
||||
|
||||
class ProjectInfo : public BaseResult
|
||||
{
|
||||
public:
|
||||
QString name;
|
||||
QList<User> users;
|
||||
QList<ResultVersion> versions;
|
||||
QList<IssueKind> issueKinds;
|
||||
};
|
||||
|
||||
class ShortIssue : public BaseResult
|
||||
{
|
||||
public:
|
||||
@@ -92,7 +53,7 @@ public:
|
||||
namespace ResultParser {
|
||||
|
||||
DashboardInfo parseDashboardInfo(const QByteArray &input);
|
||||
ProjectInfo parseProjectInfo(const QByteArray &input);
|
||||
Utils::expected_str<Dto::ProjectInfoDto> parseProjectInfo(const QByteArray &input);
|
||||
IssuesList parseIssuesList(const QByteArray &input);
|
||||
QString parseRuleInfo(const QByteArray &input);
|
||||
|
||||
|
Reference in New Issue
Block a user