cinch_web/ext.rs
1//! Extension trait for domain-specific web UI rendering.
2//!
3//! Domain crates implement [`WebExtensionRenderer`] to provide structured data
4//! that the Next.js frontend can render. Unlike the TUI renderer (which returns
5//! ratatui `Span`s), this returns JSON-serializable data.
6
7use cinch_rs::ui::{QuestionChoice, UiExtension};
8use serde::Serialize;
9
10/// Trait for domain-specific web UI rendering.
11///
12/// Domain crates implement this to provide structured data that the
13/// Next.js frontend can render as status badges, extension panels,
14/// and choice metadata.
15///
16/// # Example
17///
18/// ```ignore
19/// struct MyWebRenderer;
20///
21/// impl WebExtensionRenderer for MyWebRenderer {
22/// fn status_fields(&self, ext: &dyn UiExtension) -> Vec<StatusField> {
23/// vec![StatusField {
24/// label: "Count".into(),
25/// value: "42".into(),
26/// variant: "info".into(),
27/// }]
28/// }
29/// }
30/// ```
31pub trait WebExtensionRenderer: Send + Sync {
32 /// Extra status fields to display in the status bar.
33 ///
34 /// Returns key-value pairs rendered as badges in the web UI.
35 fn status_fields(&self, ext: &dyn UiExtension) -> Vec<StatusField> {
36 let _ = ext;
37 vec![]
38 }
39
40 /// Serialize the current extension state for WebSocket broadcast.
41 ///
42 /// Called after relevant events to push domain-specific state to clients.
43 fn to_ws_json(&self, ext: &dyn UiExtension) -> Option<serde_json::Value> {
44 let _ = ext;
45 None
46 }
47
48 /// Optional metadata to display alongside each question choice.
49 ///
50 /// For example, a tweet agent might return character count and a color
51 /// variant indicating whether the tweet is within the 280-char limit.
52 fn choice_metadata(
53 &self,
54 ext: &dyn UiExtension,
55 choice: &QuestionChoice,
56 ) -> Option<ChoiceMetadata> {
57 let _ = (ext, choice);
58 None
59 }
60}
61
62/// A key-value status field displayed as a badge in the web UI status bar.
63#[derive(Clone, Debug, Serialize)]
64pub struct StatusField {
65 /// Short label (e.g., "Drafted").
66 pub label: String,
67 /// Display value (e.g., "3").
68 pub value: String,
69 /// CSS class variant for styling (e.g., "info", "success", "warning", "error").
70 pub variant: String,
71}
72
73/// Metadata displayed alongside a question choice in the web UI.
74#[derive(Clone, Debug, Serialize)]
75pub struct ChoiceMetadata {
76 /// Display text (e.g., "142 chars").
77 pub text: String,
78 /// CSS class variant for styling.
79 pub variant: String,
80}
81
82/// No-op renderer for agents with no domain-specific web UI.
83pub struct NoWebExtension;
84
85impl WebExtensionRenderer for NoWebExtension {}