zerolaunch_plugin_api/config/
action.rs1use serde::{Deserialize, Serialize};
2#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct ConfigActionDef {
7 #[serde(rename = "action", default)]
9 pub action: String,
10 #[serde(rename = "label", default)]
12 pub label: String,
13 #[serde(rename = "description", default)]
15 pub description: String,
16}
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
22#[serde(tag = "kind", content = "binding")]
23pub enum FieldAction {
24 #[serde(rename = "data")]
26 Data(DataActionBinding),
27 #[serde(rename = "effect")]
29 Effect(EffectActionBinding),
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct DataActionBinding {
37 #[serde(rename = "action", default)]
39 pub action: String,
40 #[serde(rename = "component", default)]
42 pub component: Option<String>,
43 #[serde(rename = "labelField", default)]
45 pub label_field: String,
46 #[serde(rename = "labelFieldLabel", default)]
48 pub label_field_label: String,
49 #[serde(rename = "valueField", default)]
51 pub value_field: String,
52 #[serde(rename = "mergeKey", default)]
55 pub merge_key: Option<String>,
56 #[serde(rename = "fieldMapping", default)]
58 pub field_mapping: Vec<(String, String)>,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct EffectActionBinding {
67 #[serde(rename = "action", default)]
69 pub action: String,
70 #[serde(rename = "component", default)]
72 pub component: Option<String>,
73 #[serde(rename = "fieldMapping", default)]
75 pub field_mapping: Vec<(String, String)>,
76 #[serde(rename = "transient", default)]
78 pub transient: bool,
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize)]
85pub struct DetailActionDef {
86 #[serde(rename = "action", default)]
88 pub action: String,
89 #[serde(rename = "paramField", default)]
91 pub param_field: String,
92 #[serde(rename = "paramKey", default)]
94 pub param_key: String,
95 #[serde(rename = "previewItemKey", default)]
97 pub preview_item_key: String,
98 #[serde(rename = "previewItemLabel", default)]
100 pub preview_item_label: String,
101 #[serde(rename = "targetField", default)]
103 pub target_field: String,
104 #[serde(rename = "targetMatchKey", default)]
106 pub target_match_key: String,
107}
108
109#[cfg(test)]
110mod tests {
111 use super::{DataActionBinding, EffectActionBinding, FieldAction};
112
113 #[test]
115 fn field_action_uses_discriminated_shape() {
116 let data = serde_json::to_value(FieldAction::Data(DataActionBinding {
117 action: "search_candidates".into(),
118 component: Some("candidate-registry".into()),
119 label_field: "name".into(),
120 label_field_label: "名称".into(),
121 value_field: "target".into(),
122 merge_key: None,
123 field_mapping: vec![("iconRequestJson".into(), "icon_request_json".into())],
124 }))
125 .expect("Data action must serialize");
126 assert_eq!(data["kind"], "data");
127 assert_eq!(data["binding"]["labelField"], "name");
128 assert_eq!(data["binding"]["labelFieldLabel"], "名称");
129 assert_eq!(data["binding"]["valueField"], "target");
130 assert!(data["binding"]["mergeKey"].is_null());
131 assert_eq!(data["binding"]["fieldMapping"][0][0], "iconRequestJson");
132
133 let effect = serde_json::to_value(FieldAction::Effect(EffectActionBinding {
134 action: "apply_override".into(),
135 component: None,
136 field_mapping: vec![("custom_icon_path".into(), "custom_icon_path".into())],
137 transient: true,
138 }))
139 .expect("Effect action must serialize");
140 assert_eq!(effect["kind"], "effect");
141 assert_eq!(effect["binding"]["transient"], true);
142 assert_eq!(effect["binding"]["fieldMapping"][0][1], "custom_icon_path");
143 }
144}