Files
imks/models/message_component.rs
zhenyi 821537186e refactor(tests): reformat code and update dependency management
- Reorganized import statements in adapter tests for better readability
- Replaced or_insert_with(Vec::new) with or_default() in test closures
- Updated Cargo.lock with new dependency versions and checksums
- Added TLS features to tonic dependency configuration
- Included sqlx, chrono, and uuid dependencies with specific features
- Added jsonwebtoken and arc-swap as project dependencies
- Reformatted assertion statements to comply with line length limits
- Adjusted base64 import order in engine codec module
- Updated protobuf include statement formatting
2026-06-11 12:11:05 +08:00

96 lines
3.0 KiB
Rust

//! Interactive message components — maps to `message_component` table.
//!
//! Discord-style interactive elements attached to messages: buttons, select
//! menus, etc. Each component belongs to a message and has its own layout row.
//! Clicking a component emits an interaction event back to the bot/webhook.
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
/// An interactive component attached to a message (button, select menu, etc.).
///
/// Maps to the `message_component` table. Each component belongs to a message
/// and has a layout row/position. User interactions emit callbacks.
#[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)]
pub struct MessageComponent {
pub id: Uuid,
pub message_id: Uuid,
/// Layout row within the message (0-based).
pub row: i32,
/// Position within the row (0-based).
pub position: i32,
/// "button" | "select_menu" | "text_input"
pub component_type: String,
/// Unique identifier sent back in interaction callbacks.
pub custom_id: String,
/// Display label.
pub label: Option<String>,
/// Emoji shown on the button (unicode or `:name:id`).
pub emoji: Option<String>,
/// Button style: "primary" | "secondary" | "success" | "danger" | "link"
pub style: Option<String>,
/// URL for link-style buttons.
pub url: Option<String>,
/// Whether the component is disabled.
pub disabled: bool,
/// Placeholder text for select menus.
pub placeholder: Option<String>,
/// Min/max selections for select menus.
pub min_values: Option<i32>,
pub max_values: Option<i32>,
/// Options for select menus, stored as JSON array.
pub options: Option<serde_json::Value>,
pub created_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum ComponentType {
#[default]
Button,
SelectMenu,
TextInput,
}
impl ComponentType {
pub fn as_str(&self) -> &'static str {
match self {
Self::Button => "button",
Self::SelectMenu => "select_menu",
Self::TextInput => "text_input",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_component_serialize() {
let c = MessageComponent {
id: Uuid::now_v7(),
message_id: Uuid::now_v7(),
row: 0,
position: 0,
component_type: ComponentType::Button.as_str().into(),
custom_id: "btn_approve".into(),
label: Some("Approve".into()),
emoji: Some("".into()),
style: Some("success".into()),
url: None,
disabled: false,
placeholder: None,
min_values: None,
max_values: None,
options: None,
created_at: Utc::now(),
};
let json = serde_json::to_value(&c).unwrap();
assert_eq!(json["component_type"], "button");
assert_eq!(json["style"], "success");
}
}