use std::collections::HashMap;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum DiscoverySourceType {
Playwright,
UiBridge,
Recording,
Vision,
Manual,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum TransitionTriggerType {
Click,
Type,
Scroll,
Hover,
Custom,
}
impl Default for TransitionTriggerType {
fn default() -> Self {
Self::Click
}
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct DiscoveryBoundingBox {
pub x: f64,
pub y: f64,
pub width: f64,
pub height: f64,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct DiscoveryTransitionTrigger {
#[serde(default)]
pub r#type: TransitionTriggerType,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub image_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub element_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub selector: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub value: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct DiscoveredStateImage {
pub id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub screenshot_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub screenshot_url: Option<String>,
pub bbox: DiscoveryBoundingBox,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub pixel_hash: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub state_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub element_type: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
#[serde(default = "default_confidence_one")]
pub confidence: f64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, Value>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct DiscoveredState {
pub id: String,
pub name: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub image_ids: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub render_ids: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub element_ids: Vec<String>,
#[serde(default = "default_confidence_one")]
pub confidence: f64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, Value>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct DiscoveredTransition {
pub id: String,
pub from_state_id: String,
pub to_state_id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub trigger: Option<DiscoveryTransitionTrigger>,
#[serde(default = "default_confidence_one")]
pub confidence: f64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, Value>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct StateDiscoveryResult {
pub id: String,
pub project_id: String,
pub name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
pub source_type: DiscoverySourceType,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub source_session_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub discovery_strategy: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub images: Vec<DiscoveredStateImage>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub states: Vec<DiscoveredState>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub transitions: Vec<DiscoveredTransition>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub element_to_renders: HashMap<String, Vec<String>>,
#[serde(default)]
pub image_count: i64,
#[serde(default)]
pub state_count: i64,
#[serde(default)]
pub transition_count: i64,
#[serde(default)]
pub render_count: i64,
#[serde(default)]
pub unique_element_count: i64,
#[serde(default)]
pub confidence: f64,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub discovery_metadata: HashMap<String, Value>,
pub created_at: String,
pub updated_at: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct StateDiscoveryResultSummary {
pub id: String,
pub project_id: String,
pub name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
pub source_type: DiscoverySourceType,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub discovery_strategy: Option<String>,
#[serde(default)]
pub image_count: i64,
#[serde(default)]
pub state_count: i64,
#[serde(default)]
pub transition_count: i64,
#[serde(default)]
pub confidence: f64,
pub created_at: String,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct StateDiscoveryResultListResponse {
pub items: Vec<StateDiscoveryResultSummary>,
pub total: i64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct StateDiscoveryResultCreate {
pub name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
pub source_type: DiscoverySourceType,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub source_session_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub discovery_strategy: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub images: Vec<DiscoveredStateImage>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub states: Vec<DiscoveredState>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub transitions: Vec<DiscoveredTransition>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub element_to_renders: HashMap<String, Vec<String>>,
#[serde(default)]
pub confidence: f64,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub discovery_metadata: HashMap<String, Value>,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct StateDiscoveryResultUpdate {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub images: Option<Vec<DiscoveredStateImage>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub states: Option<Vec<DiscoveredState>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub transitions: Option<Vec<DiscoveredTransition>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub discovery_metadata: Option<HashMap<String, Value>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct StateMachineExport {
#[serde(default = "default_export_version")]
pub version: String,
pub name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
pub source_type: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub images: Vec<DiscoveredStateImage>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub states: Vec<DiscoveredState>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub transitions: Vec<DiscoveredTransition>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub element_to_renders: HashMap<String, Vec<String>>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub metadata: HashMap<String, Value>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct StateMachineImport {
pub state_machine: StateMachineExport,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
}
fn default_confidence_one() -> f64 {
1.0
}
fn default_export_version() -> String {
"1.0.0".to_string()
}