Files
certifai/src/pages/chat.rs
Sharang Parnerkar 83772cc256
All checks were successful
CI / Clippy (push) Successful in 2m17s
CI / Security Audit (push) Successful in 1m38s
CI / Format (pull_request) Successful in 6m28s
CI / Tests (push) Successful in 2m51s
CI / Format (push) Successful in 6m17s
CI / Clippy (pull_request) Successful in 2m15s
CI / Security Audit (pull_request) Successful in 1m42s
CI / Tests (pull_request) Successful in 2m48s
CI / Deploy (push) Has been skipped
CI / Deploy (pull_request) Has been skipped
fix(fmt): ran dx fmt
2026-02-19 12:20:41 +01:00

146 lines
5.8 KiB
Rust

use dioxus::prelude::*;
use crate::components::ChatBubble;
use crate::models::{ChatMessage, ChatRole, ChatSession};
/// ChatGPT-style chat interface with session list and message area.
///
/// Full-height layout: left panel shows session history,
/// right panel shows messages and input bar.
#[component]
pub fn ChatPage() -> Element {
let sessions = use_signal(mock_sessions);
let mut active_session_id = use_signal(|| "session-1".to_string());
let mut input_text = use_signal(String::new);
// Clone data out of signals before entering the rsx! block to avoid
// holding a `Signal::read()` borrow across potential await points.
let sessions_list = sessions.read().clone();
let current_id = active_session_id.read().clone();
let active_session = sessions_list.iter().find(|s| s.id == current_id).cloned();
rsx! {
section { class: "chat-page",
div { class: "chat-sidebar-panel",
div { class: "chat-sidebar-header",
h3 { "Conversations" }
button { class: "btn-icon", "+" }
}
div { class: "chat-session-list",
for session in &sessions_list {
{
let is_active = session.id == current_id;
let class = if is_active {
"chat-session-item chat-session-item--active"
} else {
"chat-session-item"
};
let id = session.id.clone();
rsx! {
button { class: "{class}", onclick: move |_| active_session_id.set(id.clone()),
div { class: "chat-session-title", "{session.title}" }
div { class: "chat-session-date", "{session.created_at}" }
}
}
}
}
}
}
div { class: "chat-main-panel",
if let Some(session) = &active_session {
div { class: "chat-messages",
for msg in &session.messages {
ChatBubble { key: "{msg.id}", message: msg.clone() }
}
}
} else {
div { class: "chat-empty",
p { "Select a conversation or start a new one." }
}
}
div { class: "chat-input-bar",
button { class: "btn-icon chat-attach-btn", "+" }
input {
class: "chat-input",
r#type: "text",
placeholder: "Type a message...",
value: "{input_text}",
oninput: move |evt: Event<FormData>| {
input_text.set(evt.value());
},
}
button { class: "btn-primary chat-send-btn", "Send" }
}
}
}
}
}
/// Returns mock chat sessions with sample messages.
fn mock_sessions() -> Vec<ChatSession> {
vec![
ChatSession {
id: "session-1".into(),
title: "RAG Pipeline Setup".into(),
messages: vec![
ChatMessage {
id: "msg-1".into(),
role: ChatRole::User,
content: "How do I set up a RAG pipeline with Ollama?".into(),
attachments: vec![],
timestamp: "10:30".into(),
},
ChatMessage {
id: "msg-2".into(),
role: ChatRole::Assistant,
content: "To set up a RAG pipeline with Ollama, you'll need to: \
1) Install Ollama and pull your preferred model, \
2) Set up a vector database (e.g. ChromaDB), \
3) Create an embedding pipeline for your documents, \
4) Wire the retrieval step into your prompt chain."
.into(),
attachments: vec![],
timestamp: "10:31".into(),
},
],
created_at: "2026-02-18".into(),
},
ChatSession {
id: "session-2".into(),
title: "GDPR Compliance Check".into(),
messages: vec![
ChatMessage {
id: "msg-3".into(),
role: ChatRole::User,
content: "What data does CERTifAI store about users?".into(),
attachments: vec![],
timestamp: "09:15".into(),
},
ChatMessage {
id: "msg-4".into(),
role: ChatRole::Assistant,
content: "CERTifAI stores only the minimum data required: \
email address, session tokens, and usage metrics. \
All data stays on your infrastructure."
.into(),
attachments: vec![],
timestamp: "09:16".into(),
},
],
created_at: "2026-02-17".into(),
},
ChatSession {
id: "session-3".into(),
title: "MCP Server Configuration".into(),
messages: vec![ChatMessage {
id: "msg-5".into(),
role: ChatRole::User,
content: "How do I add a new MCP server?".into(),
attachments: vec![],
timestamp: "14:00".into(),
}],
created_at: "2026-02-16".into(),
},
]
}