Skip to content

Feature/reactive forms bridge#7

Merged
Yaraslaut merged 13 commits into
masterfrom
feature/reactive-forms-bridge
Jul 7, 2026
Merged

Feature/reactive forms bridge#7
Yaraslaut merged 13 commits into
masterfrom
feature/reactive-forms-bridge

Conversation

@Yaraslaut

Copy link
Copy Markdown
Member

No description provided.

Yaraslau Tamashevich and others added 11 commits July 6, 2026 13:17
Plans replacing the forms demo's direct RemoteServer/wire::Envelope usage
with Bridge/BridgeHandler, and making forms fire live via set<>/subscribe<>
instead of an explicit submit button, without new per-action boilerplate.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…mits

set<&Action::field> needs a compile-time member pointer per field, and
glaze's plain-aggregate reflection (reflectable<T>, no glz::meta) exposes
only field names, not member pointers -- confirmed directly against
glaze/core/reflect.hpp. Replaced the set<>/subscribe<>-based design with a
generic executeJson(actionType, bodyJson) path backed by a registry
populated automatically inside BRIDGE_REGISTER_ACTION, preserving the
zero-new-boilerplate-per-action goal.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Six tasks: ActionExecuteRegistry + BridgeHandler::executeJson (with unit
tests), FormsController rewrite onto Bridge/BridgeHandler, reactive
DynamicForm.qml (auto-fire, no submit button), Qt Quick Test coverage,
README update, and a full regression pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…DLLs

FindQt.cmake was only included under MORPH_BUILD_QT, so enabling
MORPH_BUILD_FORMS_QML alone failed to find Qt6 on Windows. Also adds a
windeployqt post-build step so morph_forms_qml.exe can run standalone
without Qt's bin directory on PATH.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
BridgeHandler::executeJson(actionType, bodyJson) resolves a runtime
action-type string to the real compile-time execute<Action>() call,
registered automatically inside BRIDGE_REGISTER_ACTION. Lets a
schema-driven UI dispatch through Bridge/BridgeHandler without knowing
concrete C++ action types at compile time, with zero new declarations
per action.

Changes:
- Add ActionExecuteRegistry singleton to bridge.hpp with string->executor mapping
- Add BridgeHandler::executeJson() and ::guiExecutor() methods
- Hook registerActionExecutorOnce into BRIDGE_REGISTER_ACTION_4 macro
- Add 3 test cases for successful dispatch, parse error handling, and unknown action
- Update test files to include bridge.hpp (now required by macro change)

All 352 tests pass (3 new, 349 existing regressions = 0).
registerActionExecutorOnce<Model, Action> is declared in registry.hpp
but only defined in bridge.hpp (to avoid a registry.hpp -> bridge.hpp
include cycle). BRIDGE_REGISTER_ACTION_4 calls it unconditionally at
static-init time, so any translation unit that invokes
BRIDGE_REGISTER_ACTION without also including <morph/bridge.hpp> in
that same TU fails to link with an unresolved external symbol.

A prior commit patched 3 files that broke the default ctest build
(examples/forms/main.cpp, tests/test_quantity_forms.cpp,
tests/test_server_limits.cpp) but left every other call site
unaudited. A repo-wide grep for BRIDGE_REGISTER_ACTION turned up 19
more call sites needing the include: the 10 bank model headers under
examples/bank/include/bank/models/ (only built with
-DMORPH_BUILD_BANK_EXAMPLE=ON, off by default, which is why the
default build never caught this), the 7 WASM-shadow bank model
headers under examples/bank/gui_wasm/include/bank/models/,
tests/qt/qt_test_models.hpp, and examples/forms/lab_model.hpp.

Fix: add #include <morph/bridge.hpp> to every header that calls
BRIDGE_REGISTER_ACTION, and document the requirement as a hard rule
on registerActionExecutorOnce's declaration, on BRIDGE_REGISTER_ACTION's
own doc comment, and symmetrically on ActionExecuteRegistry's doc
comment in bridge.hpp.

Verified: default ctest suite still passes 352/352 with no
regressions. The bank example itself could not be built end-to-end in
this environment (Lightweight's yaml-cpp dependency isn't provisioned,
and even once it is, Lightweight fails to *compile* against this
MSVC toolset independent of this fix) -- instead verified the exact
link mechanism in isolation with a throwaway two-TU repro, confirming
the predicted LNK2019 on registerActionExecutorOnce without the fix
and a clean link with it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replaces hand-built wire::Envelope + RemoteServer plumbing with the
framework's real client API, matching how examples/bank's GUI talks to
its models. submit() is renamed submitIfValid() and now goes through
BridgeHandler::executeJson (added in the previous commit) instead of a
manually assembled envelope.
DynamicForm.qml now calls controller.submitIfValid() directly from
revalidate() whenever the assembled body passes client-side checks,
instead of waiting for a button click. Matches the live-recompute UX
the framework's fielded-action API models, without requiring a
compile-time set<&Action::field> hook per field.
Adds a Qt Quick Test driving DynamicForm through simulated field edits
against a mock controller, asserting submitIfValid fires exactly once
the form becomes valid and not before — without any button click.
The existing windeployqt POST_BUILD step only covered morph_forms_qml
(the GUI app), not morph_forms_qml_tests. Running ctest -R
forms_qml_logic outside a shell with Qt's bin/plugins already on PATH
hung ~200s then crashed with STATUS_DLL_NOT_FOUND (missing
Qt6QuickTestd.dll and, even with a full PATH, the offscreen QPA plugin
the test forces via QT_QPA_PLATFORM=offscreen -- windeployqt's static
analysis doesn't see that env-var-only platform selection, so it
skipped deploying qoffscreend.dll by default).

Fix: run windeployqt for morph_forms_qml_tests too, with
--include-plugins qoffscreen forcing the plugin deployment windeployqt
would otherwise omit. Verified ctest -R forms_qml_logic now passes in
under a second with no Qt-related PATH/QT_PLUGIN_PATH setup at all.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Updates the forms demo README to match FormsController's new transport
(Bridge/BridgeHandler via executeJson) and UX (auto-fire on valid edit,
no submit button), replacing the outdated RemoteServer/wire::Envelope
description.
@codecov

codecov Bot commented Jul 6, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Yaraslaut and others added 2 commits July 7, 2026 18:15
The Docs CI job failed because ActionExecuteRegistry's registerAction,
execute, and instance were missing @param/@return documentation, which
FAIL_ON_WARNINGS turns into a build failure. Also merge the reactive
forms design spec and implementation plan into a single
docs/superpowers/2026-07-06-reactive-forms-bridge.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rewrite the superpowers feature doc to describe only the existing
behavior in present tense (no previous-state narration or task
checklists), keeping it well under 500 lines. Record the documentation
convention and the Doxygen FAIL_ON_WARNINGS local-repro steps in a new
repo CLAUDE.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Yaraslaut Yaraslaut marked this pull request as ready for review July 7, 2026 17:04
@Yaraslaut Yaraslaut merged commit ad471f4 into master Jul 7, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant