summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRémi Nicole <nicole@kolabsystems.com>2018-02-26 18:19:43 +0100
committerChristian Mollekopf <chrigi_1@fastmail.fm>2018-02-26 18:20:13 +0100
commit331f75d4da056ddb235be45a3784d2c19e545211 (patch)
tree64adc5432725e6d484012acfcea64b95b5d1711f
parent2dc4d380f8c0cc90aa0dec67a826703c3ceb34af (diff)
downloadkube-331f75d4da056ddb235be45a3784d2c19e545211.tar.gz
kube-331f75d4da056ddb235be45a3784d2c19e545211.zip
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
-rw-r--r--framework/src/domain/maillistmodel.cpp33
-rw-r--r--framework/src/domain/maillistmodel.h4
-rw-r--r--framework/src/sinkfabric.cpp7
-rw-r--r--tests/teststore.cpp17
-rw-r--r--views/log/main.qml153
-rw-r--r--views/log/qml/View.qml67
6 files changed, 269 insertions, 12 deletions
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
400{ 400{
401 return false; 401 return false;
402} 402}
403
404void MailListModel::setEntityId(const QString &id)
405{
406 qDebug() << "Running mail query for mail with ID:" << id;
407 using namespace Sink::ApplicationDomain;
408 Sink::Query query;
409 query.setFlags(Sink::Query::LiveQuery);
410 query.filter(id.toUtf8());
411 query.request<Mail::Subject>();
412 query.request<Mail::Sender>();
413 query.request<Mail::To>();
414 query.request<Mail::Cc>();
415 query.request<Mail::Bcc>();
416 query.request<Mail::Date>();
417 query.request<Mail::Unread>();
418 query.request<Mail::Important>();
419 query.request<Mail::Draft>();
420 query.request<Mail::Folder>();
421 query.request<Mail::Sent>();
422 query.request<Mail::Trash>();
423 query.request<Mail::MimeMessage>();
424 query.request<Mail::FullPayloadAvailable>();
425 mFetchMails = true;
426 mFetchedMails.clear();
427 // Latest mail at the top
428 sort(0, Qt::DescendingOrder);
429 runQuery(query);
430}
431
432QString MailListModel::entityId() const
433{
434 return {};
435}
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
33 Q_PROPERTY (QVariant mail READ mail WRITE setMail) 33 Q_PROPERTY (QVariant mail READ mail WRITE setMail)
34 Q_PROPERTY (bool showDrafts READ showDrafts WRITE setShowDrafts) 34 Q_PROPERTY (bool showDrafts READ showDrafts WRITE setShowDrafts)
35 Q_PROPERTY (bool showInbox READ showInbox WRITE setShowInbox) 35 Q_PROPERTY (bool showInbox READ showInbox WRITE setShowInbox)
36 Q_PROPERTY (QString entityId READ entityId WRITE setEntityId)
36 37
37 Q_PROPERTY (QString filter READ filter WRITE setFilter) 38 Q_PROPERTY (QString filter READ filter WRITE setFilter)
38 39
@@ -93,6 +94,9 @@ public:
93 void setShowInbox(bool); 94 void setShowInbox(bool);
94 bool showInbox() const; 95 bool showInbox() const;
95 96
97 void setEntityId(const QString &id);
98 QString entityId() const;
99
96private: 100private:
97 void fetchMail(Sink::ApplicationDomain::Mail::Ptr mail); 101 void fetchMail(Sink::ApplicationDomain::Mail::Ptr mail);
98 102
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:
152 QVariantMap message; 152 QVariantMap message;
153 if (notification.type == Sink::Notification::Warning) { 153 if (notification.type == Sink::Notification::Warning) {
154 message["type"] = "warning"; 154 message["type"] = "warning";
155
156 QVariantList entities;
157 for(const auto &entity : notification.entities) {
158 entities << entity;
159 }
160 message["entities"] = entities;
161
155 message["resource"] = QString{notification.resource}; 162 message["resource"] = QString{notification.resource};
156 if (notification.code == Sink::ApplicationDomain::TransmissionError) { 163 if (notification.code == Sink::ApplicationDomain::TransmissionError) {
157 message["message"] = QObject::tr("Failed to send message."); 164 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)
160 using namespace Sink::ApplicationDomain; 160 using namespace Sink::ApplicationDomain;
161 const auto list = loadList(type, filter); 161 const auto list = loadList(type, filter);
162 if (!list.isEmpty()) { 162 if (!list.isEmpty()) {
163 if (list.size() > 1) {
164 qWarning() << "While loading" << type << "with filter" << filter
165 << "; got multiple elements, but returning the first one.";
166 }
163 return list.first(); 167 return list.first();
164 } 168 }
165 return {}; 169 return {};
166} 170}
167
168template <typename T> 171template <typename T>
169QVariantList toVariantList(const QList<T> &list) 172QVariantList toVariantList(const QList<T> &list)
170{ 173{
@@ -183,6 +186,17 @@ QVariantList TestStore::loadList(const QByteArray &type, const QVariantMap &filt
183 if (filter.contains("resource")) { 186 if (filter.contains("resource")) {
184 query.resourceFilter(filter.value("resource").toByteArray()); 187 query.resourceFilter(filter.value("resource").toByteArray());
185 } 188 }
189
190 for (QVariantMap::const_iterator it = filter.begin(); it != filter.end(); ++it) {
191 if (it.key() == "messageId") {
192 query.filter<Mail::MessageId>(it.value());
193 } else if (it.key() == "draft") {
194 query.filter<Mail::Draft>(it.value());
195 } else if (it.key() == "subject") {
196 query.filter<Mail::Subject>(it.value());
197 }
198 }
199
186 if (type == "mail") { 200 if (type == "mail") {
187 return toVariantList(Sink::Store::read<Mail>(query)); 201 return toVariantList(Sink::Store::read<Mail>(query));
188 } 202 }
@@ -205,6 +219,7 @@ QVariantMap TestStore::read(const QVariant &object)
205 using namespace Sink::ApplicationDomain; 219 using namespace Sink::ApplicationDomain;
206 QVariantMap map; 220 QVariantMap map;
207 if (auto mail = object.value<Mail::Ptr>()) { 221 if (auto mail = object.value<Mail::Ptr>()) {
222 map.insert("uid", mail->identifier());
208 map.insert("subject", mail->getSubject()); 223 map.insert("subject", mail->getSubject());
209 map.insert("draft", mail->getDraft()); 224 map.insert("draft", mail->getDraft());
210 return map; 225 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 @@
1/*
2 * Copyright (C) 2018 Christian Mollekopf, <mollekopf@kolabsys.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19import QtQuick 2.7
20import QtQuick.Controls 2.0
21import QtQuick.Window 2.0
22
23import org.kube.framework 1.0 as Kube
24import org.kube.test 1.0
25import "qml"
26
27ApplicationWindow {
28 id: app
29 height: Screen.desktopAvailableHeight * 0.8
30 width: Screen.desktopAvailableWidth * 0.8
31
32 Component.onCompleted: {
33 var initialState = {
34 accounts: [{
35 id: "account1",
36 name: "Test Account"
37 }],
38 identities: [{
39 account: "account1",
40 name: "Test Identity",
41 address: "identity@example.org"
42 }],
43 resources: [{
44 id: "resource1",
45 account: "account1",
46 type: "dummy"
47 },
48 {
49 id: "resource2",
50 account: "account1",
51 type: "mailtransport"
52 }],
53 folders: [{
54 id: "folder1",
55 resource: "resource1",
56 name: "Folder 1",
57 specialpurpose: ["drafts"],
58 mails: [{
59 resource: "resource1",
60 messageId: "<msg1@test.com>",
61 date: "2017-07-24T15:46:29",
62 subject: "subject1",
63 body: "body",
64 to: ["to@example.org"],
65 cc: ["cc@example.org"],
66 bcc: ["bcc@example.org"],
67 draft: true
68 },
69 {
70 resource: "resource1",
71 messageId: "<msg2@test.com>",
72 date: "2017-07-23T15:46:29",
73 subject: "LooooooooooooooooooooooooooooooooooooooooooooooooooooooooonggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggEnd",
74 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",
75 to: ["toLoooooooooooooooooooooooooooooooooooooooooooooooooong@example.org"],
76 cc: ["ccLoooooooooooooooooooooooooooooooooooooooooooooooooong@example.org"],
77 bcc: ["bccLoooooooooooooooooooooooooooooooooooooooooooooooooong@example.org"],
78 draft: true
79 }
80 ]
81 }],
82 }
83 TestStore.setup(initialState)
84 Kube.Fabric.postMessage(
85 Kube.Messages.notification,
86 {
87 "type": Kube.Notifications.error,
88 "subtype": Kube.Notifications.loginError,
89 message: "merge1",
90 resource: "resource1",
91 entities: []
92 }
93 );
94 Kube.Fabric.postMessage(
95 Kube.Messages.notification,
96 {
97 "type": Kube.Notifications.error,
98 "subtype": Kube.Notifications.hostNotFoundError,
99 message: "merge1",
100 resource: "resource1",
101 entities: []
102 }
103 )
104 Kube.Fabric.postMessage(
105 Kube.Messages.notification,
106 {
107 "type": Kube.Notifications.error,
108 "subtype": Kube.Notifications.connectionError,
109 message: "merge1",
110 resource: "resource1",
111 entities: []
112 }
113 )
114 var mail = TestStore.load("mail", {messageId: "msg1@test.com"})
115 var mail_uid = TestStore.read(mail).uid
116 Kube.Fabric.postMessage(
117 Kube.Messages.notification,
118 {
119 "type": Kube.Notifications.error,
120 "subtype": Kube.Notifications.transmissionError,
121 message: "merge1",
122 resource: "resource1",
123 entities: [mail_uid]
124 }
125 )
126 var mail2 = TestStore.load("mail", {messageId: "msg2@test.com"})
127 var mail2_uid = TestStore.read(mail2).uid
128 Kube.Fabric.postMessage(
129 Kube.Messages.notification,
130 {
131 "type": Kube.Notifications.error,
132 "subtype": Kube.Notifications.transmissionError,
133 message: "merge1",
134 resource: "resource1",
135 entities: [mail2_uid]
136 }
137 )
138 Kube.Fabric.postMessage(
139 Kube.Messages.notification,
140 {
141 "type": Kube.Notifications.error,
142 "subtype": "customSubType",
143 message: "merge1",
144 resource: "resource1",
145 entities: []
146 }
147 )
148 }
149
150 View {
151 anchors.fill: parent
152 }
153}
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 {
45 if (message.type == Kube.Notifications.error) { 45 if (message.type == Kube.Notifications.error) {
46 root.pendingError = true 46 root.pendingError = true
47 } 47 }
48 var error = {timestamp: new Date(), message: message.message, details: message.details, resource: message.resource} 48
49 var error = {
50 timestamp: new Date(),
51 message: message.message,
52 details: message.details,
53 resource: message.resource,
54 // TODO: if we passed entities as a list, it would get
55 // converted to a ListModel, in all likelihood because of
56 // ListDelegate, which we should rewrite in C++
57 entities: {elements: message.entities}
58 }
59
49 if (logModel.count > 0) { 60 if (logModel.count > 0) {
50 var lastEntry = logModel.get(0) 61 var lastEntry = logModel.get(0)
51 //Merge if we get an entry of the same subtype 62 //Merge if we get an entry of the same subtype
@@ -89,6 +100,8 @@ Controls.SplitView {
89 } else { 100 } else {
90 details.subtype = "" 101 details.subtype = ""
91 } 102 }
103
104 details.entities = error.entities
92 } 105 }
93 106
94 delegate: Kube.ListDelegate { 107 delegate: Kube.ListDelegate {
@@ -145,6 +158,7 @@ Controls.SplitView {
145 property date timestamp 158 property date timestamp
146 property string message: "" 159 property string message: ""
147 property string resourceId: "" 160 property string resourceId: ""
161 property var entities: []
148 162
149 Kube.ModelIndexRetriever { 163 Kube.ModelIndexRetriever {
150 id: retriever 164 id: retriever
@@ -166,6 +180,7 @@ Controls.SplitView {
166 property string resourceId: details.resourceId 180 property string resourceId: details.resourceId
167 property string accountId: retriever.currentData ? retriever.currentData.accountId : "" 181 property string accountId: retriever.currentData ? retriever.currentData.accountId : ""
168 property string accountName: retriever.currentData ? retriever.currentData.name : "" 182 property string accountName: retriever.currentData ? retriever.currentData.name : ""
183 property var entities: details.entities
169 184
170 function getComponent(subtype) { 185 function getComponent(subtype) {
171 if (subtype == Kube.Notifications.loginError) { 186 if (subtype == Kube.Notifications.loginError) {
@@ -340,19 +355,49 @@ Controls.SplitView {
340 right: parent.right 355 right: parent.right
341 } 356 }
342 spacing: Kube.Units.largeSpacing 357 spacing: Kube.Units.largeSpacing
358
359 Kube.Heading {
360 id: heading
361 text: qsTr("Failed to send the message.")
362 color: Kube.Colors.warningColor
363 }
364
343 Column { 365 Column {
344 Kube.Heading { 366 spacing: Kube.Units.largeSpacing
345 id: heading 367
346 text: qsTr("Failed to send the message.") 368 Repeater {
347 color: Kube.Colors.warningColor 369 model: Kube.MailListModel {
348 } 370 entityId: entities.elements[0]
349 Kube.Label { 371 }
350 id: subHeadline 372 delegate: Column {
351 text: accountName 373 id: subHeadline
352 color: Kube.Colors.disabledTextColor 374
353 wrapMode: Text.Wrap 375 Kube.Label {
376 text: qsTr("Account") + ": " + accountName
377 color: Kube.Colors.disabledTextColor
378 wrapMode: Text.Wrap
379 }
380 Kube.Label {
381 text: qsTr("Subject") + ": " + model.subject
382 color: Kube.Colors.disabledTextColor
383 wrapMode: Text.Wrap
384 }
385 Kube.Label {
386 text: qsTr("To") + ": " + model.to
387 color: Kube.Colors.disabledTextColor
388 wrapMode: Text.Wrap
389 }
390 Kube.Label {
391 visible: !!model.cc
392 text: qsTr("Cc") + ": " + model.cc;
393 color: Kube.Colors.disabledTextColor
394 wrapMode: Text.Wrap
395 }
396
397 }
354 } 398 }
355 } 399 }
400
356 Kube.Button { 401 Kube.Button {
357 text: qsTr("Try again") 402 text: qsTr("Try again")
358 onClicked: { 403 onClicked: {