feat(dash): improved frontend dashboard (#6)
All checks were successful
CI / Format (push) Successful in 6m30s
CI / Clippy (push) Successful in 2m25s
CI / Security Audit (push) Successful in 1m53s
CI / Tests (push) Successful in 2m50s
CI / Deploy (push) Successful in 4s

Co-authored-by: Sharang Parnerkar <parnerkarsharang@gmail.com>
Reviewed-on: #6
This commit was merged in pull request #6.
This commit is contained in:
2026-02-19 11:52:41 +00:00
parent f699976f4d
commit a588be306a
46 changed files with 4960 additions and 261 deletions

71
src/models/chat.rs Normal file
View File

@@ -0,0 +1,71 @@
use serde::{Deserialize, Serialize};
/// The role of a participant in a chat conversation.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ChatRole {
/// Message sent by the human user
User,
/// Message generated by the AI assistant
Assistant,
/// System-level instruction (not displayed in UI)
System,
}
/// The type of file attached to a chat message.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum AttachmentKind {
/// Image file (png, jpg, webp, etc.)
Image,
/// Document file (pdf, docx, txt, etc.)
Document,
/// Source code file
Code,
}
/// A file attachment on a chat message.
///
/// # Fields
///
/// * `name` - Original filename
/// * `kind` - Type of attachment for rendering
/// * `size_bytes` - File size in bytes
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Attachment {
pub name: String,
pub kind: AttachmentKind,
pub size_bytes: u64,
}
/// A single message in a chat conversation.
///
/// # Fields
///
/// * `id` - Unique message identifier
/// * `role` - Who sent this message
/// * `content` - The message text content
/// * `attachments` - Optional file attachments
/// * `timestamp` - ISO 8601 timestamp string
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ChatMessage {
pub id: String,
pub role: ChatRole,
pub content: String,
pub attachments: Vec<Attachment>,
pub timestamp: String,
}
/// A chat session containing a conversation history.
///
/// # Fields
///
/// * `id` - Unique session identifier
/// * `title` - Display title (usually derived from first message)
/// * `messages` - Ordered list of messages in the session
/// * `created_at` - ISO 8601 creation timestamp
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ChatSession {
pub id: String,
pub title: String,
pub messages: Vec<ChatMessage>,
pub created_at: String,
}

47
src/models/developer.rs Normal file
View File

@@ -0,0 +1,47 @@
use serde::{Deserialize, Serialize};
/// An AI agent entry managed through the developer tools.
///
/// # Fields
///
/// * `id` - Unique agent identifier
/// * `name` - Human-readable agent name
/// * `description` - What this agent does
/// * `status` - Current running status label
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AgentEntry {
pub id: String,
pub name: String,
pub description: String,
pub status: String,
}
/// A workflow/flow entry from the flow builder.
///
/// # Fields
///
/// * `id` - Unique flow identifier
/// * `name` - Human-readable flow name
/// * `node_count` - Number of nodes in the flow graph
/// * `last_run` - ISO 8601 timestamp of the last execution
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct FlowEntry {
pub id: String,
pub name: String,
pub node_count: u32,
pub last_run: Option<String>,
}
/// A single analytics metric for the developer dashboard.
///
/// # Fields
///
/// * `label` - Display name of the metric
/// * `value` - Current value as a formatted string
/// * `change_pct` - Percentage change from previous period (positive = increase)
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AnalyticsMetric {
pub label: String,
pub value: String,
pub change_pct: f64,
}

60
src/models/knowledge.rs Normal file
View File

