From 331f75d4da056ddb235be45a3784d2c19e545211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Nicole?= Date: Mon, 26 Feb 2018 18:19:43 +0100 Subject: Improvements of the log view Summary: - Add a test view for the log view - Allow passing the `entities` part of Sink messages - That allowed getting information about which mail could not be sent in sink transmission errors Reviewers: cmollekopf Reviewed By: cmollekopf Differential Revision: https://phabricator.kde.org/D10861 --- framework/src/domain/maillistmodel.cpp | 33 +++++++ framework/src/domain/maillistmodel.h | 4 + framework/src/sinkfabric.cpp | 7 ++ tests/teststore.cpp | 17 +++- views/log/main.qml | 153 +++++++++++++++++++++++++++++++++ views/log/qml/View.qml | 67 ++++++++++++--- 6 files changed, 269 insertions(+), 12 deletions(-) create mode 100644 views/log/main.qml diff --git a/framework/src/domain/maillistmodel.cpp b/framework/src/domain/maillistmodel.cpp index e2f52d13..143c8a60 100644 --- a/framework/src/domain/maillistmodel.cpp +++ b/framework/src/domain/maillistmodel.cpp @@ -400,3 +400,36 @@ bool MailListModel::showInbox() const { return false; } + +void MailListModel::setEntityId(const QString &id) +{ + qDebug() << "Running mail query for mail with ID:" << id; + using namespace Sink::ApplicationDomain; + Sink::Query query; + query.setFlags(Sink::Query::LiveQuery); + query.filter(id.toUtf8()); + query.request(); + query.request(); + query.request(); + query.request(); + query.request(); + query.request(); + query.request(); + query.request(); + query.request(); + query.request(); + query.request(); + query.request(); + query.request(); + query.request(); + mFetchMails = true; + mFetchedMails.clear(); + // Latest mail at the top + sort(0, Qt::DescendingOrder); + runQuery(query); +} + +QString MailListModel::entityId() const +{ + return {}; +} diff --git a/framework/src/domain/maillistmodel.h b/framework/src/domain/maillistmodel.h index f83656b9..a6965915 100644 --- a/framework/src/domain/maillistmodel.h +++ b/framework/src/domain/maillistmodel.h @@ -33,6 +33,7 @@ class MailListModel : public QSortFilterProxyModel Q_PROPERTY (QVariant mail READ mail WRITE setMail) Q_PROPERTY (bool showDrafts READ showDrafts WRITE setShowDrafts) Q_PROPERTY (bool showInbox READ showInbox WRITE setShowInbox) + Q_PROPERTY (QString entityId READ entityId WRITE setEntityId) Q_PROPERTY (QString filter READ filter WRITE setFilter) @@ -93,6 +94,9 @@ public: void setShowInbox(bool); bool showInbox() const; + void setEntityId(const QString &id); + QString entityId() const; + private: void fetchMail(Sink::ApplicationDomain::Mail::Ptr mail); diff --git a/framework/src/sinkfabric.cpp b/framework/src/sinkfabric.cpp index 7d780ce3..8492f272 100644 --- a/framework/src/sinkfabric.cpp +++ b/framework/src/sinkfabric.cpp @@ -152,6 +152,13 @@ public: QVariantMap message; if (notification.type == Sink::Notification::Warning) { message["type"] = "warning"; + + QVariantList entities; + for(const auto &entity : notification.entities) { + entities << entity; + } + message["entities"] = entities; + message["resource"] = QString{notification.resource}; if (notification.code == Sink::ApplicationDomain::TransmissionError) { message["message"] = QObject::tr("Failed to send message."); diff --git a/tests/teststore.cpp b/tests/teststore.cpp index e5a3ea88..9d56dd33 100644 --- a/tests/teststore.cpp +++ b/tests/teststore.cpp @@ -160,11 +160,14 @@ QVariant TestStore::load(const QByteArray &type, const QVariantMap &filter) using namespace Sink::ApplicationDomain; const auto list = loadList(type, filter); if (!list.isEmpty()) { + if (list.size() > 1) { + qWarning() << "While loading" << type << "with filter" << filter + << "; got multiple elements, but returning the first one."; + } return list.first(); } return {}; } - template QVariantList toVariantList(const QList &list) { @@ -183,6 +186,17 @@ QVariantList TestStore::loadList(const QByteArray &type, const QVariantMap &filt if (filter.contains("resource")) { query.resourceFilter(filter.value("resource").toByteArray()); } + + for (QVariantMap::const_iterator it = filter.begin(); it != filter.end(); ++it) { + if (it.key() == "messageId") { + query.filter(it.value()); + } else if (it.key() == "draft") { + query.filter(it.value()); + } else if (it.key() == "subject") { + query.filter(it.value()); + } + } + if (type == "mail") { return toVariantList(Sink::Store::read(query)); } @@ -205,6 +219,7 @@ QVariantMap TestStore::read(const QVariant &object) using namespace Sink::ApplicationDomain; QVariantMap map; if (auto mail = object.value()) { + map.insert("uid", mail->identifier()); map.insert("subject", mail->getSubject()); map.insert("draft", mail->getDraft()); return map; diff --git a/views/log/main.qml b/views/log/main.qml new file mode 100644 index 00000000..f4f20582 --- /dev/null +++ b/views/log/main.qml @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2018 Christian Mollekopf, + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Window 2.0 + +import org.kube.framework 1.0 as Kube +import org.kube.test 1.0 +import "qml" + +ApplicationWindow { + id: app + height: Screen.desktopAvailableHeight * 0.8 + width: Screen.desktopAvailableWidth * 0.8 + + Component.onCompleted: { + var initialState = { + accounts: [{ + id: "account1", + name: "Test Account" + }], + identities: [{ + account: "account1", + name: "Test Identity", + address: "identity@example.org" + }], + resources: [{ + id: "resource1", + account: "account1", + type: "dummy" + }, + { + id: "resource2", + account: "account1", + type: "mailtransport" + }], + folders: [{ + id: "folder1", + resource: "resource1", + name: "Folder 1", + specialpurpose: ["drafts"], + mails: [{ + resource: "resource1", + messageId: "", + date: "2017-07-24T15:46:29", + subject: "subject1", + body: "body", + to: ["to@example.org"], + cc: ["cc@example.org"], + bcc: ["bcc@example.org"], + draft: true + }, + { + resource: "resource1", + messageId: "", + date: "2017-07-23T15:46:29", + subject: "LooooooooooooooooooooooooooooooooooooooooooooooooooooooooonggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggEnd", + body: "LooooooooooooooooooooooooooooooooooooooooooooooooooooooooonggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggEnd\nbody\nbody\n\n\nbody\n\n\nbody\n\n\nbody\n\n\nbody\nbody\n\n\nbody\n\n\nbody\n\n\nbody\n\n\nbody\n\n\n\n\n\n\n\n\nbody\nbody\n\n\nbody\n\n\nbody\n\n\nbody\n\n\nbody\n\n\nbody", + to: ["toLoooooooooooooooooooooooooooooooooooooooooooooooooong@example.org"], + cc: ["ccLoooooooooooooooooooooooooooooooooooooooooooooooooong@example.org"], + bcc: ["bccLoooooooooooooooooooooooooooooooooooooooooooooooooong@example.org"], + draft: true + } + ] + }], + } + TestStore.setup(initialState) + Kube.Fabric.postMessage( + Kube.Messages.notification, + { + "type": Kube.Notifications.error, + "subtype": Kube.Notifications.loginError, + message: "merge1", + resource: "resource1", + entities: [] + } + ); + Kube.Fabric.postMessage( + Kube.Messages.notification, + { + "type": Kube.Notifications.error, + "subtype": Kube.Notifications.hostNotFoundError, + message: "merge1", + resource: "resource1", + entities: [] + } + ) + Kube.Fabric.postMessage( + Kube.Messages.notification, + { + "type": Kube.Notifications.error, + "subtype": Kube.Notifications.connectionError, + message: "merge1", + resource: "resource1", + entities: [] + } + ) + var mail = TestStore.load("mail", {messageId: "msg1@test.com"}) + var mail_uid = TestStore.read(mail).uid + Kube.Fabric.postMessage( + Kube.Messages.notification, + { + "type": Kube.Notifications.error, + "subtype": Kube.Notifications.transmissionError, + message: "merge1", + resource: "resource1", + entities: [mail_uid] + } + ) + var mail2 = TestStore.load("mail", {messageId: "msg2@test.com"}) + var mail2_uid = TestStore.read(mail2).uid + Kube.Fabric.postMessage( + Kube.Messages.notification, + { + "type": Kube.Notifications.error, + "subtype": Kube.Notifications.transmissionError, + message: "merge1", + resource: "resource1", + entities: [mail2_uid] + } + ) + Kube.Fabric.postMessage( + Kube.Messages.notification, + { + "type": Kube.Notifications.error, + "subtype": "customSubType", + message: "merge1", + resource: "resource1", + entities: [] + } + ) + } + + View { + anchors.fill: parent + } +} diff --git a/views/log/qml/View.qml b/views/log/qml/View.qml index 14e2d543..7e95e20f 100644 --- a/views/log/qml/View.qml +++ b/views/log/qml/View.qml @@ -45,7 +45,18 @@ Controls.SplitView { if (message.type == Kube.Notifications.error) { root.pendingError = true } - var error = {timestamp: new Date(), message: message.message, details: message.details, resource: message.resource} + + var error = { + timestamp: new Date(), + message: message.message, + details: message.details, + resource: message.resource, + // TODO: if we passed entities as a list, it would get + // converted to a ListModel, in all likelihood because of + // ListDelegate, which we should rewrite in C++ + entities: {elements: message.entities} + } + if (logModel.count > 0) { var lastEntry = logModel.get(0) //Merge if we get an entry of the same subtype @@ -89,6 +100,8 @@ Controls.SplitView { } else { details.subtype = "" } + + details.entities = error.entities } delegate: Kube.ListDelegate { @@ -145,6 +158,7 @@ Controls.SplitView { property date timestamp property string message: "" property string resourceId: "" + property var entities: [] Kube.ModelIndexRetriever { id: retriever @@ -166,6 +180,7 @@ Controls.SplitView { property string resourceId: details.resourceId property string accountId: retriever.currentData ? retriever.currentData.accountId : "" property string accountName: retriever.currentData ? retriever.currentData.name : "" + property var entities: details.entities function getComponent(subtype) { if (subtype == Kube.Notifications.loginError) { @@ -340,19 +355,49 @@ Controls.SplitView { right: parent.right } spacing: Kube.Units.largeSpacing + + Kube.Heading { + id: heading + text: qsTr("Failed to send the message.") + color: Kube.Colors.warningColor + } + Column { - Kube.Heading { - id: heading - text: qsTr("Failed to send the message.") - color: Kube.Colors.warningColor - } - Kube.Label { - id: subHeadline - text: accountName - color: Kube.Colors.disabledTextColor - wrapMode: Text.Wrap + spacing: Kube.Units.largeSpacing + + Repeater { + model: Kube.MailListModel { + entityId: entities.elements[0] + } + delegate: Column { + id: subHeadline + + Kube.Label { + text: qsTr("Account") + ": " + accountName + color: Kube.Colors.disabledTextColor + wrapMode: Text.Wrap + } + Kube.Label { + text: qsTr("Subject") + ": " + model.subject + color: Kube.Colors.disabledTextColor + wrapMode: Text.Wrap + } + Kube.Label { + text: qsTr("To") + ": " + model.to + color: Kube.Colors.disabledTextColor + wrapMode: Text.Wrap + } + Kube.Label { + visible: !!model.cc + text: qsTr("Cc") + ": " + model.cc; + color: Kube.Colors.disabledTextColor + wrapMode: Text.Wrap + } + + } } } + Kube.Button { text: qsTr("Try again") onClicked: { -- cgit v1.2.3