Skip to main content

cloudflare_dns/ui/
state.rs

1/// Application state management.
2///
3/// This module contains the core state types used throughout the application,
4/// including the shared AppState and iocraft Props definitions.
5use iocraft::prelude::*;
6use std::sync::{Arc, Mutex};
7
8use crate::api::{CloudflareClient, DnsCache, DnsRecord};
9
10/// Shared application state wrapped in Arc for thread-safe access.
11///
12/// This state is shared across multiple async tasks and UI components.
13pub struct AppState {
14    /// Cloudflare API client
15    pub client: Arc<CloudflareClient>,
16    /// Zone name (resolved from zone ID on startup)
17    pub zone_name: Mutex<String>,
18    /// Current DNS records
19    pub records: Mutex<Vec<DnsRecord>>,
20    /// Unique IPs extracted from A/AAAA records (for IP selector)
21    pub existing_ips: Mutex<Vec<String>>,
22    /// Cache for DNS records to reduce redundant API calls
23    pub dns_cache: Mutex<DnsCache>,
24}
25
26impl AppState {
27    /// Create a new AppState instance.
28    pub fn new(api_token: String, zone_id: String) -> Self {
29        Self {
30            client: Arc::new(CloudflareClient::new(api_token, zone_id.clone())),
31            zone_name: Mutex::new(zone_id),
32            records: Mutex::new(Vec::new()),
33            existing_ips: Mutex::new(Vec::new()),
34            dns_cache: Mutex::new(DnsCache::with_default_ttl()),
35        }
36    }
37}
38
39/// Props passed to the root App component.
40#[derive(Props, Clone)]
41pub struct AppProps {
42    /// Shared application state
43    pub state: Arc<AppState>,
44}
45
46impl Default for AppProps {
47    fn default() -> Self {
48        Self {
49            state: Arc::new(AppState::new(String::new(), String::new())),
50        }
51    }
52}
53
54/// Props for the FormField component.
55#[derive(Default, Props)]
56pub struct FormFieldProps {
57    /// Field label
58    pub label: String,
59    /// Field value (state binding)
60    pub value: Option<State<String>>,
61    /// Whether this field has focus
62    pub has_focus: bool,
63    /// Optional suffix text (e.g., domain suffix)
64    pub suffix: String,
65    /// Whether this field should be editable as text input (false for cycled fields like Type/Proxied)
66    pub is_editable: bool,
67}
68
69/// Props for the StatusBar component.
70#[derive(Default, Props)]
71pub struct StatusBarProps {
72    /// Status message text
73    pub message: String,
74}
75
76/// Represents the current view mode of the application.
77#[derive(Clone, Copy, PartialEq, Default)]
78pub enum AppView {
79    /// Main record list view
80    #[default]
81    List,
82    /// Create new record form
83    Create,
84    /// Edit existing record form
85    Edit,
86    /// Delete confirmation dialog
87    Delete,
88    /// IP address selector
89    IpSelect,
90}