feat: multi-pod/container log monitoring with word wrap - #21
Conversation
Allow selecting multiple containers (across same or different pods) in the Pod/Container picker without disconnecting and reconnecting. - PodContainerSelect: multi-select checkboxes replacing single-select dropdown - StreamConfig: stores multiple selections as comma-separated 'pod/container' tokens - StreamPanel: auto-reconnects on container change (was missing), per-token removable chips - logUtils: compileLogFilters handles comma-separated container tokens for client-side filtering - main.go: parseRegexFilters builds alternation regex from comma-separated container tokens
Add a checkbox on each pod row that selects/deselects all of that pod's containers at once, complementing the per-container checkboxes. Shows an 'indeterminate'/partial-count indicator when only some containers are picked.
- Switch log rows from whitespace-nowrap to whitespace-pre-wrap break-words so long lines wrap vertically instead of overflowing horizontally - Hide horizontal overflow on the scroll container - Let rows size naturally (min-height instead of fixed height) so wrapped lines are fully visible - Replace absolute-position virtualization with inline spacers so variable height rows don't overlap - Add LogViewer component tests
There was a problem hiding this comment.
🟡 Changes recommended
StreamConfig clears state with two sequential updateConfig calls that both spread stale config, so the container filter is not actually reset when clearing or picking a single whole-pod selection.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR extends the log-streaming UI so a user can monitor multiple containers/pods at once and enables word wrapping for long log lines. It reworks the pod/container picker from single- to multi-select, threads a comma-separated pod/container token list through the frontend config and the Go backend's regex filtering, and switches the log viewer to naturally-sized wrapped rows with spacer-based virtualization. It fits into the existing StreamPanel → StreamConfig → PodContainerSelect config flow and the parseRegexFilters backend pipeline.
Changes:
- Multi-select pod/container picker with per-pod select-all (indeterminate) checkboxes, chips, and comma-separated token config wiring across
PodContainerSelect,StreamConfig, andStreamPanel. - Backend (
main.go) and client (logUtils.js) now parse multiple tokens into anchored alternation regexes for pods and containers. LogViewerwraps long lines (whitespace-pre-wrap break-words) and uses inline spacers for virtualization; new/expanded tests and docs.
File summaries
| File | Description |
|---|---|
main.go |
Parses comma-separated container tokens, derives unique pod names, builds combined pod/container regex filters. |
frontend/src/utils/logUtils.js |
compileLogFilters builds an anchored alternation regex from multiple container tokens. |
frontend/src/components/stream/StreamPanel.jsx |
Reconnects on container change; builds per-token filter chips. |
frontend/src/components/stream/StreamConfig.jsx |
Maps multi-select selection to container/query; has a stale multi-field update bug. |
frontend/src/components/logs/LogViewer.jsx |
Word-wrapped, naturally-sized rows with spacer-based virtualization (fixed ROW_HEIGHT assumption). |
frontend/src/components/common/PodContainerSelect.jsx |
Converted single-select picker to multi-select with per-pod checkboxes/chips. |
frontend/src/components/logs/__tests__/LogViewer.test.jsx |
New tests for rendering, wrapping classes, and scroll buttons. |
frontend/src/components/common/__tests__/PodContainerSelect.test.jsx |
Added multi-select and pod select-all/deselect tests. |
.github/instructions/unittestMcp.instructions.md |
Documents the review_test protective gate. |
Review details
- Files reviewed: 9/9 changed files
- Comments generated: 3
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Addresses review feedback: the fixed ROW_HEIGHT virtualization drifted when lines wrapped. Now each rendered row is measured via a callback ref and its real height feeds prefix sums that drive the visible slice and spacers, so wrapped rows contribute their actual size to the scroll geometry. - Key measurements by log id (stable across filter changes) - Binary-search the visible slice over measured prefix sums - Reset measurements when the underlying log set changes - Re-pin to the tail after measurements change total height while following - Add test verifying measured heights are reflected in scroll geometry
Addresses review feedback: the empty-selection and single whole-pod branches called updateConfig twice in a row. Since each call derives from the same render-time config and forwards to setConfig, React applied only the last call, so container was never actually cleared. Merge each pair into one onChange call, matching the multi-select branch. - Add StreamConfig tests covering clear, multi-select, and single-select
Addresses review feedback: the new comma-separated multi-token behavior in compileLogFilters was untested. Add cases asserting that multiple pod/container tokens (and mixed plain tokens) build an alternation that matches any of the containers.
Summary
Enhances the log stream to support monitoring multiple containers/pods at once and improves the log display with word wrapping.
Changes
Multi-container selection
PodContainerSelect.jsx: Converted the pod/container picker from single-select to multi-select. Users can pick multiple containers across different pods; chosen values render as removable chips.StreamConfig.jsx: Wires the picker to the config using comma-separatedpod/containertokens.StreamPanel.jsx: Container changes now trigger a debounced reconnect (previously the stream silently stayed on the old container). Filter chips are built per selected token.logUtils.js:compileLogFiltersnow builds an anchored alternation regex from the selected container tokens.main.go: Backend parses comma-separated container tokens, derives unique pod names, and builds the container/pod regex filters for the stern stream.Word wrap
LogViewer.jsx: Log rows now usewhitespace-pre-wrap break-wordsso long lines wrap vertically instead of overflowing horizontally. Horizontal overflow is hidden, rows size naturally, and virtualization uses inline spacers so variable-height rows don't overlap.Tests
LogViewer.test.jsx(9 tests) and expandedPodContainerSelect.test.jsx(pod select-all / deselect).Docs
.github/instructions/unittestMcp.instructions.mdto document thereview_testprotective gate.Commits
091c9c0feat: support multiple container selection without reconnectb9d425cfeat: allow selecting an entire pod (all containers) in the picker8b722fffeat: wrap long log lines in LogViewer7ea3154docs: add review_test protective gate to unit test instructions