reasoninglayer 0.1.2

Rust client SDK for the Reasoning Layer API
Documentation
//! UI descriptor DTOs.

use std::collections::BTreeMap;

use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum LayoutModeDto {
    Detail,
    List,
    Grid,
    Form,
    Dashboard,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LayoutSlotDto {
    pub id: String,
    pub label: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LayoutSurfaceDto {
    pub id: String,
    pub layout_mode: LayoutModeDto,
    pub slots: Vec<LayoutSlotDto>,
}

/// Validation rule type.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ValidationTypeDto {
    Required,
    Min { params: f64 },
    Max { params: f64 },
    Pattern { params: String },
    OneOf { params: Vec<String> },
    ValueType { params: String },
    DateAfter { params: String },
    DateBefore { params: String },
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValidationRuleDto {
    pub field: String,
    pub message: String,
    pub rule_type: ValidationTypeDto,
}

/// UI action.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum UIActionDto {
    SubmitForm {
        sort_name: String,
        osfql_template: String,
        field_types: BTreeMap<String, String>,
    },
    LoadData {
        osfql_query: String,
    },
    UpdateForm {
        sort_name: String,
        osfql_template: String,
        field_types: BTreeMap<String, String>,
    },
    DeleteRecord {
        sort_name: String,
    },
    TriggerInference {
        osfql_derive: String,
    },
    Navigate {
        sort_id: String,
        view_mode: String,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        term_id: Option<String>,
    },
    Refresh,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UIDescriptorDto {
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub actions: Vec<UIActionDto>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub binding_path: Option<String>,
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub children: Vec<UIDescriptorDto>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub initial_values: Option<serde_json::Value>,
    pub priority: f64,
    #[serde(default)]
    pub props: serde_json::Value,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub slot_id: Option<String>,
    pub sort: String,
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub validation_rules: Vec<ValidationRuleDto>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct UIAssemblyStatsDto {
    pub component_count: u64,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub data_rows: Option<u64>,
    pub included_features: u64,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub osfql_executed: Option<String>,
    pub sort_name: String,
    pub total_features: u64,
    pub view_mode: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UIDescribeRequest {
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub customizations: Option<Vec<serde_json::Value>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub load_data: Option<bool>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub max_components: Option<u32>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub max_depth: Option<u32>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub priority_threshold: Option<f64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub query: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub session_id: Option<String>,
    pub sort_id: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub term_id: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UIDescribeResponse {
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub data: Option<serde_json::Value>,
    pub descriptor: UIDescriptorDto,
    pub layout: LayoutSurfaceDto,
    pub stats: UIAssemblyStatsDto,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UIActionRequest {
    pub action_type: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub field_types: Option<serde_json::Value>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub original_values: Option<serde_json::Value>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub osfql: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub sort_name: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub term_id: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub values: Option<serde_json::Value>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct UIActionResponse {
    #[serde(default)]
    pub diagnostics: Vec<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub error: Option<String>,
    #[serde(default)]
    pub produced_term_ids: Vec<String>,
    pub success: bool,
}

/// Catalog entry — `UiSort` is structure-opaque from the TS SDK, so we keep it as JSON.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UICatalogEntry {
    pub category: String,
    pub sort: serde_json::Value,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct UICatalogResponse {
    #[serde(default)]
    pub components: Vec<UICatalogEntry>,
    pub count: u64,
}