//! Presentation analysis and template listing commands. use std::sync::Arc; use tauri::State; use serde::{Deserialize, Serialize}; use serde_json::Value; use super::types::PipelineInputInfo; use super::PipelineState; /// Analyze presentation data // @connected #[tauri::command] pub async fn analyze_presentation( data: Value, ) -> Result { use zclaw_pipeline::presentation::PresentationAnalyzer; let analyzer = PresentationAnalyzer::new(); let analysis = analyzer.analyze(&data); // Convert analysis to JSON serde_json::to_value(&analysis).map_err(|e| e.to_string()) } /// Pipeline template metadata #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct PipelineTemplateInfo { pub id: String, pub display_name: String, pub description: String, pub category: String, pub industry: String, pub tags: Vec, pub icon: String, pub version: String, pub author: String, pub inputs: Vec, } /// @reserved — no frontend UI yet /// List available pipeline templates from the `_templates/` directory. /// /// Templates are pipeline YAML files that users can browse and instantiate. /// They live in `pipelines/_templates/` and are not directly runnable /// (they serve as blueprints). #[tauri::command] pub async fn pipeline_templates( state: State<'_, Arc>, ) -> Result, String> { let pipelines = state.pipelines.read().await; // Filter pipelines that have `is_template: true` in metadata // or are in the _templates directory let templates: Vec = pipelines.iter() .filter_map(|(_id, pipeline)| { // Check if this pipeline has template metadata let is_template = pipeline.metadata.annotations .as_ref() .and_then(|a| a.get("is_template")) .and_then(|v| v.as_bool()) .unwrap_or(false); if !is_template { return None; } Some(PipelineTemplateInfo { id: pipeline.metadata.name.clone(), display_name: pipeline.metadata.display_name.clone() .unwrap_or_else(|| pipeline.metadata.name.clone()), description: pipeline.metadata.description.clone().unwrap_or_default(), category: pipeline.metadata.category.clone().unwrap_or_default(), industry: pipeline.metadata.industry.clone().unwrap_or_default(), tags: pipeline.metadata.tags.clone(), icon: pipeline.metadata.icon.clone().unwrap_or_else(|| "📦".to_string()), version: pipeline.metadata.version.clone(), author: pipeline.metadata.author.clone().unwrap_or_default(), inputs: pipeline.spec.inputs.iter().map(|input| { PipelineInputInfo { name: input.name.clone(), input_type: match input.input_type { zclaw_pipeline::InputType::String => "string".to_string(), zclaw_pipeline::InputType::Number => "number".to_string(), zclaw_pipeline::InputType::Boolean => "boolean".to_string(), zclaw_pipeline::InputType::Select => "select".to_string(), zclaw_pipeline::InputType::MultiSelect => "multi-select".to_string(), zclaw_pipeline::InputType::File => "file".to_string(), zclaw_pipeline::InputType::Text => "text".to_string(), }, required: input.required, label: input.label.clone().unwrap_or_else(|| input.name.clone()), placeholder: input.placeholder.clone(), default: input.default.clone(), options: input.options.clone(), } }).collect(), }) }) .collect(); tracing::debug!("[pipeline_templates] Found {} templates", templates.len()); Ok(templates) }