feat(GODT-2793): Feed the bug report body with the answered questions.

This commit is contained in:
Romain LE JEUNE
2023-07-26 17:09:16 +02:00
committed by Romain Le Jeune
parent 2c2f816f3a
commit c4bcc38c53
9 changed files with 61 additions and 51 deletions

View File

@ -247,7 +247,7 @@ void QMLBackend::setQuestionAnswer(quint8 questionId, QString const &answer) {
/// \param[in] categoryId The id of the question set.
/// \return concatenate answers for set of questions.
//****************************************************************************************************************************************************
QString QMLBackend::collectAnswer(quint8 categoryId) const {
QString QMLBackend::collectAnswers(quint8 categoryId) const {
return reportFlow_.collectAnswers(categoryId);
}

View File

@ -60,7 +60,7 @@ public: // member functions.
Q_INVOKABLE bool areSameFileOrFolder(QUrl const &lhs, QUrl const &rhs) const; ///< Check if two local URL point to the same file.
Q_INVOKABLE QVariantList getQuestionSet(quint8 categoryId) const; ///< Retrieve the set of question for a given bug category.
Q_INVOKABLE void setQuestionAnswer(quint8 questionId, QString const &answer); ///< Feed an answer for a given question.
Q_INVOKABLE QString collectAnswer(quint8 categoryId) const; ///< Collect answer for a given set of questions.
Q_INVOKABLE QString collectAnswers(quint8 categoryId) const; ///< Collect answer for a given set of questions.
public: // Qt/QML properties. Note that the NOTIFY-er signal is required even for read-only properties (QML warning otherwise)
Q_PROPERTY(bool showOnStartup READ showOnStartup NOTIFY showOnStartupChanged)

View File

@ -24,9 +24,6 @@ SettingsView {
signal questionAnswered
function setDefaultValue() {
}
function setCategoryId(catId) {
root.categoryId = catId;
}
@ -38,11 +35,6 @@ SettingsView {
onCategoryIdChanged: {
root.questionSet = Backend.getQuestionSet(root.categoryId)
root.setDefaultValue();
}
onVisibleChanged: {
root.setDefaultValue();
}
Label {
@ -67,7 +59,12 @@ SettingsView {
tips: root.questions[modelData].tips ? root.questions[modelData].tips : ""
label: root.questions[modelData].label ? root.questions[modelData].label : ""
type: root.questions[modelData].type
mandatory: root.questions[modelData].mandatory ? root.questions[modelData].mandatory : false
answerList: root.questions[modelData].answerList ? root.questions[modelData].answerList : []
onAnswerChanged:{
Backend.setQuestionAnswer(modelData, answer);
}
}
}
// fill height so the footer label will always be attached to the bottom

View File

@ -35,10 +35,11 @@ Item {
bugReportFlow.currentIndex = 0;
}
function showBugQuestion() {
bugReportFlow.currentIndex = 1;
bugQuestion.setCategoryId(root.categoryId);
bugReportFlow.currentIndex = 1;
}
function showBugReport() {
bugReport.setCategoryId(root.categoryId);
bugReportFlow.currentIndex = 2;
}

View File

@ -19,6 +19,7 @@ SettingsView {
id: root
property var selectedAddress
property var categoryId:-1
signal bugReportWasSent
@ -26,15 +27,18 @@ SettingsView {
const reEmail = /^[^@]+@[^@]+\.[A-Za-z]+\s*$/;
return reEmail.test(text);
}
function setCategoryId(catId) {
root.categoryId = catId;
}
function setDefaultValue() {
description.text = "";
description.text = Backend.collectAnswers(root.categoryId);
address.text = root.selectedAddress;
emailClient.text = Backend.currentEmailClient;
includeLogs.checked = true;
}
function setDescription(message) {
description.text = message;
}
function submit() {
sendButton.loading = true;
Backend.reportBug(description.text, address.text, emailClient.text, includeLogs.checked);
@ -54,39 +58,19 @@ SettingsView {
TextArea {
id: description
property int _maxLength: 800
property int _minLength: 150
KeyNavigation.priority: KeyNavigation.BeforeItem
KeyNavigation.tab: address
Layout.fillHeight: true
Layout.fillWidth: true
Layout.minimumHeight: heightForLinesVisible(4)
colorScheme: root.colorScheme
hint: description.text.length + "/" + _maxLength
// set implicitHeight to explicit height because se don't
// want TextArea implicitHeight (which is height of all text)
// to be considered in SettingsView internal scroll view
implicitHeight: height
label: qsTr("Description")
placeholderText: qsTr("Tell us what went wrong or isn't working (min. %1 characters).").arg(_minLength)
validator: function (text) {
if (description.text.length < description._minLength) {
return qsTr("Enter a problem description (min. %1 characters).").arg(_minLength);
}
if (description.text.length > description._maxLength) {
return qsTr("Enter a problem description (max. %1 characters).").arg(_maxLength);
}
return;
}
onTextChanged: {
// Rise max length error immediately while typing
if (description.text.length > description._maxLength) {
validate();
}
}
label: qsTr("Your answers")
readOnly : true
}
TextField {
id: address

View File

@ -31,6 +31,7 @@ Item {
property string text: ""
property string tips: ""
property string label: ""
property bool mandatory: false
property var type: QuestionItem.InputType.TextInput
property var answerList: ListModel{}
@ -67,8 +68,30 @@ Item {
Layout.minimumHeight: root.type === QuestionItem.InputType.TextInput ? heightForLinesVisible(2) : 0
colorScheme: root.colorScheme
property int _maxLength: 400
property int _minLength: 10
label: qsTr(root.label)
placeholderText: qsTr(root.tips)
hint: mandatory ? textInput.text.length + "/" + _maxLength : ""
placeholderText: mandatory ? qsTr("%1... (min. %2 characters)").arg(root.text).arg(_minLength) : ""
validator: function (text) {
if (!mandatory)
return;
if (textInput.text.length < textInput._minLength) {
return qsTr("min. %1 characters").arg(_minLength);
}
if (textInput.text.length > textInput._maxLength) {
return qsTr("max. %1 characters").arg(_maxLength);
}
return;
}
onTextChanged: {
// Rise max length error immediately while typing if mandatory field
if (mandatory && textInput.text.length > textInput._maxLength) {
validate();
}
}
visible: root.type === QuestionItem.InputType.TextInput
}
@ -96,10 +119,10 @@ Item {
var str = "";
for (var i = 0; i < buttons.length; ++i) {
if (buttons[i].checked) {
str += buttons[i].text + " ";
str += buttons[i].text + ", ";
}
}
return str;
return str.slice(0, -2);
}
}
Repeater {

View File

@ -35,13 +35,15 @@
"id": 0,
"text": "What happened?",
"tips": "Expected behavior",
"type": 1
"type": 1,
"mandatory": true
},
{
"id": 1,
"text": "What did you want or expect to happen?",
"tips": "Result",
"type": 1
"type": 1,
"mandatory": true
},
{
"id": 2,

View File

@ -129,10 +129,10 @@ TEST_F(BugReportFlowFixture, validFile) {
EXPECT_TRUE(flow_.setAnswer(0, "pwet"));
EXPECT_FALSE(flow_.setAnswer(1, "pwet"));
qDebug() << flow_.collectAnswers(0);
EXPECT_EQ(flow_.collectAnswers(0), " - What happened? pwet\n\r");
EXPECT_EQ(flow_.collectAnswers(0), "Category: I can't receive mail\n\r - What happened?\n\rpwet\n\r");
EXPECT_EQ(flow_.collectAnswers(1), "");
flow_.clearAnswers();
EXPECT_EQ(flow_.collectAnswers(0), " - What happened? \n\r");
EXPECT_EQ(flow_.collectAnswers(0), "Category: I can't receive mail\n\r");
}

View File

@ -97,14 +97,17 @@ bool BugReportFlow::setAnswer(quint8 questionId, QString const &answer) {
//****************************************************************************************************************************************************
QString BugReportFlow::collectAnswers(quint8 categoryId) const {
QString answers;
if (categoryId > categories_.count() - 1)
return answers;
answers += "Category: " + categories_[categoryId] + "\n\r";
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";
for (QVariant const &var: sets) {
const QString& answer = answers_[var.toInt()];
if (answer.isEmpty())
continue;
answers += " - " + questions_[var.toInt()].toMap()["text"].toString() + "\n\r";
answers += answer + "\n\r";
}
return answers;
}
@ -129,7 +132,7 @@ bool BugReportFlow::parseFile() {
QJsonObject data = getJsonDataObj(getJsonRootObj());
QJsonArray categoriesJson = data.value("categories").toArray();
foreach (const QJsonValue & v, categoriesJson) {
for (const QJsonValueRef &v : categoriesJson) {
categories_.append(v.toObject()["name"].toString());
questionsSet_.append(v.toObject()["questions"].toArray().toVariantList());
}