Skip to main content

jira_core/model/
field.rs

1use serde::{Deserialize, Serialize};
2use serde_json::{json, Value};
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct Field {
6    pub id: String,
7    pub name: String,
8    pub field_type: String,
9    pub required: bool,
10    pub schema: Option<Value>,
11    /// Allowed values for Select / MultiSelect fields (from createmeta)
12    pub allowed_values: Option<Vec<Value>>,
13}
14
15/// Typed classification of a Jira field, derived from its schema.
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub enum FieldKind {
18    Text,
19    Number,
20    DateTime,
21    Select,
22    MultiSelect,
23    User,
24    UserArray,
25    Url,
26    Checkbox,
27    Labels,
28    CascadingSelect,
29    Unknown,
30}
31
32impl Field {
33    /// Derive the kind of this field from its schema metadata.
34    pub fn kind(&self) -> FieldKind {
35        let schema = match &self.schema {
36            Some(s) => s,
37            None => return FieldKind::Unknown,
38        };
39
40        let typ = schema.get("type").and_then(|v| v.as_str()).unwrap_or("");
41        let items = schema.get("items").and_then(|v| v.as_str()).unwrap_or("");
42        let custom = schema.get("custom").and_then(|v| v.as_str()).unwrap_or("");
43
44        match typ {
45            "string" if custom.contains("url") => FieldKind::Url,
46            "string" => FieldKind::Text,
47            "number" => FieldKind::Number,
48            "datetime" | "date" => FieldKind::DateTime,
49            "boolean" => FieldKind::Checkbox,
50            "option" if custom.contains("cascading") => FieldKind::CascadingSelect,
51            "option" => FieldKind::Select,
52            "array" if items == "option" => FieldKind::MultiSelect,
53            "array" if items == "string" => FieldKind::Labels,
54            "array" if items == "user" => FieldKind::UserArray,
55            "user" => FieldKind::User,
56            _ => FieldKind::Unknown,
57        }
58    }
59}
60
61/// Typed value ready to be serialized into a Jira API request body.
62#[derive(Debug, Clone)]
63pub enum FieldValue {
64    Text(String),
65    Number(f64),
66    /// ISO 8601 date string ("YYYY-MM-DD" or full datetime)
67    Date(String),
68    /// Select field — match by value string
69    SelectName(String),
70    /// Select field — match by option ID
71    SelectId(String),
72    /// Multi-select — list of value strings
73    MultiSelect(Vec<String>),
74    /// User field — identified by email address
75    UserEmail(String),
76    /// Labels — plain string list
77    Labels(Vec<String>),
78    /// Escape hatch for anything else
79    Raw(Value),
80}
81
82impl FieldValue {
83    /// Serialize to the JSON shape Jira expects for each field type.
84    pub fn to_api_json(&self) -> Value {
85        match self {
86            FieldValue::Text(s) => json!(s),
87            FieldValue::Number(n) => json!(n),
88            FieldValue::Date(d) => json!(d),
89            FieldValue::SelectName(v) => json!({ "value": v }),
90            FieldValue::SelectId(id) => json!({ "id": id }),
91            FieldValue::MultiSelect(vs) => {
92                json!(vs.iter().map(|v| json!({ "value": v })).collect::<Vec<_>>())
93            }
94            FieldValue::UserEmail(e) => json!({ "emailAddress": e }),
95            FieldValue::Labels(ls) => json!(ls),
96            FieldValue::Raw(v) => v.clone(),
97        }
98    }
99}