gui: Options — Capture tab, saveTo.allowedRoots, lock coverage to the schema

Options was missing 8 of the 43 real settings.* keys: capture.enabled,
monitoredExtensions, monitoredMimeTypes, minSizeBytes, excludedHosts,
bypassModifier, autoStartTypes, and saveTo.allowedRoots. The capture.* keys
were dropped in an earlier pass on the mistaken read that the spec's "File
Types" tab meant per-category extension lists (which do live on Category,
not settings.*) — they're real settings.* keys for a real daemon feature
(the extension's auto-capture policy), so the tab exists now, named
"Capture" to match what it actually configures rather than the spec's
label.

New tst_optionsdialog case (allKeysMatchesTheSchemaExactly) loads
Settings.schema.json itself at test time and diffs its property set against
OptionsDialog::allKeys() — this drifted silently once already, so the
regression is now a build-time gate an unused import or a future key
addition would trip, not something that needs re-discovering by hand again.

Verified against a real veloxd (not just mockd): settings.get across all
43 keys, a settings.set/get round trip on a scalar (connection.timeoutSec)
and on array-valued keys in the shapes OptionsDialog::currentValues()
actually produces (capture.monitoredExtensions, proxy.bypassHosts,
saveTo.allowedRoots), and event.settings.changed fanning out to a second
subscribed client — all round-tripped and restored to their original
values afterward. The real OptionsDialog widget also loads and renders
correctly against that same daemon's live defaults with no crash under
ASan+UBSan.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NSCdCWFXBTSBBK3MzWtJiC
This commit is contained in:
2026-09-12 21:29:19 +04:00
co-authored by Claude Sonnet 5
parent 755d85964e
commit 1fd2e0a0db
4 changed files with 137 additions and 11 deletions
+18 -5
View File
@@ -1,11 +1,12 @@
// The Options dialog. Lane GUI.
//
// docs/03-gui-spec.md §4: every control here maps 1:1 onto a settings.* key from
// contracts/schema/types/Settings.schema.json. The spec's "File Types" and "Site Logins"
// tabs have no backing key (per-category extension lists live on Category via
// category.upsert, not settings.*; login credentials go to the Secret Service) — a real
// tab either binds to a real key or does not exist here, so those two are left out rather
// than shipped as fake affordances.
// contracts/schema/types/Settings.schema.json. The spec's "File Types" tab turned out to
// have real backing after all (capture.monitoredExtensions/monitoredMimeTypes/
// autoStartTypes are settings.* keys, not Category — a mistake in an earlier pass here,
// caught while checking this dialog covers all 43 keys against the now-live real veloxd);
// it is named "Capture" below to match what it actually configures. "Site Logins" still
// has no settings.* key (credentials go to the Secret Service) and stays out.
#pragma once
@@ -16,6 +17,7 @@ class QCheckBox;
class QComboBox;
class QLabel;
class QLineEdit;
class QPlainTextEdit;
class QSpinBox;
class QTabWidget;
@@ -45,6 +47,7 @@ class OptionsDialog : public QDialog {
private:
void buildGeneralTab();
void buildCaptureTab();
void buildSaveToTab();
void buildConnectionTab();
void buildDownloadsTab();
@@ -67,11 +70,21 @@ class OptionsDialog : public QDialog {
QComboBox *language_;
QCheckBox *checkForUpdates_;
// Capture
QCheckBox *captureEnabled_;
QLineEdit *monitoredExtensions_;
QLineEdit *monitoredMimeTypes_;
QSpinBox *minSizeKiB_;
QLineEdit *excludedHosts_;
QComboBox *bypassModifier_;
QLineEdit *autoStartTypes_;
// Save To
QLineEdit *defaultDir_;
QLineEdit *tempDir_;
QComboBox *fileExistsPolicy_;
QCheckBox *createSubfolderPerSite_;
QPlainTextEdit *allowedRoots_;
// Connection
QComboBox *connectionPreset_;