@@ -0,0 +1,60 @@
use serde::{Deserialize, Serialize};
/// The type of file stored in the knowledge base.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum FileKind {
/// PDF document
Pdf,
/// Plain text or markdown file
Text,
/// Spreadsheet (csv, xlsx)
Spreadsheet,
/// Source code file
Code,
/// Image file
Image,
}
impl FileKind {
/// Returns the display label for a file kind.
pub fn label(&self) -> &'static str {
match self {
Self::Pdf => "PDF",
Self::Text => "Text",
Self::Spreadsheet => "Spreadsheet",
Self::Code => "Code",
Self::Image => "Image",
}
}
/// Returns an icon identifier for rendering.
pub fn icon(&self) -> &'static str {
match self {
Self::Pdf => "file-pdf",
Self::Text => "file-text",
Self::Spreadsheet => "file-spreadsheet",
Self::Code => "file-code",
Self::Image => "file-image",
}
}
}
/// A file stored in the knowledge base for RAG retrieval.
///
/// # Fields
///
/// * `id` - Unique file identifier
/// * `name` - Original filename
/// * `kind` - Type classification of the file
/// * `size_bytes` - File size in bytes
/// * `uploaded_at` - ISO 8601 upload timestamp
/// * `chunk_count` - Number of vector chunks created from this file
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct KnowledgeFile {
pub id: String,
pub name: String,
pub kind: FileKind,
pub size_bytes: u64,
pub uploaded_at: String,
pub chunk_count: u32,
}

View File

@@ -1,3 +1,17 @@
mod chat;
mod developer;
mod knowledge;
mod news;
mod organization;
mod provider;
mod tool;
mod user;
pub use chat::*;
pub use developer::*;
pub use knowledge::*;
pub use news::*;
pub use organization::*;
pub use provider::*;
pub use tool::*;
pub use user::*;

62
src/models/news.rs Normal file
View File

@@ -0,0 +1,62 @@
use serde::{Deserialize, Serialize};
/// Categories for classifying AI news articles.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum NewsCategory {
/// Large language model announcements and updates
Llm,
/// AI agent frameworks and tooling
Agents,
/// Data privacy and regulatory compliance
Privacy,
/// AI infrastructure and deployment
Infrastructure,
/// Open-source AI project releases
OpenSource,
}
impl NewsCategory {
/// Returns the display label for a news category.
pub fn label(&self) -> &'static str {
match self {
Self::Llm => "LLM",
Self::Agents => "Agents",
Self::Privacy => "Privacy",
Self::Infrastructure => "Infrastructure",
Self::OpenSource => "Open Source",
}
}
/// Returns the CSS class suffix for styling category badges.
pub fn css_class(&self) -> &'static str {
match self {
Self::Llm => "llm",
Self::Agents => "agents",
Self::Privacy => "privacy",
Self::Infrastructure => "infrastructure",
Self::OpenSource => "open-source",
}
}
}
/// A single news feed card representing an AI-related article.
///
/// # Fields
///
/// * `title` - Headline of the article
/// * `source` - Publishing outlet or author
/// * `summary` - Brief summary text
/// * `category` - Classification category
/// * `url` - Link to the full article
/// * `thumbnail_url` - Optional thumbnail image URL
/// * `published_at` - ISO 8601 date string
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct NewsCard {
pub title: String,
pub source: String,
pub summary: String,
pub category: NewsCategory,
pub url: String,
pub thumbnail_url: Option<String>,
pub published_at: String,
}

View File

@@ -0,0 +1,84 @@
use serde::{Deserialize, Serialize};
/// Role assigned to an organization member.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum MemberRole {
/// Full administrative access
Admin,
/// Standard user access
Member,
/// Read-only access
Viewer,
}
impl MemberRole {
/// Returns the display label for a member role.
pub fn label(&self) -> &'static str {
match self {
Self::Admin => "Admin",
Self::Member => "Member",
Self::Viewer => "Viewer",
}
}
/// Returns all available roles for populating dropdowns.
pub fn all() -> &'static [Self] {
&[Self::Admin, Self::Member, Self::Viewer]
}
}
/// A member of the organization.
///
/// # Fields
///
/// * `id` - Unique member identifier
/// * `name` - Display name
/// * `email` - Email address
/// * `role` - Assigned role within the organization
/// * `joined_at` - ISO 8601 join date
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct OrgMember {
pub id: String,
pub name: String,
pub email: String,
pub role: MemberRole,
pub joined_at: String,
}
/// A pricing plan tier.
///
/// # Fields
///
/// * `id` - Unique plan identifier
/// * `name` - Plan display name (e.g. "Starter", "Team", "Enterprise")
/// * `price_eur` - Monthly price in euros
/// * `features` - List of included features
/// * `highlighted` - Whether this plan should be visually emphasized
/// * `max_seats` - Maximum number of seats, None for unlimited
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PricingPlan {
pub id: String,
pub name: String,
pub price_eur: u32,
pub features: Vec<String>,
pub highlighted: bool,
pub max_seats: Option<u32>,
}
/// Billing usage statistics for the current cycle.
///
/// # Fields
///
/// * `seats_used` - Number of active seats
/// * `seats_total` - Total seats in the plan
/// * `tokens_used` - Tokens consumed this billing cycle
/// * `tokens_limit` - Token limit for the billing cycle
/// * `billing_cycle_end` - ISO 8601 date when the current cycle ends
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BillingUsage {
pub seats_used: u32,
pub seats_total: u32,
pub tokens_used: u64,
pub tokens_limit: u64,
pub billing_cycle_end: String,
}

