Repository navigation
CAMEL-25897: camel-jbang - the source view shows the body types each step has been reached with at the end of its line - #28234
Conversation
|
🌟 Thank you for your contribution to the Apache Camel project! 🌟 🐫 Apache Camel Committers, please review the following items:
|
gnodet-bot
left a comment
There was a problem hiding this comment.
This is a clean, well-tested feature. The 7 test cases cover the full feature lifecycle: alignment and gutter marks, narrow-viewport truncation, plain mode, stale/dirty state dimming, quick-doc content, multi-processor-per-line aggregation with correct mixed semantics, and the save-stale-refresh state machine.
A few design notes worth having on record:
BodyTypes.mixed(null) is null-safe. The call in LiveRunLines.addBodyTypes() passes p.bodyKinds which can be null, but BodyTypes.mixed() has an explicit null guard (return kinds != null && kinds.size() > 1) — null input returns false, which is correct (no kinds = not mixed).
Threading is correct. bodyTypesAlign is written in refreshLiveLines() and read in addBodyTypes() — both on the render thread, following the same single-render-thread pattern as the existing liveTotalWidth/liveFailedWidth/liveMeanWidth fields. No volatile needed. Similarly, wasDirty in SourceRunState.Tracker is read and written exclusively from the UI thread in shown() — refresh() on the background thread never touches it.
gutter() / addBodyTypes() consistency. Both call current() which reads volatile saves/computedSaves. A background refresh could flip current() between the two calls, but this produces at most a one-frame visual glitch (gutter mark with no type list, or vice versa) — harmless in a TUI, not a correctness issue.
Progressive degradation in BodyTypes.fit(). The fallback chain (full label → short label → first N types + count → truncated first type + count → just the mark → empty) handles all viewport widths gracefully, which is validated by the narrow-view test (theTypesAreCutToTheRoomThereIs at 56 cols).
Save-stale semantics. The aSaveInTheEditorLeavesThemOutUntilTheIntegrationIsSeenToLoadIt test correctly verifies that after refresh(), stale() still returns true because state.kind() != Kind.RUNNING — body types remain hidden until the integration actually loads the new file version, not just until the next refresh cycle.
This review was generated by an AI agent, Hermès on behalf of @gnodet.
oscerd
left a comment
There was a problem hiding this comment.
TL;DR
A careful third view of the body types: they come only from the integration's status, nothing loads the route file, and the run state from #28220 hides them while another version runs. No code blocker. Two display gaps and the CI gap are worth closing first.
Blockers
- None in the code. Merge precondition: this PR is stacked (base
feature/CAMEL-25771-route-checksum-views, on #28220 → #28213), so Build and test, doc validation and the license check never ran on8a4c917d6339. Only Dependency Review and PR id uploader did. Let's get a completed build once it targetsmain.
Other findings: 4 (2 non-blocking, 1 suggestion, 1 question)
- Cut types lose their last column (
SourceViewer.java:2952). The right edge isviewportWidth + hSkip, andviewportWidthiscontentArea.width()(:1878). But the paragraph is drawn inhChunks.get(0), which is one column narrower because the last column is kept for the scrollbar (:1883-1888). WhenBodyTypes.fitcuts a name,truncateWithEllipsisfills the room exactly (BodyTypes.java:114). The…or the last digit of+Nthen lands in that column and is clipped:ByteArra…shows asByteArra, which reads like a whole name. PassingviewportWidth - 1 + hSkipfixes it and keepswrapRowCountconsistent. The 56-column test stops at⚠ byte[] +1, well before the edge. A narrower render that reaches the cut, asserting the…and the+1, would cover it. - An unknown run state counts as current (
SourceRunState.java:242).stale()is false whenevercurrent()is null for a reason other than a save. One case is a state computed for another file: this lasts until the next refresh after switching files, whileliveLines()can still serve the previous file's map for up to a second (SourceLiveColumn.java:257). The other isof()finding noStartedroute from the file (:95, all stopped or suspended). In that case, with a plaincamel run(its default dev profile turns the message history on, and nothing reloads), a saved edit shows the old types and ⚠ on the new lines again after the next refresh, undimmed. What do you think about these three changes? Treat "not computed for the file shown" as stale (keepComputed(shown, null)so it differs from "no started route"). Re-readliveLines()when the file changes. And decide what a file whose routes are all stopped should show. - [Suggestion] Jira scope. CAMEL-25897 still says the routes an edit did not change keep their hints through the CAMEL-25771 checksum, and the PR explains why it leaves that out. Could we update the issue text, or open a follow-up, before resolving it?
- [Question] Gutter ⚠. The mark for a mixed body kind is the same glyph and style as the deprecated-line mark (
SourceViewer.java:2935," ⚠ "inTheme.warning()), and a deprecated line shows only that one. Is sharing it intended, or would a distinct style help tell them apart?
Reviewed with Claude Code on behalf of oscerd. This review was generated by an AI agent and may contain inaccuracies; please verify all suggestions before applying.
|
Thanks. These are addressed in 3101f32, after merging the updated #28220 branch in. CI: as for #28220,
Claude Code on behalf of davsclaus |
gnodet-bot
left a comment
There was a problem hiding this comment.
Following up on my earlier review — all 4 of oscerd's findings have been addressed in 3101f32.
[1] Right-edge off-by-one — ✅ Addressed. viewportWidth - 1 + hSkip at SourceViewer.java:2952 is correct; the new aCutNameKeepsItsEllipsisAndTheCountItsDigits test validates the fix across 44–72 column widths, asserting the … and the +N digit are preserved at every width.
[2] Unknown run state — ✅ Addressed. Three separate fixes:
Computed(file, null)is now stored for the file shown but with no started route, sostale()correctly returns true until the nextrefresh()computes it — the gap is a single frame.liveLines()re-reads immediately whenliveLinesFilediffers fromloadedFilePath, eliminating the up-to-one-second lag on file switch.Kind.STOPPEDhandles the all-stopped-routes case;state.stale()is 0 when routes were loaded as saved (body types visible), and is incremented for routes stopped after a reload (body types hidden). All three sub-cases have test coverage inSourceBodyTypesTest.
[3] JIRA scope — ✅ Confirmed by author.
[4] Gutter ⚠ glyph — ✅ Confirmed intentional; consistent with Routes and Diagram tabs.
Pre-fix validation (static trace): anotherFileHasItsOwnLiveRunDataAtOnce asserts immediate data switch after viewer.loadFile(other), which exercises the liveLinesFile check added in refreshLiveLines(). aSaveInTheEditorLeavesThemOutUntilTheIntegrationIsSeenToLoadIt verifies the saves/computedSaves tracking. Both tests would pass without the fix only if the data happened to load within the assert's frame — not the case given the synchronous refreshLiveLinesForTesting() helper.
The Tracker concurrency model is sound: shown() and stale() are UI-thread-only; saves is volatile and written only on the UI thread; the synchronized block in refresh() guards computed/written/computedSaves; and the AtomicLong refreshes ordering ensures a later refresh always wins over an earlier one that ends after it.
LGTM.
This review was generated by an AI agent, Hermès on behalf of @gnodet.
…sion and checksum of a route, and the Source view whether the file runs as saved
The route console has the checksum and the revision of each route, so the
views show them:
- Routes: a route added again changed in this run, such as by a reload, has
its revision after its id, muted ("orders rev 3"). tui_get_table has the
checksum and the revision of each route.
- Diagram: the Info panel of a route in the topology has its checksum, and
its revision with the changes in this run ("3 · 2 changes").
- Source: the bottom border says whether the integration runs the file as it
is saved: running as saved, reloading, not running yet (the integration
runs without --dev, or did not reload the file), or the reload failed.
tui_get_table has it as runState, so an agent can tell its edit runs.
The Source view compares when the file was saved with when the integration
loaded the routes it has from the file, not the checksums of the file:
- loading a YAML or XML file with Camel runs parts of it, such as creating
its beans, which a tool that reads route sources must not do;
- an endpoint written with parameters is built by its component, which the
TUI does not have, so the checksum would not be the one the route runs
with.
An integration that has not reloaded loaded its routes when it started; after
a reload, a route that started after the save runs what is saved.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
…e is in parentheses and dimmed The Routes table shows the revision of a changed route as "orders (rev 3)", with the revision dimmed like the time since the last exchange beside the totals. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
… tui_get_table reads it or the tab is selected (address review) - tui_get_table may read the Source tab while another tab is on screen, which the data refresh does not refresh, so its run state is computed when the table is read. - Selecting the tab computes it in the background at once, so the border does not show the state of before for a refresh. - The file shown comes from SourceViewer.getCurrentFilePath(), which already gave it. - The docs say that an integration without camel-xml-io has no checksum and revision either: camel run always has it, a Spring Boot or Quarkus application may not. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
…step has been reached with at the end of its line With the message history on, such as with camel run --dev, the body types each step of a running route has been reached with go at the end of its line in the source view of the Source tab, dimmed, lined up, and cut to the room there is. A step reached with bodies of more than one kind (null, payload, data or collection) has a ⚠ in the gutter, and its types in the warning color. The quick documentation of the line lists all the types, and for a mix of kinds says that the body there depends on the path a message takes. The facts of a line only hold while the view has the version of the file that runs. The live run data is dimmed, and the body types are left out: - while the integration does not run the file as saved (saved after it loaded it, reloading, or the reload failed); - after a save in the editor, until the next refresh knows the state again. Keeping the body types of the routes an edit did not change would need the checksums of the routes of the edited file, which the TUI cannot compute without loading the file with Camel. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
…re the scrollbar, and stay out until the run state of the file shown is known (address review) - The last column of the source view is the scrollbar's, so the body types are cut one column before it: a cut name keeps its ellipsis, and "+1" its digit. - The live run data is read again as soon as another file is shown, not up to a second later with the numbers of the previous file. - Until the run state is known for the file shown, the integration may run another version of it, so the live run data is dimmed and the body types are left out. Showing another file, or saving it, computes the state at once in the background; a refresh that started later wins over one that ends after it. - A file whose routes are all stopped (or suspended) shows "the routes of this file are stopped". Its live run data and body types still show when the integration loaded the file as saved, which is known without a reload, and not for a route stopped after a reload. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
18e2b26 to
484ea29
Compare
0b57a47 to
91c5380
Compare
…ource-body-types Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
|
🧪 CI tested the following changed modules:
🔬 Scalpel shadow comparison — Scalpel: 2 of 707 tested, 1 compile-only — current: 2 all testedMaveniverse Scalpel detected 2 affected modules (current approach: 2). Skip-tests mode would test 2 modules (2 direct + 1 downstream), skip tests for 1 (generated code, meta-modules) Modules Scalpel would test (2)
Modules with tests skipped (1)
All tested modules (4 modules, 40.5s total)Total reactor time: 40.5s
Top 20 slowest modules:
|
Stacked on #28220. CAMEL-25892 brought the body types each step of a route has been reached with to the Routes and Diagram tabs of the Camel TUI. This is its third view, the source view of the Source tab (CAMEL-25897):
ByteArrayInputStreamCache,⚠ LinkedHashMap | InputStreamCache).Only for the version of the file that runs. The facts of a line hold only while the view has the file as the integration runs it. #28220 added the run state of the open file. The live run data is dimmed, and the body types are left out:
A file whose routes are all stopped (or suspended) shows
○ the routes of this file are stopped. Its live run data and body types still show when the integration loaded the file as saved. Without a reload that is known, as the routes were loaded at the start. After a reload, when a stopped route was loaded is not known, so they are left out.The issue asked to keep the body types of the routes an edit did not change, by their checksums. The TUI cannot compute the checksums of an edited YAML or XML file without loading it with Camel, which runs parts of it and needs the components (see #28220). So the view leaves them all out until the integration runs the file. In dev mode that is about a second after a save, and they come back as messages reach the new steps.
How
LiveRunLinescollects the body types of the steps on each line with the live run data. A line is mixed when one of its steps was reached with more than one kind. Two steps on one line that each have a kind of their own do not make it mixed.SourceLiveColumndraws the gutter mark and the types after the code, and gives the quick documentation entry. The types are cut one column before the scrollbar's.SourceVieweronly calls it, and stays within its size limit.Tests
SourceBodyTypesTest:…and a count its digit, from 44 to 72 columns;SourceRunStateTest: a file whose routes are all stopped, before and after a reload.Docs: the Source help page, and the Source Editor and Diagram pages of the manual, with the screenshot.
Claude Code on behalf of davsclaus
🤖 Generated with Claude Code