use tauri::{AppHandle, State};
use serde_json::Value;
use crate::AppState;
use crate::core::context::Context;
use crate::core::errors::AppError;
#[tauri::command]
pub async fn run_action(
name: String,
body: Value,
state: State<'_, AppState>,
app_handle: AppHandle,
) -> Result<Value, AppError> {
let route = state.manifest.routes.get(&name)
.ok_or_else(|| AppError::Config(format!("Route '{}' not found in manifest", name)))?;
let mut data_map = serde_json::Map::new();
for connector_name in &route.reads {
if let Some(connector) = state.connector_manager.get(connector_name) {
let connector_data = connector.read().await?;
data_map.insert(connector_name.clone(), connector_data);
} else {
return Err(AppError::Config(format!("Connector '{}' in reads for action '{}' is not defined.", connector_name, name)));
}
}
let initial_context = Context::new(Value::Object(data_map), body, Value::Null);
let final_context = state.action_engine.run(
&route.steps,
initial_context,
&state,
&app_handle
).await?;
if let Some(data_object) = final_context.data.as_object() {
for connector_name in &route.writes {
if let (Some(connector), Some(data_to_write)) = (
state.connector_manager.get(connector_name),
data_object.get(connector_name)
) {
connector.write(data_to_write).await?;
state.socket_manager.notify_on_write(
connector_name,
&state,
&app_handle
).await?;
}
}
}
let mut response_map = serde_json::Map::new();
if let Some(component_to_update) = &route.update {
let render_context = serde_json::json!({
"data": final_context.data,
"user": final_context.user,
"globals": state.manifest.globals,
});
let html = state.renderer.render_component(
&state.asset_loader,
component_to_update,
&render_context
).await?;
response_map.insert("html".to_string(), Value::String(html));
}
Ok(Value::Object(response_map))
}