Stream update progress into a bar on the stack's row (0.42.0)
CI / build-and-push (push) Successful in 1m55s

Update ran as a blocking POST with nothing to show but a spinner, so the
status added in 86c67df could only sit above the table as a banner.

Adds /ws/update/{stack_id}, streaming `compose pull` then `up -d` with
--progress json, and feeds it through the existing DeployTracker — the
same weighting the deploy console uses. The result renders as a progress
bar inside the stack's own row: percentage, phase label, and layer/byte
detail. Non-streaming actions (start/stop/restart/pull/down) reuse the
bar in its indeterminate form, so every row action looks consistent.

compose_service gains _stream_phase, shared by stream_up and the new
stream_update; a failed pull short-circuits before `up`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016pMmFFkdfxkoYjcEcpZTa5
This commit is contained in:
menzelj
2026-08-31 00:33:34 +02:00
co-authored by Claude Opus 5
parent 86c67dfcea
commit 1e8d4248fd
11 changed files with 392 additions and 56 deletions
+3 -4
View File
@@ -5,7 +5,6 @@ import { toast } from "sonner";
import { Card } from "@/components/ui";
import { HostHeader } from "@/components/hosts/HostHeader";
import { StacksTable } from "@/components/stacks/StacksTable";
import { ActionStatusList } from "@/components/stacks/ActionStatusBanner";
import { AttentionStrip } from "@/components/dashboard/AttentionStrip";
import { FleetKpiRow } from "@/components/dashboard/FleetKpiRow";
import { StackStatusBar } from "@/components/dashboard/StackStatusBar";
@@ -22,7 +21,7 @@ import type { Agent } from "@/types";
export function Dashboard() {
const isAdmin = useAuthStore((s) => s.user?.role === "admin");
const { isBusy, statuses, dismissStatus, start, stop, restart } = useStackActions();
const { isBusy, statusFor, dismissStatus, start, stop, restart } = useStackActions();
const qc = useQueryClient();
const [refreshing, setRefreshing] = useState(false);
@@ -113,8 +112,6 @@ export function Dashboard() {
</>
)}
<ActionStatusList statuses={statuses} onDismiss={dismissStatus} />
{/* ---- Local host stacks ---- */}
<section>
{hasAgents ? <HostHeader /> : <h2 className="sp-label mb-3">This host</h2>}
@@ -125,6 +122,8 @@ export function Dashboard() {
hostMem={info.data?.ram.total ?? 0}
isAdmin={isAdmin}
isBusy={isBusy}
statusFor={statusFor}
onDismissStatus={dismissStatus}
loading={stacks.isLoading}
onStart={start}
onStop={stop}