forked from Silverfish/proton-bridge
feat(GODT-2791): Parse the Bug Report Flow description file and ensure forward compatibility (GODT-2789).
This commit is contained in:
committed by
Romain Le Jeune
parent
1a2783a63b
commit
86e115b2f3
@ -37,6 +37,15 @@
|
|||||||
using namespace bridgepp;
|
using namespace bridgepp;
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
|
||||||
|
QString const bugReportFile = ":qml/Resources/bug_report_flow.json";
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
//
|
//
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
@ -89,7 +98,8 @@ void QMLBackend::init(GRPCConfig const &serviceConfig) {
|
|||||||
this->setUseSSLForIMAP(sslForIMAP);
|
this->setUseSSLForIMAP(sslForIMAP);
|
||||||
this->setUseSSLForSMTP(sslForSMTP);
|
this->setUseSSLForSMTP(sslForSMTP);
|
||||||
this->retrieveUserList();
|
this->retrieveUserList();
|
||||||
this->retrieveBugReportFlow();
|
if (!reportFlow_.parse(bugReportFile))
|
||||||
|
app().log().error(QString("Cannot parse BugReportFlow description file: %1").arg(bugReportFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -216,7 +226,10 @@ bool QMLBackend::areSameFileOrFolder(QUrl const &lhs, QUrl const &rhs) const {
|
|||||||
/// \return Set of question for this category.
|
/// \return Set of question for this category.
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
QVariantList QMLBackend::getQuestionSet(quint8 categoryId) const {
|
QVariantList QMLBackend::getQuestionSet(quint8 categoryId) const {
|
||||||
return questionsSet_[categoryId];
|
QVariantList list = reportFlow_.questionSet(categoryId);
|
||||||
|
if (list.count() == 0)
|
||||||
|
app().log().error(QString("Bug category not found (id: %1)").arg(categoryId));
|
||||||
|
return list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -225,7 +238,8 @@ QVariantList QMLBackend::getQuestionSet(quint8 categoryId) const {
|
|||||||
/// \param[in] answer The answer to that question.
|
/// \param[in] answer The answer to that question.
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
void QMLBackend::setQuestionAnswer(quint8 questionId, QString const &answer) {
|
void QMLBackend::setQuestionAnswer(quint8 questionId, QString const &answer) {
|
||||||
this->answers_[questionId] = answer;
|
if (!reportFlow_.setAnswer(questionId, answer))
|
||||||
|
app().log().error(QString("Bug Report Question not found (id: %1)").arg(questionId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -234,16 +248,7 @@ void QMLBackend::setQuestionAnswer(quint8 questionId, QString const &answer) {
|
|||||||
/// \return concatenate answers for set of questions.
|
/// \return concatenate answers for set of questions.
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
QString QMLBackend::collectAnswer(quint8 categoryId) const {
|
QString QMLBackend::collectAnswer(quint8 categoryId) const {
|
||||||
QString answers;
|
return reportFlow_.collectAnswers(categoryId);
|
||||||
QVariantList sets = this->getQuestionSet(categoryId);
|
|
||||||
foreach(const QVariant& var, sets) {
|
|
||||||
answers += " - ";
|
|
||||||
answers += questions_[var.toInt()].toMap()["text"].toString();
|
|
||||||
answers += " ";
|
|
||||||
answers += answers_[var.toInt()];
|
|
||||||
answers += "\n\r";
|
|
||||||
}
|
|
||||||
return answers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -622,14 +627,14 @@ QStringList QMLBackend::availableKeychain() const {
|
|||||||
/// \return The value for the 'bugCategories' property.
|
/// \return The value for the 'bugCategories' property.
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
QStringList QMLBackend::bugCategories() const {
|
QStringList QMLBackend::bugCategories() const {
|
||||||
return categories_;
|
return reportFlow_.categories();
|
||||||
}
|
}
|
||||||
|
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
/// \return The value for the 'bugQuestions' property.
|
/// \return The value for the 'bugQuestions' property.
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
QVariantList QMLBackend::bugQuestions() const {
|
QVariantList QMLBackend::bugQuestions() const {
|
||||||
return questions_;
|
return reportFlow_.questions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1221,31 +1226,6 @@ void QMLBackend::retrieveUserList() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//****************************************************************************************************************************************************
|
|
||||||
//
|
|
||||||
//****************************************************************************************************************************************************
|
|
||||||
void QMLBackend::retrieveBugReportFlow() {
|
|
||||||
categories_.clear();
|
|
||||||
questions_.clear();
|
|
||||||
questionsSet_.clear();
|
|
||||||
QString val;
|
|
||||||
QFile file;
|
|
||||||
file.setFileName(":qml/Resources/bug_report_flow.json");
|
|
||||||
file.open(QIODevice::ReadOnly | QIODevice::Text);
|
|
||||||
val = file.readAll();
|
|
||||||
file.close();
|
|
||||||
QJsonDocument d = QJsonDocument::fromJson(val.toUtf8());
|
|
||||||
QJsonObject root = d.object();
|
|
||||||
QJsonObject data = root.value(QString("data_v1.0.0")).toObject();
|
|
||||||
QJsonArray categoriesJson = data.value(QString("categories")).toArray();
|
|
||||||
foreach (const QJsonValue & v, categoriesJson) {
|
|
||||||
categories_.append(v.toObject()["name"].toString());
|
|
||||||
questionsSet_.append(v.toObject()["questions"].toArray().toVariantList());
|
|
||||||
}
|
|
||||||
questions_ = data.value(QString("questions")).toArray().toVariantList();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
//
|
//
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
|
|||||||
@ -24,6 +24,7 @@
|
|||||||
#include "BuildConfig.h"
|
#include "BuildConfig.h"
|
||||||
#include "TrayIcon.h"
|
#include "TrayIcon.h"
|
||||||
#include "UserList.h"
|
#include "UserList.h"
|
||||||
|
#include <bridgepp/BugReportFlow/BugReportFlow.h>
|
||||||
#include <bridgepp/GRPC/GRPCClient.h>
|
#include <bridgepp/GRPC/GRPCClient.h>
|
||||||
#include <bridgepp/GRPC/GRPCUtils.h>
|
#include <bridgepp/GRPC/GRPCUtils.h>
|
||||||
#include <bridgepp/Worker/Overseer.h>
|
#include <bridgepp/Worker/Overseer.h>
|
||||||
@ -278,7 +279,6 @@ private: // member functions
|
|||||||
void retrieveUserList(); ///< Retrieve the list of users via gRPC.
|
void retrieveUserList(); ///< Retrieve the list of users via gRPC.
|
||||||
void connectGrpcEvents(); ///< Connect gRPC that need to be forwarded to QML via backend signals
|
void connectGrpcEvents(); ///< Connect gRPC that need to be forwarded to QML via backend signals
|
||||||
void displayBadEventDialog(QString const& userID); ///< Displays the bad event dialog for a user.
|
void displayBadEventDialog(QString const& userID); ///< Displays the bad event dialog for a user.
|
||||||
void retrieveBugReportFlow(); ///< Get the bug report flow description file and parse it.
|
|
||||||
|
|
||||||
private: // data members
|
private: // data members
|
||||||
UserList *users_ { nullptr }; ///< The user list. Owned by backend.
|
UserList *users_ { nullptr }; ///< The user list. Owned by backend.
|
||||||
@ -294,10 +294,7 @@ private: // data members
|
|||||||
bool isInternetOn_ { true }; ///< Does bridge consider internet as on?
|
bool isInternetOn_ { true }; ///< Does bridge consider internet as on?
|
||||||
QList<QString> badEventDisplayQueue_; ///< THe queue for displaying 'bad event feedback request dialog'.
|
QList<QString> badEventDisplayQueue_; ///< THe queue for displaying 'bad event feedback request dialog'.
|
||||||
std::unique_ptr<TrayIcon> trayIcon_; ///< The tray icon for the application.
|
std::unique_ptr<TrayIcon> trayIcon_; ///< The tray icon for the application.
|
||||||
QStringList categories_; ///< The list of Bug Category parsed from the description file.
|
BugReportFlow reportFlow_; ///< The bug report flow.
|
||||||
QVariantList questions_; ///< The list of Questions parsed from the description file.
|
|
||||||
QList<QVariantList> questionsSet_; ///< Sets of questions per bug category.
|
|
||||||
QMap<quint8, QString> answers_; ///< Map of QuestionId/Answer for the bug form.
|
|
||||||
friend class AppController;
|
friend class AppController;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -48,7 +48,7 @@ SettingsView {
|
|||||||
Label {
|
Label {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
colorScheme: root.colorScheme
|
colorScheme: root.colorScheme
|
||||||
text: qsTr("Give us more details")
|
text: qsTr("Describe the issue")
|
||||||
type: Label.Heading
|
type: Label.Heading
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -33,13 +33,13 @@
|
|||||||
"questions": [
|
"questions": [
|
||||||
{
|
{
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"text": "What did you expect to happen?",
|
"text": "What happened?",
|
||||||
"tips": "Expected behavior",
|
"tips": "Expected behavior",
|
||||||
"type": 1
|
"type": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"text": "What happened instead?",
|
"text": "What did you want or expect to happen?",
|
||||||
"tips": "Result",
|
"tips": "Result",
|
||||||
"type": 1
|
"type": 1
|
||||||
},
|
},
|
||||||
@ -51,15 +51,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 3,
|
"id": 3,
|
||||||
"text": "Can you reproduce your issue?",
|
"text": "Can you reproduce this issue? (If you repeat the actions, the same thing happens.)",
|
||||||
"type": 2,
|
"type": 2,
|
||||||
"answerList": ["yes", "no", "I don't know"]
|
"answerList": ["Yes", "No", "I don't know"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 4,
|
"id": 4,
|
||||||
"text": "Do you have such software running?",
|
"text": "Are you running any of these software?",
|
||||||
"type": 3,
|
"type": 3,
|
||||||
"answerList": ["VPN", "anti-virus", "firewall", "cache cleaner", "None of this"]
|
"answerList": ["VPN", "Antivirus", "Firewall", "Cache cleaner", "None of the above"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -135,6 +135,7 @@ add_custom_command(
|
|||||||
|
|
||||||
|
|
||||||
add_library(bridgepp
|
add_library(bridgepp
|
||||||
|
bridgepp/BugReportFlow/BugReportFlow.cpp bridgepp/BugReportFlow/BugReportFlow.h
|
||||||
bridgepp/BridgeUtils.cpp bridgepp/BridgeUtils.h
|
bridgepp/BridgeUtils.cpp bridgepp/BridgeUtils.h
|
||||||
bridgepp/CLI/CLIUtils.cpp bridgepp/CLI/CLIUtils.h
|
bridgepp/CLI/CLIUtils.cpp bridgepp/CLI/CLIUtils.h
|
||||||
bridgepp/Exception/Exception.h bridgepp/Exception/Exception.cpp
|
bridgepp/Exception/Exception.h bridgepp/Exception/Exception.cpp
|
||||||
|
|||||||
@ -0,0 +1,172 @@
|
|||||||
|
// Copyright (c) 2023 Proton AG
|
||||||
|
//
|
||||||
|
// This file is part of Proton Mail Bridge.
|
||||||
|
//
|
||||||
|
// Proton Mail Bridge is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "BugReportFlow.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
|
||||||
|
QString const currentFormatVersion = "1.0.0";
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
//
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
BugReportFlow::BugReportFlow() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
/// \param[in] filepath The path of the file to parse.
|
||||||
|
/// \return True iff the file can be properly parsed.
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
bool BugReportFlow::parse(const QString& filepath) {
|
||||||
|
if (!QFile(filepath).exists())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
this->filepath_ = filepath;
|
||||||
|
return parseFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
/// \param[in] categoryId The id of the bug category.
|
||||||
|
/// \return Set of question for this category.
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
QVariantList BugReportFlow::questionSet(quint8 categoryId) const {
|
||||||
|
if (categoryId >= questionsSet_.count() - 1)
|
||||||
|
return QVariantList();
|
||||||
|
return questionsSet_[categoryId];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
/// \param[in] questionId The id of the question.
|
||||||
|
/// \param[in] answer The answer to that question.
|
||||||
|
/// \return true iff questionId match an existing question.
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
bool BugReportFlow::setAnswer(quint8 questionId, QString const &answer) {
|
||||||
|
if (questionId >= questions_.count() - 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
this->answers_[questionId] = answer;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
/// \param[in] categoryId The id of the question set.
|
||||||
|
/// \return concatenate answers for set of questions.
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
QString BugReportFlow::collectAnswers(quint8 categoryId) const {
|
||||||
|
QString answers;
|
||||||
|
|
||||||
|
QVariantList sets = this->questionSet(categoryId);
|
||||||
|
foreach(const QVariant& var, sets) {
|
||||||
|
answers += " - ";
|
||||||
|
answers += questions_[var.toInt()].toMap()["text"].toString();
|
||||||
|
answers += " ";
|
||||||
|
answers += answers_[var.toInt()];
|
||||||
|
answers += "\n\r";
|
||||||
|
}
|
||||||
|
return answers;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
/// \return The value for the 'bugCategories' property.
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
QStringList BugReportFlow::categories() const {
|
||||||
|
return categories_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
/// \return The value for the 'bugQuestions' property.
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
QVariantList BugReportFlow::questions() const {
|
||||||
|
return questions_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
//
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
bool BugReportFlow::parseFile() {
|
||||||
|
categories_.clear();
|
||||||
|
questions_.clear();
|
||||||
|
questionsSet_.clear();
|
||||||
|
|
||||||
|
QJsonObject data = getJsonDataObj(getJsonRootObj());
|
||||||
|
|
||||||
|
QJsonArray categoriesJson = data.value("categories").toArray();
|
||||||
|
foreach (const QJsonValue & v, categoriesJson) {
|
||||||
|
categories_.append(v.toObject()["name"].toString());
|
||||||
|
questionsSet_.append(v.toObject()["questions"].toArray().toVariantList());
|
||||||
|
}
|
||||||
|
questions_ = data.value("questions").toArray().toVariantList();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject BugReportFlow::getJsonRootObj() {
|
||||||
|
QFile file(filepath_);
|
||||||
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||||
|
return QJsonObject();
|
||||||
|
|
||||||
|
const QString& val = file.readAll();
|
||||||
|
file.close();
|
||||||
|
QJsonDocument d = QJsonDocument::fromJson(val.toUtf8());
|
||||||
|
return d.object();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QJsonObject BugReportFlow::getJsonDataObj(const QJsonObject& root) {
|
||||||
|
QString version = getJsonVersion(root);
|
||||||
|
if (version.isEmpty())
|
||||||
|
return QJsonObject();
|
||||||
|
|
||||||
|
QJsonValue data = root.value(QString("data_v%1").arg(version));
|
||||||
|
if (data == QJsonValue::Undefined || !data.isObject())
|
||||||
|
return QJsonObject();
|
||||||
|
QJsonObject dataObj = data.toObject();
|
||||||
|
|
||||||
|
return migrateData(dataObj, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QString BugReportFlow::getJsonVersion(const QJsonObject& root) {
|
||||||
|
QJsonValue metadata = root.value("metadata");
|
||||||
|
if (metadata == QJsonValue::Undefined || !metadata.isObject()) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
QJsonValue version = metadata.toObject().value("version");
|
||||||
|
if (version == QJsonValue::Undefined || !version.isString()) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
return version.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QJsonObject BugReportFlow::migrateData(const QJsonObject& data, const QString& version) {
|
||||||
|
if (version != currentFormatVersion)
|
||||||
|
return QJsonObject();
|
||||||
|
// nothing to migrate now but migration should be done here.
|
||||||
|
return data;
|
||||||
|
}
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
// Copyright (c) 2023 Proton AG
|
||||||
|
//
|
||||||
|
// This file is part of Proton Mail Bridge.
|
||||||
|
//
|
||||||
|
// Proton Mail Bridge is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef BRIDGE_GUI_BUG_REPORT_FLOW_H
|
||||||
|
#define BRIDGE_GUI_BUG_REPORT_FLOW_H
|
||||||
|
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
/// \brief Bug Report Flow parser.
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
class BugReportFlow {
|
||||||
|
|
||||||
|
public: // member functions.
|
||||||
|
BugReportFlow(); ///< Default constructor.
|
||||||
|
BugReportFlow(BugReportFlow const &) = delete; ///< Disabled copy-constructor.
|
||||||
|
BugReportFlow(BugReportFlow &&) = delete; ///< Disabled assignment copy-constructor.
|
||||||
|
~BugReportFlow() = default; ///< Destructor.
|
||||||
|
|
||||||
|
bool parse(const QString& filepath); ///< Initialize the Bug Report Flow.
|
||||||
|
|
||||||
|
QVariantList questionSet(quint8 categoryId) const; ///< Retrieve the set of question for a given bug category.
|
||||||
|
bool setAnswer(quint8 questionId, QString const &answer); ///< Feed an answer for a given question.
|
||||||
|
QString collectAnswers(quint8 categoryId) const; ///< Collect answer for a given set of questions.
|
||||||
|
QStringList categories() const; ///< Getter for the 'bugCategories' property.
|
||||||
|
QVariantList questions() const; ///< Getter for the 'bugQuestions' property.
|
||||||
|
|
||||||
|
private: // member functions
|
||||||
|
bool parseFile(); ///< Parse the bug report flow description file.
|
||||||
|
QJsonObject getJsonRootObj(); ///< Extract the JSON root object.
|
||||||
|
QJsonObject getJsonDataObj(const QJsonObject& root); ///< Extract the JSON data object.
|
||||||
|
QString getJsonVersion(const QJsonObject& root); ///< Extract the JSON version of the file.
|
||||||
|
QJsonObject migrateData(const QJsonObject& data, const QString& version); ///< Migrate data if needed/possible.
|
||||||
|
|
||||||
|
private: // data members
|
||||||
|
QString filepath_; ///< The file path of the BugReportFlow description file.
|
||||||
|
QStringList categories_; ///< The list of Bug Category parsed from the description file.
|
||||||
|
QVariantList questions_; ///< The list of Questions parsed from the description file.
|
||||||
|
QList<QVariantList> questionsSet_; ///< Sets of questions per bug category.
|
||||||
|
QMap<quint8, QString> answers_; ///< Map of QuestionId/Answer for the bug form.
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BRIDGE_GUI_BUG_REPORT_FLOW_H
|
||||||
Reference in New Issue
Block a user