research: pipeline-running signal + spinners so users aren't guessing
The prior flow was ambiguous: after hitting Start research, status flipped to "processing" and a "Submit for review" button appeared immediately with no indication that anything was actually running. Users had to guess whether the pipeline was working or stalled. Backend surfaces the truth as a signal: - new topology_runs::active_runs_for_research_topic counts queued+running runs whose research_topic_id matches - TopicDetail includes runs_in_flight: i64 alongside the existing status field, so the canvas can distinguish "pipeline still working" from "runner stalled". ResearchCanvas is now honest about state: - while runs_in_flight > 0, the header status pill grows a cyan "N runs in flight" badge with an inline SVG spinner - the stage-explainer card turns cyan-bordered and shows a "pipeline is running" hint, plus copy pointing the user at the Agents tier where each teammate's activity streams live - the "Submit for review (manual)" button is HIDDEN while any run is in flight — it's an escape hatch for stalled runs only, not the happy-path action. It reappears if runs_in_flight drops to zero but the topic is still marked processing, so a stalled runner can still be nudged along. - the canvas polls getTopic every 4s while status is processing/ publishing or runs_in_flight > 0, so the spinner + outcome swap in automatically when the pipeline completes. ResearchList sidebar: - each row's status dot becomes a spinner when the topic's status is processing or publishing, matching the canvas at a glance - the list also polls every 6s while ANY topic is active, so transitions land in the sidebar without waiting on a parent bump. The poll is gated on a derived boolean to avoid effect thrash. Follow-up: same pattern belongs on LoopsList / LoopsCanvas for loop iterations in flight — same signal (queued+running runs per loop) but not wired here.
This commit is contained in:
@@ -245,6 +245,11 @@ pub struct TopicDetail {
|
||||
/// beyond so reviewers see what actually needs approval.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub latest_outcome: Option<cm_db::repo::research_outcomes::Outcome>,
|
||||
/// queued + running topology_runs bound to this topic. > 0 means the
|
||||
/// pipeline is still working — the canvas shows a running badge with a
|
||||
/// spinner and hides the manual "Submit for review" button, which is
|
||||
/// only offered when this is 0 (as an escape hatch for stalled runs).
|
||||
pub runs_in_flight: i64,
|
||||
}
|
||||
|
||||
pub async fn get_topic(
|
||||
@@ -261,11 +266,14 @@ pub async fn get_topic(
|
||||
.await?
|
||||
.is_some();
|
||||
let latest_outcome = cm_db::repo::research_outcomes::latest(&state.pool, id).await?;
|
||||
let runs_in_flight =
|
||||
cm_db::repo::topology_runs::active_runs_for_research_topic(&state.pool, id).await?;
|
||||
Ok(Json(TopicDetail {
|
||||
topic,
|
||||
agents,
|
||||
has_pending_publish_request,
|
||||
latest_outcome,
|
||||
runs_in_flight,
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user