Skip to main content

leptos_forms_rs/devtools/debug/
debug_utilities.rs

1//! Debug Utilities implementation
2//!
3//! This module provides debug utilities for form inspection and debugging.
4
5use crate::core::types::FieldValue;
6use crate::core::{Form, FormHandle};
7use leptos::prelude::GetUntracked;
8use std::collections::HashMap;
9use std::time::SystemTime;
10
11use super::super::types::{FieldChange, FormSnapshot, IntegrityCheck, SnapshotDiff};
12
13/// Debug Utilities for DevTools
14pub struct DebugUtilities;
15
16impl DebugUtilities {
17    pub fn create_form_snapshot<T: Form + Send + Sync + PartialEq>(
18        form_handle: &FormHandle<T>,
19    ) -> FormSnapshot {
20        let form_data = form_handle.values().get_untracked();
21        let state = form_handle.state().get_untracked();
22        let mut field_values = HashMap::new();
23
24        for field_metadata in &T::schema().field_metadata {
25            let value = form_data.get_field_value(&field_metadata.name);
26            field_values.insert(field_metadata.name.clone(), value);
27        }
28
29        FormSnapshot {
30            form_name: T::schema().name,
31            timestamp: SystemTime::now(),
32            field_count: T::schema().field_metadata.len(),
33            field_values,
34            is_dirty: state.is_dirty,
35            is_submitting: state.is_submitting,
36            has_errors: !state.errors.is_empty(),
37        }
38    }
39
40    pub fn compare_snapshots(snapshot1: &FormSnapshot, snapshot2: &FormSnapshot) -> SnapshotDiff {
41        let mut changed_fields = Vec::new();
42
43        for (field_name, value1) in &snapshot1.field_values {
44            if let Some(value2) = snapshot2.field_values.get(field_name) {
45                if value1 != value2 {
46                    changed_fields.push(FieldChange {
47                        field_name: field_name.clone(),
48                        old_value: Some(value1.clone()),
49                        new_value: Some(value2.clone()),
50                    });
51                }
52            }
53        }
54
55        SnapshotDiff {
56            has_changes: !changed_fields.is_empty(),
57            changed_fields,
58        }
59    }
60
61    pub fn export_form_data<T: Form + Send + Sync + PartialEq + std::fmt::Debug>(
62        form_handle: &FormHandle<T>,
63    ) -> String {
64        let form_data = form_handle.values().get_untracked();
65        let state = form_handle.state().get_untracked();
66
67        format!(
68            "Form: {}\nFields: {}\nIs Dirty: {}\nIs Submitting: {}\nHas Errors: {}\nData: {:?}",
69            T::schema().name,
70            T::schema().field_metadata.len(),
71            state.is_dirty,
72            state.is_submitting,
73            !state.errors.is_empty(),
74            form_data
75        )
76    }
77
78    pub fn validate_form_integrity<T: Form + Send + Sync + PartialEq>(
79        form_handle: &FormHandle<T>,
80    ) -> IntegrityCheck {
81        let mut issues = Vec::new();
82
83        // Check if all required fields have values
84        let form_data = form_handle.values().get_untracked();
85        for field_metadata in &T::schema().field_metadata {
86            if field_metadata.is_required {
87                let value = form_data.get_field_value(&field_metadata.name);
88                if matches!(value, FieldValue::Null)
89                    || matches!(value, FieldValue::String(ref s) if s.is_empty())
90                {
91                    issues.push(format!("Required field '{}' is empty", field_metadata.name));
92                }
93            }
94        }
95
96        IntegrityCheck {
97            is_valid: issues.is_empty(),
98            issues,
99        }
100    }
101}