Repository navigation
Provide remote command stream output - #253
Conversation
Signed-off-by: Seokho Son <shsongist@gmail.com>
There was a problem hiding this comment.
Pull request overview
Adds a real-time (SSE-based) streaming UI for Remote Command execution so users can watch stdout/stderr as it arrives and re-open ongoing/recent sessions via a floating badge, aligning MapUI behavior with the referenced cb-tumblebug enhancement.
Changes:
- Introduces an SSE streaming session manager (global registry, streaming modal, session list modal, floating “sessions” badge).
- Updates Remote Command execution to request async mode (
async=true) and, on 202 responses, connect to the streaming endpoint using the returnedxRequestId. - Adjusts ScaleOut request payload to send
numVMsToAddas a number (not a string).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| } | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
When the SSE connection ends normally (reader.read() returns done=true), consumeSSEStream just returns without emitting a terminal event or throwing. In that case the session can remain in a perpetual "Streaming..." state (spinner not removed, waiting timer continues) unless the server always sends a CommandDone event. Consider explicitly treating EOF as completion/error: after the read loop, if abortController.signal.aborted is false and no CommandDone was received, set session.error (or a specific status) and stop/clear related timers/spinner.
| } | |
| } | |
| // If the stream ended naturally without being aborted, surface this as an error | |
| // so callers can handle cleanup (e.g., stopping spinners/timers). | |
| if (!abortController.signal.aborted) { | |
| throw new Error('SSE stream ended unexpectedly without a terminal event.'); | |
| } |
| return `<tr style="cursor:pointer;" onclick="openStreamingSessionModal('${window.escapeHtml(reqId)}')"> | ||
| <td style="padding:6px 8px;font-size:11px;">${statusIcon} ${statusText}</td> | ||
| <td style="padding:6px 8px;font-size:11px;font-weight:600;">${window.escapeHtml(s.mciId)}</td> | ||
| <td style="padding:6px 8px;font-size:11px;">${completedVms}/${totalVms} VMs</td> | ||
| <td style="padding:6px 8px;font-size:11px;color:#888;">${elapsed}s ago</td> | ||
| <td style="padding:6px 8px;font-size:10px;color:#aaa;max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">${window.escapeHtml(reqId)}</td> | ||
| <td style="padding:6px 8px;"> | ||
| ${!isFinished && !s.error ? `<button onclick="event.stopPropagation(); abortStreamingSession('${window.escapeHtml(reqId)}');" | ||
| style="font-size:10px;padding:2px 6px;border:1px solid #dc3545;border-radius:3px;background:#fff;color:#dc3545;cursor:pointer;">Stop</button>` : | ||
| `<button onclick="event.stopPropagation(); dismissStreamingSession('${window.escapeHtml(reqId)}');" | ||
| style="font-size:10px;padding:2px 6px;border:1px solid #6c757d;border-radius:3px;background:#fff;color:#6c757d;cursor:pointer;">Dismiss</button>`} |
There was a problem hiding this comment.
The session list/table uses inline onclick="...('${window.escapeHtml(reqId)}')" handlers. escapeHtml is not safe for JavaScript string contexts because HTML entities are decoded before the handler executes, so a requestId containing ' (or similar) can break out of the string and enable XSS. Avoid inline JS handlers here: render rows/buttons with data-x-request-id attributes and attach click listeners via addEventListener (or event delegation) using the raw value, or serialize safely (e.g., JSON.stringify) and still avoid inline code where possible.
Signed-off-by: Seokho Son <shsongist@gmail.com>
|
/approve |
Apply cloud-barista/cb-tumblebug#2319 enhancement.