feat: entry templates CRUD backend

This commit is contained in:
Your Name
2026-02-20 15:06:50 +02:00
parent 6e05ddcf89
commit dcfcdaf1b0
3 changed files with 189 additions and 0 deletions

View File

@@ -2361,6 +2361,52 @@ pub fn upsert_timesheet_entry(
}
}
// Entry template commands
#[tauri::command]
pub fn get_entry_templates(state: State<AppState>) -> Result<Vec<serde_json::Value>, String> {
let conn = state.db.lock().map_err(|e| e.to_string())?;
let mut stmt = conn.prepare(
"SELECT id, name, project_id, task_id, description, duration, billable, created_at FROM entry_templates ORDER BY name"
).map_err(|e| e.to_string())?;
let rows = stmt.query_map([], |row| {
Ok(serde_json::json!({
"id": row.get::<_, i64>(0)?,
"name": row.get::<_, String>(1)?,
"project_id": row.get::<_, i64>(2)?,
"task_id": row.get::<_, Option<i64>>(3)?,
"description": row.get::<_, Option<String>>(4)?,
"duration": row.get::<_, i64>(5)?,
"billable": row.get::<_, i64>(6)?,
"created_at": row.get::<_, String>(7)?,
}))
}).map_err(|e| e.to_string())?;
Ok(rows.filter_map(|r| r.ok()).collect())
}
#[tauri::command]
pub fn create_entry_template(state: State<AppState>, template: serde_json::Value) -> Result<i64, String> {
let conn = state.db.lock().map_err(|e| e.to_string())?;
let name = template.get("name").and_then(|v| v.as_str()).unwrap_or("Untitled");
let project_id = template.get("project_id").and_then(|v| v.as_i64()).ok_or("project_id required")?;
let task_id = template.get("task_id").and_then(|v| v.as_i64());
let description = template.get("description").and_then(|v| v.as_str());
let duration = template.get("duration").and_then(|v| v.as_i64()).unwrap_or(0);
let billable = template.get("billable").and_then(|v| v.as_i64()).unwrap_or(1);
conn.execute(
"INSERT INTO entry_templates (name, project_id, task_id, description, duration, billable) VALUES (?1, ?2, ?3, ?4, ?5, ?6)",
params![name, project_id, task_id, description, duration, billable],
).map_err(|e| e.to_string())?;
Ok(conn.last_insert_rowid())
}
#[tauri::command]
pub fn delete_entry_template(state: State<AppState>, id: i64) -> Result<(), String> {
let conn = state.db.lock().map_err(|e| e.to_string())?;
conn.execute("DELETE FROM entry_templates WHERE id = ?1", params![id]).map_err(|e| e.to_string())?;
Ok(())
}
fn format_seconds_as_time(secs: i64) -> String {
let h = secs / 3600;
let m = (secs % 3600) / 60;