feat: add unknown option toasts

This commit is contained in:
2 * r + 2 * t 2026-04-12 03:12:13 +10:00
parent ee9dce0268
commit 5a13cc22f6
4 changed files with 49 additions and 1 deletions

View file

@ -18,6 +18,10 @@ Scope {
Toaster.toast(qsTr("Failed to save config%1").arg(screen ? " for " + screen : ""), error, "settings_alert", Toast.Error); Toaster.toast(qsTr("Failed to save config%1").arg(screen ? " for " + screen : ""), error, "settings_alert", Toast.Error);
} }
function onUnknownOption(key: string, screen: string): void {
Toaster.toast(qsTr("Unknown option in%1 config").arg(screen ? " " + screen : ""), key, "question_mark", Toast.Warning);
}
target: GlobalConfig target: GlobalConfig
} }
@ -26,6 +30,10 @@ Scope {
Toaster.toast(qsTr("Failed to parse token config%1").arg(screen ? "for " + screen : ""), error, "settings_alert", Toast.Warning); Toaster.toast(qsTr("Failed to parse token config%1").arg(screen ? "for " + screen : ""), error, "settings_alert", Toast.Warning);
} }
function onUnknownOption(key: string, screen: string): void {
Toaster.toast(qsTr("Unknown option in%1 token config").arg(screen ? " " + screen : ""), key, "question_mark", Toast.Warning);
}
target: TokenConfig target: TokenConfig
} }
} }

View file

@ -39,6 +39,7 @@ GlobalConfig* MonitorConfigManager::configForScreen(const QString& screen) {
connect(overlay.config, &GlobalConfig::saved, global, &GlobalConfig::saved); connect(overlay.config, &GlobalConfig::saved, global, &GlobalConfig::saved);
connect(overlay.config, &GlobalConfig::loadFailed, global, &GlobalConfig::loadFailed); connect(overlay.config, &GlobalConfig::loadFailed, global, &GlobalConfig::loadFailed);
connect(overlay.config, &GlobalConfig::saveFailed, global, &GlobalConfig::saveFailed); connect(overlay.config, &GlobalConfig::saveFailed, global, &GlobalConfig::saveFailed);
connect(overlay.config, &GlobalConfig::unknownOption, global, &GlobalConfig::unknownOption);
} }
return overlay.config; return overlay.config;
} }
@ -55,6 +56,7 @@ TokenConfig* MonitorConfigManager::tokensForScreen(const QString& screen) {
connect(overlay.tokens, &TokenConfig::saved, global, &TokenConfig::saved); connect(overlay.tokens, &TokenConfig::saved, global, &TokenConfig::saved);
connect(overlay.tokens, &TokenConfig::loadFailed, global, &TokenConfig::loadFailed); connect(overlay.tokens, &TokenConfig::loadFailed, global, &TokenConfig::loadFailed);
connect(overlay.tokens, &TokenConfig::saveFailed, global, &TokenConfig::saveFailed); connect(overlay.tokens, &TokenConfig::saveFailed, global, &TokenConfig::saveFailed);
connect(overlay.tokens, &TokenConfig::unknownOption, global, &TokenConfig::unknownOption);
} }
return overlay.tokens; return overlay.tokens;
} }

View file

@ -4,6 +4,7 @@
#include <qfile.h> #include <qfile.h>
#include <qfileinfo.h> #include <qfileinfo.h>
#include <qjsondocument.h> #include <qjsondocument.h>
#include <qmetaobject.h>
#include <qstandardpaths.h> #include <qstandardpaths.h>
namespace caelestia::config { namespace caelestia::config {
@ -19,6 +20,35 @@ QString watchRoot() {
RootConfig::RootConfig(QObject* parent) RootConfig::RootConfig(QObject* parent)
: ConfigObject(parent) {} : ConfigObject(parent) {}
QStringList RootConfig::collectUnknownKeys(const ConfigObject* obj, const QJsonObject& json) {
QStringList unknown;
const auto* meta = obj->metaObject();
QSet<QString> known;
for (int i = meta->propertyOffset(); i < meta->propertyCount(); ++i)
known.insert(QString::fromUtf8(meta->property(i).name()));
for (auto it = json.begin(); it != json.end(); ++it) {
if (!known.contains(it.key())) {
unknown.append(it.key());
} else if (it.value().isObject()) {
int idx = meta->indexOfProperty(it.key().toUtf8().constData());
if (idx >= 0) {
auto prop = meta->property(idx);
auto value = prop.read(obj);
auto* subObj = value.value<ConfigObject*>();
if (subObj) {
const auto subUnknown = collectUnknownKeys(subObj, it.value().toObject());
for (const auto& subKey : subUnknown)
unknown.append(it.key() + QStringLiteral(".") + subKey);
}
}
}
}
return unknown;
}
void RootConfig::setupFileBackend(const QString& path, const QString& screen) { void RootConfig::setupFileBackend(const QString& path, const QString& screen) {
m_filePath = path; m_filePath = path;
m_screen = screen; m_screen = screen;
@ -157,7 +187,13 @@ std::optional<QString> RootConfig::reloadFromFile() {
qCDebug(lcConfig) << "Reloading" << metaObject()->className() << "from" << m_filePath; qCDebug(lcConfig) << "Reloading" << metaObject()->className() << "from" << m_filePath;
clearLoadedKeys(); clearLoadedKeys();
loadFromJson(doc.object());
auto jsonObj = doc.object();
const auto unknownKeys = collectUnknownKeys(this, jsonObj);
for (const auto& key : unknownKeys)
emit unknownOption(key, m_screen);
loadFromJson(jsonObj);
return QString(); // success return QString(); // success
} }

View file

@ -31,8 +31,10 @@ signals:
void loadFailed(const QString& error, const QString& screen); void loadFailed(const QString& error, const QString& screen);
void saved(const QString& screen); void saved(const QString& screen);
void saveFailed(const QString& error, const QString& screen); void saveFailed(const QString& error, const QString& screen);
void unknownOption(const QString& key, const QString& screen);
private: private:
static QStringList collectUnknownKeys(const ConfigObject* obj, const QJsonObject& json);
void updateWatch(); void updateWatch();
void onWatcherEvent(); void onWatcherEvent();