Commit 6485e2d
kanban: render the remaining forms, and file the gap that stops the last two
#357 converted the login form and left the rest of the showcase hand-built.
This finishes it: `CreateProject`, `CreateColumn`, `CreateSwimlane`,
`CreateTask` and `AddComment` now render from
`morph::forms::schemaJson<A>()` through the shipped `DynamicForm`, each with
the renderer's own explicit Submit button. Six forms on five screens, none
with a hand-written field or submit button.
`BoardBridge` grows the controller contract the renderer calls --
`schemasJson`, `submitIfValid`, `replyReceived` -- forwarding to a
`BoardPresenter::submitForm` that dispatches through `executeJson` and then
decodes the reply. Decoding is the load-bearing part: every board action
returns the full rebuilt state, so `submitForm` re-emits `boardOpened` (and
`commentAdded` for `AddComment`), which is what keeps `BoardBridge::board`
and every binding over it live in the same turn as the submit rather than at
the next poll tick. `ProjectAdminPresenter::submitForm` becomes the
two-model routing table its own comment predicted, and re-emits
`projectCreated` with the name recovered from the submitted body so the
project pane keeps re-listing itself. Both bridges serve one schema document
and route only their own actions; an action a controller does not serve is
reported on `replyReceived`, never dropped -- checked on `MoveTaskPosition`,
a registered action deliberately outside the form set, so the gate is proven
rather than the JSON decoder.
`createProject`, `createColumn`, `createSwimlane`, `createTask` and
`addComment` are demoted from `Q_INVOKABLE` to plain methods: nothing in
`gui/qml/` calls them any more, and dead QML surface is what
`test_kanban_qml_surface.cpp` exists to catch. `submitIfValid` needs the
opposite exemption on both bridges, its caller being the shipped
`DynamicForm.qml`.
Two DTO declarations carry the interaction the hand-built controls had.
`CreateTask`'s column/swimlane ids and `AddComment`'s task id are context,
not input -- the task goes in the column you are typing in, the comment on
the task whose popup is open -- so they are `hidden` in `fieldMetadata` and
seeded by the view that owns the form; no row id reaches the screen.
`CreateColumn::wipLimit` joins `optionalFields`, because 0 already means
unlimited and the `SpinBox` it replaced defaulted to it rather than
demanding a number.
Rendering these for real found what generating them could not, which is the
point triage made when it said schema generation is necessary and not
sufficient. `MembersView`'s role pickers and `RulesView`'s mutation-type
picker are *not* converted, and now carry rule 2(a)'s written justification
plus the finding rule 2 demands: `schemaJson` describes a `enum class`
completely, and `DynamicForm` draws it as a free-text field that reports
`ready` for `role = "Emperor"` (morph#386). Converting them would have
replaced two working combo boxes with two typo-accepting text boxes. Two
smaller renderer findings are filed rather than folded in: morph#387 (every
form warns about `onOptionsReceived` on a controller with no `Choice` field
-- invisible until a real controller is attached) and morph#388 (array-valued
schema keys mistyped when `schema` is assigned rather than bound). The
drag-and-drop board keeps its own rule 2(a) justification and files nothing:
its schema renders fine, and a form is simply the wrong shape for a gesture
whose inputs the gesture itself produces.
`tests/test_gui_forms_render.cpp` is what makes "rendered" more than a claim:
it loads the shipped `.qml` into a real engine with real bridges over a real
backend and, per form, asserts the controls drawn, the body assembled and the
row written. Mutation-checked twice -- dropping the hidden-field seeding
leaves `CreateTask` permanently `!ready`, and dropping `hidden` from
`CreateTask::columnId` makes the raw id column visible on screen.
151 kanban cases pass (was 140), 1672 in the whole configure; both scenario
scripts still exit 0. Built with `MORPH_ENABLE_STRICT_COMPILATION=OFF`
because morph#372 makes any AUTOMOC target unbuildable from a nested
worktree, so the test binary was not compiled under the strict warning set;
the two changed DTO headers were compiled separately under it and are clean.
Closes #344.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GnSnsebJ92Kti1D7m3RwYJ1 parent 2a035fe commit 6485e2d
22 files changed
Lines changed: 1466 additions & 157 deletions
File tree
- examples/kanban
- gui_lib
- gui/qml
- include/kanban/dto
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
14 | 31 | | |
15 | 32 | | |
16 | 33 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
124 | 124 | | |
125 | 125 | | |
126 | 126 | | |
127 | | - | |
128 | | - | |
129 | | - | |
130 | | - | |
131 | | - | |
132 | | - | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
133 | 131 | | |
134 | | - | |
135 | | - | |
136 | | - | |
137 | | - | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
138 | 162 | | |
139 | | - | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
140 | 172 | | |
141 | | - | |
142 | | - | |
143 | | - | |
144 | | - | |
145 | | - | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
146 | 191 | | |
147 | | - | |
148 | | - | |
149 | | - | |
150 | | - | |
151 | | - | |
152 | | - | |
153 | | - | |
154 | | - | |
155 | | - | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
156 | 204 | | |
157 | | - | |
158 | | - | |
159 | | - | |
160 | | - | |
161 | | - | |
162 | | - | |
163 | | - | |
164 | | - | |
165 | | - | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
166 | 212 | | |
167 | 213 | | |
168 | 214 | | |
| |||
266 | 312 | | |
267 | 313 | | |
268 | 314 | | |
269 | | - | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
270 | 318 | | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
271 | 328 | | |
272 | 329 | | |
273 | 330 | | |
| |||
0 commit comments