web: extract shared status/verdict chip and sidebar tree-head components
commit
2e90008web: extract shared status/verdict chip and sidebar tree-head components
Pull the pass/fail/error status chip (commits' checks card, agents' derived session state, effects' trigger-parse check), the review verdict chip (commits' per-commit reviews, the reviews aggregate list, its sidebar, and its own detail page), and a sidebar’s "+ New" tree-head (agents, issues) into shared pages::mod helpers, replacing four independently-hand-rolled copies of the same markup each.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reviews
No reviews of this commit yet — record a verdict below.
Start a review
crates/cli/ents-web/src/pages/agents.rs
@@ -94,10 +94,7 @@
/// page, `.active` naming the viewed session's id.
fn agents_sidebar(rows: &[(String, AgentSession)], active: Option<&str>) -> Markup {
html! {
- div.tree-head {
- span { "Agents" }
- a.btn.btn-sm.btn-ghost[active.is_some()] href="/agents" { "+ New" }
- }
+ (super::tree_head("Agents", "/agents", active.is_some()))
@if rows.is_empty() {
span.tree-note { "No agent sessions yet." }
}
@@ -265,9 +262,9 @@
}
/// The state badge [`agents_sidebar`] and [`show`] both render: a
-/// checkmark/cross `.status` chip for the terminal `done`/`failed` states
-/// (matching `crate::pages::commits::checks_section`'s identical result
-/// taxonomy -- a session's own finish literally records a
+/// checkmark/cross [`super::status_chip_labeled`] for the terminal
+/// `done`/`failed` states (matching `crate::pages::commits::checks_section`'s
+/// identical result taxonomy -- a session's own finish literally records a
/// [`ents_model::Status::Pass`]/`Fail`), or a neutral `.chip.state-in-progress`
/// pill labeled with [`session_state`]'s own word for every state still in
/// flight -- the four non-terminal states share one color, since the
@@ -275,8 +272,8 @@
fn state_badge(session: &AgentSession) -> Markup {
let label = session_state(session);
match label {
- "done" => html! { span.status.status-pass { "done" } },
- "failed" => html! { span.status.status-fail { "failed" } },
+ "done" => super::status_chip_labeled("done", "pass"),
+ "failed" => super::status_chip_labeled("failed", "fail"),
_ => html! {
span.chip.chip-pill.state-in-progress {
span.dot {}
crates/cli/ents-web/src/pages/commits.rs
@@ -380,18 +380,6 @@
seconds: Option<i64>,
}
-/// A [`ents_model::Status`]'s display word, doubling as its
-/// `.status-<word>` chip class -- the closed pass/fail/error taxonomy
-/// (`model.result-taxonomy`), spelled out here rather than through
-/// `Debug`.
-fn status_label(status: ents_model::Status) -> &'static str {
- match status {
- ents_model::Status::Pass => "pass",
- ents_model::Status::Fail => "fail",
- ents_model::Status::Error => "error",
- }
-}
-
/// The "Checks" card on `GET /commit/{oid}`: every recorded result
/// (`model.result-identity`) whose stored `target` field names this
/// commit -- the canonical `refs/meta/results/<effect>/<short-oid>`
@@ -451,9 +439,7 @@
div.card-header { "Checks" }
@for row in &rows {
div.card-row {
- span class={ "status status-" (status_label(row.status)) } {
- (status_label(row.status))
- }
+ (super::status_chip(row.status))
" "
a href={ "/effects/" (row.effect) } { (row.effect) }
@if let Some(member) = &row.self_run {
@@ -504,7 +490,7 @@
@for ((target, member), review) in &reviews {
div.card {
div.comment-meta {
- span class={ "verdict verdict-" (review.verdict) } { (review.verdict) }
+ (super::verdict_chip(review.verdict))
(super::avatar(member.as_str()))
span.author { (member) }
@let reviewer = ents_model::namespace::review_ref(target, member)
crates/cli/ents-web/src/pages/effects.rs
@@ -181,15 +181,15 @@
})?;
let body = match effect {
Ok(effect) => {
- let (label, status_class) = match effect.trigger.parse::<Query>() {
- Ok(_) => ("parses".to_owned(), "status-pass"),
- Err(error) => (format!("does not parse: {error}"), "status-fail"),
+ let (label, class) = match effect.trigger.parse::<Query>() {
+ Ok(_) => ("parses".to_owned(), "pass"),
+ Err(error) => (format!("does not parse: {error}"), "fail"),
};
html! {
(crate::render::view(&effect))
p {
"trigger query: "
- span class={ "status " (status_class) } { (label) }
+ (super::status_chip_labeled(&label, class))
}
}
}
crates/cli/ents-web/src/pages/issues.rs
@@ -84,10 +84,7 @@
/// linking to its own page, `.active` naming the viewed issue's id.
fn issues_sidebar(rows: &[(String, ents_forge::Issue)], active: Option<&str>) -> Markup {
html! {
- div.tree-head {
- span { "Issues" }
- a.btn.btn-sm.btn-ghost[active.is_some()] href="/issues" { "+ New" }
- }
+ (super::tree_head("Issues", "/issues", active.is_some()))
@if rows.is_empty() {
span.tree-note { "No issues yet." }
}
crates/cli/ents-web/src/pages/mod.rs
@@ -657,6 +657,37 @@
format!("scope-c{}", hash.checked_rem(6).unwrap_or(0))
}
+/// A `.status-<class>` chip: `label` as its text, `class` as its CSS suffix.
+pub(crate) fn status_chip_labeled(label: &str, class: &str) -> Markup {
+ html! { span class={ "status status-" (class) } { (label) } }
+}
+
+/// The `.status-<word>` chip for a closed pass/fail/error [`ents_model::Status`].
+pub(crate) fn status_chip(status: ents_model::Status) -> Markup {
+ let word = match status {
+ ents_model::Status::Pass => "pass",
+ ents_model::Status::Fail => "fail",
+ ents_model::Status::Error => "error",
+ };
+ status_chip_labeled(word, word)
+}
+
+/// A `.verdict-<word>` chip for a review's own [`ents_forge::review::Verdict`].
+pub(crate) fn verdict_chip(verdict: ents_forge::review::Verdict) -> Markup {
+ html! { span class={ "verdict verdict-" (verdict) } { (verdict) } }
+}
+
+/// A sidebar `.tree-head`: `name` plus a "+ New" link into `new_href`,
+/// ghost-styled while `viewing_one` (a child page is open).
+pub(crate) fn tree_head(name: &str, new_href: &str, viewing_one: bool) -> Markup {
+ html! {
+ div.tree-head {
+ span { (name) }
+ a.btn.btn-sm.btn-ghost[viewing_one] href=(new_href) { "+ New" }
+ }
+ }
+}
+
/// The acting session's member id -- the composite review key's
/// `<member>` segment -- resolved the same way
/// [`account::resolve_member_by_key`] does, falling back to a short hash of
crates/cli/ents-web/src/pages/reviews.rs
@@ -94,7 +94,7 @@
html! {
div.card {
div.comment-meta {
- span class={ "verdict verdict-" (review.verdict) } { (review.verdict) }
+ (super::verdict_chip(review.verdict))
(super::avatar(member.as_str()))
span.author { (member) }
span.spacer {}
@@ -158,7 +158,7 @@
href={ "/reviews/" (target) "/" (member) }
{
span.side-title {
- span class={ "verdict verdict-" (review.verdict) } { (review.verdict) }
+ (super::verdict_chip(review.verdict))
" " (member.as_str())
}
span.side-meta {
@@ -219,7 +219,7 @@
div.card {
dl.entity-view {
dt { "verdict" }
- dd { span class={ "verdict verdict-" (review.verdict) } { (review.verdict) } }
+ dd { (super::verdict_chip(review.verdict)) }
dt { "state" }
dd { (state_badge(review.state)) }
dt { "target" }