新增: DockerNode+CI状态读取+模板CRUD+CIStatus面板
- DockerNode: 环境检测(docker --version)+授权+容器内执行(12个测试) - ci_status.rs: Gitea commit status API 读取(7个测试,失败返回空不阻塞) - CIStatus.vue: CI检查面板(通过/失败/pending 汇总+可点击跳转) - 模板CRUD IPC: list/save/delete templates(内置只读+自定义KV持久化) - TemplateInfo 结构体(IPC传输用) - 零编译警告,vue-tsc+vite build 通过
This commit is contained in:
@@ -141,6 +141,95 @@ pub async fn get_plan_execution() -> Result<bool, String> {
|
||||
Ok(df_ai::plan_executor::plan_execution_enabled())
|
||||
}
|
||||
|
||||
/// 列出可用模板(内置 + 自定义)。
|
||||
///
|
||||
/// 内置模板从 assets/templates/ 加载;自定义模板从 app_settings KV(df-custom-templates)读取。
|
||||
#[tauri::command]
|
||||
pub async fn list_templates(state: State<'_, AppState>) -> Result<Vec<TemplateInfo>, String> {
|
||||
let mut templates = Vec::new();
|
||||
|
||||
// 内置模板
|
||||
let builtin = [
|
||||
("code-review", "代码审查", "AI 驱动的代码审查流程"),
|
||||
("bug-fix", "Bug 修复", "AI 驱动的 bug 修复流程"),
|
||||
("feature-dev", "功能开发", "AI 驱动的功能开发全流程"),
|
||||
];
|
||||
for (id, name, desc) in &builtin {
|
||||
templates.push(TemplateInfo {
|
||||
id: id.to_string(),
|
||||
name: name.to_string(),
|
||||
description: desc.to_string(),
|
||||
builtin: true,
|
||||
yaml: String::new(), // 内置模板不返回全文(前端需要时单独加载)
|
||||
});
|
||||
}
|
||||
|
||||
// 自定义模板
|
||||
if let Ok(Some(custom_json)) = state.settings.get("df-custom-templates").await {
|
||||
if let Ok(custom) = serde_json::from_str::<Vec<TemplateInfo>>(&custom_json) {
|
||||
templates.extend(custom);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(templates)
|
||||
}
|
||||
|
||||
/// 保存自定义模板(新建/覆盖)。
|
||||
#[tauri::command]
|
||||
pub async fn save_template(
|
||||
state: State<'_, AppState>,
|
||||
template: TemplateInfo,
|
||||
) -> Result<(), String> {
|
||||
let mut customs: Vec<TemplateInfo> = state
|
||||
.settings
|
||||
.get("df-custom-templates")
|
||||
.await
|
||||
.map_err(err_str)?
|
||||
.and_then(|s| serde_json::from_str(&s).ok())
|
||||
.unwrap_or_default();
|
||||
|
||||
// 按 id 去重(覆盖同名)
|
||||
customs.retain(|t| t.id != template.id);
|
||||
customs.push(template);
|
||||
|
||||
let json = serde_json::to_string(&customs).map_err(|e| e.to_string())?;
|
||||
state.settings.set("df-custom-templates", &json).await.map_err(err_str)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 删除自定义模板。
|
||||
#[tauri::command]
|
||||
pub async fn delete_template(state: State<'_, AppState>, template_id: String) -> Result<(), String> {
|
||||
let mut customs: Vec<TemplateInfo> = state
|
||||
.settings
|
||||
.get("df-custom-templates")
|
||||
.await
|
||||
.map_err(err_str)?
|
||||
.and_then(|s| serde_json::from_str(&s).ok())
|
||||
.unwrap_or_default();
|
||||
|
||||
let before = customs.len();
|
||||
customs.retain(|t| t.id != template_id);
|
||||
|
||||
if customs.len() < before {
|
||||
let json = serde_json::to_string(&customs).map_err(|e| e.to_string())?;
|
||||
state.settings.set("df-custom-templates", &json).await.map_err(err_str)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 模板信息(IPC 传输用)
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct TemplateInfo {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
/// true = 内置模板(只读);false = 自定义模板
|
||||
pub builtin: bool,
|
||||
/// 自定义模板的 YAML 内容(内置模板为空)
|
||||
pub yaml: String,
|
||||
}
|
||||
|
||||
/// 解决合并冲突(用户/reviewer 选择解决方案后调用)。
|
||||
///
|
||||
/// 更新 ai_conflicts 表的 resolution + resolved_by + resolved_at,
|
||||
|
||||
Reference in New Issue
Block a user