Show global directory errors messages
Previously, only error messages for failed items have been shown.
This commit is contained in:
parent
c78fec4151
commit
c4ccda93c9
|
@ -434,9 +434,10 @@ void Application::printDir(const SyncthingDir *dir)
|
|||
printProperty("Auto-normalize", dir->autoNormalize);
|
||||
printProperty("Rescan interval", TimeSpan::fromSeconds(dir->rescanInterval));
|
||||
printProperty("Min. free disk percentage", dir->minDiskFreePercentage);
|
||||
if (!dir->errors.empty()) {
|
||||
cout << " Errors\n";
|
||||
for (const SyncthingDirError &error : dir->errors) {
|
||||
printProperty("Error", dir->globalError);
|
||||
if (!dir->itemErrors.empty()) {
|
||||
cout << " Failed items\n";
|
||||
for (const SyncthingItemError &error : dir->itemErrors) {
|
||||
printProperty(" - Message", error.message);
|
||||
printProperty(" File", error.path);
|
||||
}
|
||||
|
|
|
@ -1372,7 +1372,15 @@ void SyncthingConnection::readStatusChangedEvent(DateTime eventTime, const QJson
|
|||
int index;
|
||||
if (SyncthingDir *dirInfo = findDirInfo(dir, index)) {
|
||||
// directory is already known -> just update status
|
||||
if (dirInfo->assignStatus(eventData.value(QStringLiteral("to")).toString(), eventTime)) {
|
||||
bool statusChanged = dirInfo->assignStatus(eventData.value(QStringLiteral("to")).toString(), eventTime);
|
||||
if (dirInfo->status == SyncthingDirStatus::OutOfSync) {
|
||||
const QString errorMessage(eventData.value(QStringLiteral("error")).toString());
|
||||
if (!errorMessage.isEmpty()) {
|
||||
dirInfo->globalError = errorMessage;
|
||||
statusChanged = true;
|
||||
}
|
||||
}
|
||||
if (statusChanged) {
|
||||
emit dirStatusChanged(*dirInfo, index);
|
||||
}
|
||||
} else {
|
||||
|
@ -1443,17 +1451,17 @@ void SyncthingConnection::readDirEvent(DateTime eventTime, const QString &eventT
|
|||
for (const QJsonValue &errorVal : errors) {
|
||||
const QJsonObject error(errorVal.toObject());
|
||||
if (!error.isEmpty()) {
|
||||
auto &errors = dirInfo->errors;
|
||||
SyncthingDirError dirError(
|
||||
auto &errors = dirInfo->itemErrors;
|
||||
SyncthingItemError dirError(
|
||||
error.value(QStringLiteral("error")).toString(), error.value(QStringLiteral("path")).toString());
|
||||
if (find(errors.cbegin(), errors.cend(), dirError) == errors.cend()) {
|
||||
errors.emplace_back(move(dirError));
|
||||
dirInfo->assignStatus(SyncthingDirStatus::OutOfSync, eventTime);
|
||||
|
||||
// emit newNotification() for new errors
|
||||
auto &previousErrors = dirInfo->previousErrors;
|
||||
if (find(previousErrors.cbegin(), previousErrors.cend(), dirInfo->errors.back()) == previousErrors.cend()) {
|
||||
emitNotification(eventTime, dirInfo->errors.back().message);
|
||||
const auto &previousErrors = dirInfo->previousItemErrors;
|
||||
if (find(previousErrors.cbegin(), previousErrors.cend(), dirInfo->itemErrors.back()) == previousErrors.cend()) {
|
||||
emitNotification(eventTime, dirInfo->itemErrors.back().message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1586,7 +1594,7 @@ void SyncthingConnection::readItemFinished(DateTime eventTime, const QJsonObject
|
|||
}
|
||||
} else if (dirInfo->status == SyncthingDirStatus::OutOfSync) {
|
||||
// FIXME: find better way to check whether the event is still relevant
|
||||
dirInfo->errors.emplace_back(error, item);
|
||||
dirInfo->itemErrors.emplace_back(error, item);
|
||||
dirInfo->status = SyncthingDirStatus::OutOfSync;
|
||||
emit dirStatusChanged(*dirInfo, index);
|
||||
emitNotification(eventTime, error);
|
||||
|
|
|
@ -31,48 +31,39 @@ QString statusString(SyncthingDirStatus status)
|
|||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Assigns the status from the specified status string.
|
||||
* \returns Returns whether the status has actually changed.
|
||||
*/
|
||||
bool SyncthingDir::assignStatus(const QString &statusStr, ChronoUtilities::DateTime time)
|
||||
bool SyncthingDir::checkWhetherStatusUpdateRelevant(DateTime time)
|
||||
{
|
||||
// ignore old updates
|
||||
if (lastStatusUpdate > time) {
|
||||
return false;
|
||||
} else {
|
||||
lastStatusUpdate = time;
|
||||
}
|
||||
SyncthingDirStatus newStatus;
|
||||
if (statusStr == QLatin1String("idle")) {
|
||||
progressPercentage = 0;
|
||||
newStatus = SyncthingDirStatus::Idle;
|
||||
} else if (statusStr == QLatin1String("scanning")) {
|
||||
newStatus = SyncthingDirStatus::Scanning;
|
||||
} else if (statusStr == QLatin1String("syncing")) {
|
||||
// ensure status changed signal is emitted
|
||||
if (!errors.empty()) {
|
||||
status = SyncthingDirStatus::Unknown;
|
||||
}
|
||||
// errors become obsolete; however errors must be kept as previous errors to be able
|
||||
// to identify new errors occuring during this sync attempt as known errors
|
||||
previousErrors.clear();
|
||||
previousErrors.swap(errors);
|
||||
newStatus = SyncthingDirStatus::Synchronizing;
|
||||
} else if (statusStr == QLatin1String("error")) {
|
||||
progressPercentage = 0;
|
||||
newStatus = SyncthingDirStatus::OutOfSync;
|
||||
} else {
|
||||
newStatus = SyncthingDirStatus::Idle;
|
||||
}
|
||||
if (newStatus == SyncthingDirStatus::Idle) {
|
||||
if (!errors.empty()) {
|
||||
lastStatusUpdate = time;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SyncthingDir::finalizeStatusUpdate(SyncthingDirStatus newStatus)
|
||||
{
|
||||
// check whether out-of-sync or unshared
|
||||
switch (newStatus) {
|
||||
case SyncthingDirStatus::Unknown:
|
||||
case SyncthingDirStatus::Idle:
|
||||
case SyncthingDirStatus::Unshared:
|
||||
if (!itemErrors.empty()) {
|
||||
newStatus = SyncthingDirStatus::OutOfSync;
|
||||
} else if (devices.size() < 2) {
|
||||
// FIXME: we can assume only own device is assigned, correct?
|
||||
newStatus = SyncthingDirStatus::Unshared;
|
||||
}
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
// clear global error if not out-of-sync anymore
|
||||
if (newStatus != SyncthingDirStatus::OutOfSync) {
|
||||
globalError.clear();
|
||||
}
|
||||
// actuall update the status ...
|
||||
if (newStatus != status) {
|
||||
// ... and also update last scan time
|
||||
switch (status) {
|
||||
case SyncthingDirStatus::Scanning:
|
||||
lastScanTime = DateTime::now();
|
||||
|
@ -85,37 +76,39 @@ bool SyncthingDir::assignStatus(const QString &statusStr, ChronoUtilities::DateT
|
|||
return false;
|
||||
}
|
||||
|
||||
bool SyncthingDir::assignStatus(SyncthingDirStatus newStatus, DateTime time)
|
||||
/*!
|
||||
* \brief Assigns the status from the specified status string.
|
||||
* \returns Returns whether the status has actually changed.
|
||||
*/
|
||||
bool SyncthingDir::assignStatus(const QString &statusStr, ChronoUtilities::DateTime time)
|
||||
{
|
||||
if (lastStatusUpdate > time) {
|
||||
if (!checkWhetherStatusUpdateRelevant(time)) {
|
||||
return false;
|
||||
}
|
||||
// identify statusStr
|
||||
SyncthingDirStatus newStatus;
|
||||
if (statusStr == QLatin1String("idle")) {
|
||||
progressPercentage = 0;
|
||||
newStatus = SyncthingDirStatus::Idle;
|
||||
} else if (statusStr == QLatin1String("scanning")) {
|
||||
newStatus = SyncthingDirStatus::Scanning;
|
||||
} else if (statusStr == QLatin1String("syncing")) {
|
||||
// ensure status changed signal is emitted
|
||||
if (!itemErrors.empty()) {
|
||||
status = SyncthingDirStatus::Unknown;
|
||||
}
|
||||
// errors become obsolete; however errors must be kept as previous errors to be able
|
||||
// to identify new errors occuring during this sync attempt as known errors
|
||||
previousItemErrors.clear();
|
||||
previousItemErrors.swap(itemErrors);
|
||||
newStatus = SyncthingDirStatus::Synchronizing;
|
||||
} else if (statusStr == QLatin1String("error")) {
|
||||
progressPercentage = 0;
|
||||
newStatus = SyncthingDirStatus::OutOfSync;
|
||||
} else {
|
||||
lastStatusUpdate = time;
|
||||
newStatus = SyncthingDirStatus::Idle;
|
||||
}
|
||||
switch (newStatus) {
|
||||
case SyncthingDirStatus::Unknown:
|
||||
case SyncthingDirStatus::Idle:
|
||||
case SyncthingDirStatus::Unshared:
|
||||
if (!errors.empty()) {
|
||||
newStatus = SyncthingDirStatus::OutOfSync;
|
||||
} else if (devices.size() < 2) {
|
||||
// FIXME: we can assume only own device is assigned, correct?
|
||||
newStatus = SyncthingDirStatus::Unshared;
|
||||
}
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
if (newStatus != status) {
|
||||
switch (status) {
|
||||
case SyncthingDirStatus::Scanning:
|
||||
lastScanTime = DateTime::now();
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
status = newStatus;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return finalizeStatusUpdate(newStatus);
|
||||
}
|
||||
|
||||
QString SyncthingDir::statusString() const
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef DATA_SYNCTHINGDIR_H
|
||||
#ifndef DATA_SYNCTHINGDIR_H
|
||||
#define DATA_SYNCTHINGDIR_H
|
||||
|
||||
#include "./global.h"
|
||||
|
@ -24,14 +24,14 @@ Q_ENUM_NS(SyncthingDirStatus)
|
|||
|
||||
QString statusString(SyncthingDirStatus status);
|
||||
|
||||
struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingDirError {
|
||||
SyncthingDirError(const QString &message = QString(), const QString &path = QString())
|
||||
struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingItemError {
|
||||
SyncthingItemError(const QString &message = QString(), const QString &path = QString())
|
||||
: message(message)
|
||||
, path(path)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const SyncthingDirError &other) const
|
||||
bool operator==(const SyncthingItemError &other) const
|
||||
{
|
||||
return message == other.message && path == other.path;
|
||||
}
|
||||
|
@ -81,8 +81,9 @@ struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingDir {
|
|||
ChronoUtilities::DateTime lastStatusUpdate;
|
||||
int progressPercentage = 0;
|
||||
int progressRate = 0;
|
||||
std::vector<SyncthingDirError> errors;
|
||||
std::vector<SyncthingDirError> previousErrors;
|
||||
QString globalError;
|
||||
std::vector<SyncthingItemError> itemErrors;
|
||||
std::vector<SyncthingItemError> previousItemErrors;
|
||||
int globalBytes = 0, globalDeleted = 0, globalFiles = 0;
|
||||
int localBytes = 0, localDeleted = 0, localFiles = 0;
|
||||
int neededByted = 0, neededFiles = 0;
|
||||
|
@ -95,6 +96,10 @@ struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingDir {
|
|||
int blocksToBeDownloaded = 0;
|
||||
unsigned int downloadPercentage = 0;
|
||||
QString downloadLabel;
|
||||
|
||||
private:
|
||||
bool checkWhetherStatusUpdateRelevant(ChronoUtilities::DateTime time);
|
||||
bool finalizeStatusUpdate(SyncthingDirStatus newStatus);
|
||||
};
|
||||
|
||||
inline SyncthingDir::SyncthingDir(const QString &id, const QString &label, const QString &path)
|
||||
|
@ -109,9 +114,14 @@ inline QString SyncthingDir::displayName() const
|
|||
return label.isEmpty() ? id : label;
|
||||
}
|
||||
|
||||
inline bool SyncthingDir::assignStatus(SyncthingDirStatus newStatus, ChronoUtilities::DateTime time)
|
||||
{
|
||||
return checkWhetherStatusUpdateRelevant(time) && finalizeStatusUpdate(newStatus);
|
||||
}
|
||||
|
||||
} // namespace Data
|
||||
|
||||
Q_DECLARE_METATYPE(Data::SyncthingDirError)
|
||||
Q_DECLARE_METATYPE(Data::SyncthingItemError)
|
||||
Q_DECLARE_METATYPE(Data::SyncthingItemDownloadProgress)
|
||||
Q_DECLARE_METATYPE(Data::SyncthingDir)
|
||||
|
||||
|
|
|
@ -173,14 +173,14 @@ void MiscTests::testSyncthingDir()
|
|||
CPPUNIT_ASSERT_EQUAL(updateTime, dir.lastStatusUpdate);
|
||||
CPPUNIT_ASSERT(dir.lastScanTime >= lastScanTime);
|
||||
|
||||
dir.errors.emplace_back(QStringLiteral("message"), QStringLiteral("path"));
|
||||
dir.itemErrors.emplace_back(QStringLiteral("message"), QStringLiteral("path"));
|
||||
CPPUNIT_ASSERT(dir.assignStatus(SyncthingDirStatus::Idle, updateTime += TimeSpan::fromMinutes(1.5)));
|
||||
CPPUNIT_ASSERT_EQUAL(QStringLiteral("out of sync"), dir.statusString());
|
||||
|
||||
CPPUNIT_ASSERT(!dir.assignStatus(SyncthingDirStatus::Idle, updateTime += TimeSpan::fromMinutes(1.5)));
|
||||
CPPUNIT_ASSERT(dir.assignStatus(QStringLiteral("syncing"), updateTime += TimeSpan::fromMinutes(1.5)));
|
||||
|
||||
dir.errors.clear();
|
||||
dir.itemErrors.clear();
|
||||
CPPUNIT_ASSERT(dir.assignStatus(QStringLiteral("error"), updateTime += TimeSpan::fromMinutes(1.5)));
|
||||
CPPUNIT_ASSERT_EQUAL(QStringLiteral("out of sync"), dir.statusString());
|
||||
|
||||
|
@ -190,11 +190,11 @@ void MiscTests::testSyncthingDir()
|
|||
CPPUNIT_ASSERT_MESSAGE("older status discarded", !dir.assignStatus(QStringLiteral("scanning"), updateTime - TimeSpan::fromSeconds(1)));
|
||||
CPPUNIT_ASSERT_EQUAL(QStringLiteral("idle"), dir.statusString());
|
||||
|
||||
dir.errors.emplace_back(QStringLiteral("message"), QStringLiteral("path"));
|
||||
dir.itemErrors.emplace_back(QStringLiteral("message"), QStringLiteral("path"));
|
||||
CPPUNIT_ASSERT(dir.assignStatus(QStringLiteral("idle"), updateTime += TimeSpan::fromMinutes(1.5)));
|
||||
CPPUNIT_ASSERT_EQUAL(QStringLiteral("out of sync"), dir.statusString());
|
||||
|
||||
dir.errors.clear();
|
||||
dir.itemErrors.clear();
|
||||
dir.devices.removeLast();
|
||||
CPPUNIT_ASSERT(dir.assignStatus(QStringLiteral("idle"), updateTime += TimeSpan::fromMinutes(1.5)));
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("dir considered unshared when only one dev present", QStringLiteral("unshared"), dir.statusString());
|
||||
|
|
|
@ -122,9 +122,19 @@ QVariant SyncthingDirectoryModel::data(const QModelIndex &index, int role) const
|
|||
case 6:
|
||||
return dir.lastFileName.isEmpty() ? tr("unknown") : dir.lastFileName;
|
||||
case 7:
|
||||
return dir.errors.empty()
|
||||
? tr("none")
|
||||
: tr("%1 item(s) out of sync", nullptr, static_cast<int>(dir.errors.size())).arg(dir.errors.size());
|
||||
if (!dir.globalError.isEmpty() || !dir.itemErrors.empty()) {
|
||||
if (dir.itemErrors.empty()) {
|
||||
return dir.globalError;
|
||||
}
|
||||
if (dir.globalError.isEmpty()) {
|
||||
return tr("%1 item(s) out of sync", nullptr, static_cast<int>(dir.itemErrors.size())).arg(dir.itemErrors.size());
|
||||
}
|
||||
return tr("%1 and %2 item(s) out of sync", nullptr, static_cast<int>(dir.itemErrors.size()))
|
||||
.arg(dir.globalError)
|
||||
.arg(dir.itemErrors.size());
|
||||
} else {
|
||||
return tr("none");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -143,7 +153,7 @@ QVariant SyncthingDirectoryModel::data(const QModelIndex &index, int role) const
|
|||
return dir.lastFileName.isEmpty() ? Colors::gray(m_brightColors)
|
||||
: (dir.lastFileDeleted ? Colors::red(m_brightColors) : QVariant());
|
||||
case 7:
|
||||
return dir.errors.empty() ? Colors::gray(m_brightColors) : Colors::red(m_brightColors);
|
||||
return dir.globalError.isEmpty() && dir.itemErrors.empty() ? Colors::gray(m_brightColors) : Colors::red(m_brightColors);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -169,10 +179,10 @@ QVariant SyncthingDirectoryModel::data(const QModelIndex &index, int role) const
|
|||
}
|
||||
break;
|
||||
case 7:
|
||||
if (!dir.errors.empty()) {
|
||||
if (!dir.itemErrors.empty()) {
|
||||
QStringList errors;
|
||||
errors.reserve(static_cast<int>(dir.errors.size()));
|
||||
for (const auto &error : dir.errors) {
|
||||
errors.reserve(static_cast<int>(dir.itemErrors.size()));
|
||||
for (const auto &error : dir.itemErrors) {
|
||||
errors << error.path;
|
||||
}
|
||||
return QVariant(QStringLiteral("<b>") % tr("Failed items") % QStringLiteral("</b><ul><li>")
|
||||
|
|
|
@ -48,11 +48,11 @@ void DirView::mouseReleaseEvent(QMouseEvent *event)
|
|||
emit openDir(*dir);
|
||||
}
|
||||
}
|
||||
} else if (clickedIndex.row() == 7 && !dir->errors.empty()) {
|
||||
} else if (clickedIndex.row() == 7 && !dir->itemErrors.empty()) {
|
||||
// show errors
|
||||
auto *textViewDlg = new TextViewDialog(tr("Errors of %1").arg(dir->label.isEmpty() ? dir->id : dir->label));
|
||||
auto *browser = textViewDlg->browser();
|
||||
for (const SyncthingDirError &error : dir->errors) {
|
||||
for (const SyncthingItemError &error : dir->itemErrors) {
|
||||
browser->append(error.path % QChar(':') % QChar(' ') % QChar('\n') % error.message % QChar('\n'));
|
||||
}
|
||||
textViewDlg->show();
|
||||
|
|
Loading…
Reference in New Issue