Add terminal exec and port forwarding features#2
Merged
Conversation
- Add internal/k8s/update.go with UpdateResource and DeleteResource functions using dynamic K8s client - Add YamlEditor component with Monaco editor, YAML validation, and inline highlighting for Pod editable fields
Adds two major interactive features to Explorer: 1. **Terminal Exec**: Open a shell session into any running container directly from the UI. Uses WebSocket to proxy kubectl exec with full terminal emulation via xterm.js. Supports multiple concurrent sessions with a tabbed dock interface that preserves state when switching tabs. 2. **Port Forwarding**: Forward container ports to localhost with one click. Includes a port forward manager in the UI header showing all active forwards with status indicators and easy cleanup. Backend changes: - exec.go: WebSocket handler for kubectl exec with PTY support - portforward.go: HTTP handlers for starting/stopping/listing port forwards - server.go: Register new routes and CORS for WebSocket Frontend changes: - New dock system (BottomDock, DockContext, TerminalTab, LogsTab) - Port forward components (PortForwardButton, PortForwardManager) - Updated PodRenderer with terminal/logs buttons per container - Updated ServiceRenderer with port forward buttons - xterm.js integration with FitAddon for responsive terminals Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
4 tasks
nadaverell
added a commit
that referenced
this pull request
May 2, 2026
…#570) * fix(ui): keep tooltips anchored to their trigger and dismiss on click Three reported tooltip bugs on app.radarhq.io that share a single root cause in the shared Tooltip primitive (SKY-818): 1. Hovering a nav button (Home, Topology, Resources, Timeline, Helm, Traffic, Audit) flashed the tooltip text at the viewport's top-left (0, 0) before snapping into place, overlapping the "Radar / By Skyhook" logo. On Timeline the logo literally rendered as "adar" because "Timeline" painted over the "R". 2. Clicking a pod row left the row's full-name tooltip pinned above the table header, obscuring the column headers after the cursor moved away. 3. Clicking a tab pill left the tab's tooltip stuck under the active pill instead of dismissing on click. Root causes: - The portal's initial render used `top: 0; left: 0` because position state was seeded with zeros and only updated one rAF later. On slower clients (or whenever the requestAnimationFrame callback was delayed by layout work) that single frame painted at the viewport origin was visible to the user. - Dismissal relied on `mouseleave` and on the trigger unmounting, but for nav buttons / tab pills the click triggers a route change without unmounting the trigger, and the cursor stays over it — so neither path fires and the tooltip lingers. Fix: - Extract the position math into a pure helper `computeTooltipPosition` with full unit coverage (`tooltip-position.ts` + `.test.ts`). It returns `null` when the trigger has no layout, so we never show coords we can't trust. - Track coords as `{ top, left } | null`. While null, render the portal with `visibility: hidden` and `aria-hidden`, so no (0, 0) frame is ever visible. - Two-pass measurement: rAF #1 captures the trigger rect with the unmeasured tooltip (size 0); rAF #2 re-runs with the now-known tooltip size for exact centering. Cleaned up via the existing rafRef so HMR / rapid re-renders can't leak frames. - Add `onPointerDown` on the wrapper that fires before any child onClick, guaranteeing the tooltip is hidden before nav/tab/route-change actions run. Fixes bugs 2 and 3. - Add window-level `popstate` and Escape listeners while a tooltip is visible, as belt-and-braces for in-app navigation that doesn't go through pointerdown on the trigger (e.g. keyboard shortcuts). No behavior change for the singleton coordinator, the disabled flow, or the public `Tooltip` / `WithTooltip` API. Linear: SKY-818 Made-with: Cursor * review: trim bug-narrative comments from tooltip primitive No behavior change — keeps the load-bearing WHYs (popstate dismissal mechanism, second-pass rAF, visibility:hidden guard) but drops the incident-history framing that would rot. --------- Co-authored-by: eliran-mic <eliran.mic@gmail.com> Co-authored-by: Nadav Erell <nadaverell@gmail.com>
nadaverell
added a commit
that referenced
this pull request
May 18, 2026
Pod/Workload drawer was placing the new "Permissions via ServiceAccount" section at position #2 — right under Status, before Containers and Resource Usage. That's incident/audit framing on a daily-browsing surface. Operators opening a Pod want to see what's running and how it's behaving; "what could an attacker do with this SA" comes after. Move it below the diagnostic block (Status → Containers → Resource Usage → Conditions). Combined with the earlier collapse-by-default change (auto-expands only when blast-radius detected), the section now stays out of the way unless it's actually load-bearing for the operator's task. Same move in PodRenderer and WorkloadRenderer.
nadaverell
added a commit
that referenced
this pull request
May 19, 2026
Two follow-ups from #655 on per-user RBAC visual test: 1. Topology preview card on Home: the SSE topology stream is cluster- wide for small/medium clusters; only the dashboard summary is namespace-filtered server-side. That left the kind legend showing cluster-wide totals while the "<X> resources · <Y> conn" header had already narrowed to the active namespace. Filter the topology client-side in HomeView before passing it to TopologyPreview (and ActivitySummary) so the legend matches the title. No-op on large clusters where forceNamespaceFilter already filters SSE server-side. 2. Cluster info card "0 namespaces" for restricted users: dashboard.go only populated resourceCounts.Namespaces when the user could list namespaces cluster-wide, leaving a misleading "0" for users with a restricted namespace view. Fall back to len(allowedNamespaces), mirroring the same pattern in resource_counts.go. Item #2 from the issue (sidebar count "1" vs page "No Namespace found" asymmetry) is left as-is — genuine product call, neither option is obviously better than the other.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds two major interactive features to Explorer:
Terminal Exec: Open a shell session into any running container directly from the UI. Click the terminal icon next to any running container in the pod details drawer to open a fully interactive shell with xterm.js terminal emulation.
Port Forwarding: Forward container ports to localhost with one click. Click port numbers in pod/service views to start forwarding. Active forwards are shown in a manager dropdown in the header with status and easy cleanup.
Key Changes
Backend (Go)
exec.go- WebSocket handler proxying kubectl exec with PTY supportportforward.go- HTTP handlers for managing port forwards (start/stop/list)server.go- Route registration and WebSocket upgrade handlingFrontend (React)