74
src/models/provider.rs Normal file
View File

@@ -0,0 +1,74 @@
use serde::{Deserialize, Serialize};
/// Supported LLM provider backends.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum LlmProvider {
/// Self-hosted models via Ollama
Ollama,
/// Hugging Face Inference API
HuggingFace,
/// OpenAI-compatible endpoints
OpenAi,
/// Anthropic Claude API
Anthropic,
}
impl LlmProvider {
/// Returns the display name for a provider.
pub fn label(&self) -> &'static str {
match self {
Self::Ollama => "Ollama",
Self::HuggingFace => "Hugging Face",
Self::OpenAi => "OpenAI",
Self::Anthropic => "Anthropic",
}
}
}
/// A model available from a provider.
///
/// # Fields
///
/// * `id` - Unique model identifier (e.g. "llama3.1:8b")
/// * `name` - Human-readable display name
/// * `provider` - Which provider hosts this model
/// * `context_window` - Maximum context length in tokens
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ModelEntry {
pub id: String,
pub name: String,
pub provider: LlmProvider,
pub context_window: u32,
}
/// An embedding model available from a provider.
///
/// # Fields
///
/// * `id` - Unique embedding model identifier
/// * `name` - Human-readable display name
/// * `provider` - Which provider hosts this model
/// * `dimensions` - Output embedding dimensions
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct EmbeddingEntry {
pub id: String,
pub name: String,
pub provider: LlmProvider,
pub dimensions: u32,
}
/// Active provider configuration state.
///
/// # Fields
///
/// * `provider` - Currently selected provider
/// * `selected_model` - ID of the active chat model
/// * `selected_embedding` - ID of the active embedding model
/// * `api_key_set` - Whether an API key has been configured
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProviderConfig {
pub provider: LlmProvider,
pub selected_model: String,
pub selected_embedding: String,
pub api_key_set: bool,
}

73
src/models/tool.rs Normal file
View File

@@ -0,0 +1,73 @@
use serde::{Deserialize, Serialize};
/// Category grouping for MCP tools.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ToolCategory {
/// Web search and browsing tools
Search,
/// File and document processing tools
FileSystem,
/// Computation and math tools
Compute,
/// Code execution and analysis tools
Code,
/// Communication and notification tools
Communication,
}
impl ToolCategory {
/// Returns the display label for a tool category.
pub fn label(&self) -> &'static str {
match self {
Self::Search => "Search",
Self::FileSystem => "File System",
Self::Compute => "Compute",
Self::Code => "Code",
Self::Communication => "Communication",
}
}
}
/// Status of an MCP tool instance.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ToolStatus {
/// Tool is running and available
Active,
/// Tool is installed but not running
Inactive,
/// Tool encountered an error
Error,
}
impl ToolStatus {
/// Returns the CSS class suffix for status styling.
pub fn css_class(&self) -> &'static str {
match self {
Self::Active => "active",
Self::Inactive => "inactive",
Self::Error => "error",
}
}
}
/// An MCP (Model Context Protocol) tool entry.
///
/// # Fields
///
/// * `id` - Unique tool identifier
/// * `name` - Human-readable display name
/// * `description` - Brief description of what the tool does
/// * `category` - Classification category
/// * `status` - Current running status
/// * `enabled` - Whether the tool is toggled on by the user
/// * `icon` - Icon identifier for rendering
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct McpTool {
pub id: String,
pub name: String,
pub description: String,
pub category: ToolCategory,
pub status: ToolStatus,
pub enabled: bool,
pub icon: String,
}