# cockpit_project_tasks.dspy - Return clean task list for current project # Used by cockpit project button to show task tree import json uid = await get_user() if not uid: return json.dumps({"tasks": [], "error": "请先登录"}, ensure_ascii=False) dbname = get_module_dbname('pipeline-sdlc') # Get current project and tasks in one session async with DBPools().sqlorContext(dbname) as sor: recs = await sor.sqlExe( "SELECT current_project_id FROM pipeline_agent_settings WHERE user_id=${uid}$", {"uid": uid}) pid = getattr(recs[0], 'current_project_id', '') if recs else '' if not pid: return json.dumps({"tasks": [], "error": "没有当前项目"}, ensure_ascii=False) # Get project name pname = '' precs = await sor.sqlExe( "SELECT name FROM sd_projects WHERE id=${pid}$", {"pid": pid}) if precs and len(precs) > 0: pname = getattr(precs[0], 'name', '') or '' # Get tasks for this project (tenant_id = project_id for SDLC tasks) tasks = await sor.sqlExe( "SELECT id, title, state, current_version, created_at, params, role " "FROM pipeline_tasks WHERE tenant_id=${pid}$ ORDER BY created_at DESC LIMIT 50", {"pid": pid}) task_list = [] for t in tasks: d = {} # Use to_dict() if available (DictObject), otherwise vars() raw = {} if hasattr(t, 'to_dict') and callable(t.to_dict): try: raw = t.to_dict() except: pass if not raw and hasattr(t, '__dict__'): raw = vars(t) # Extract fields directly for attr in ('id', 'title', 'state', 'current_version', 'created_at', 'role', 'params'): val = getattr(t, attr, '') or '' if attr == 'params' and val: try: p = json.loads(val) if isinstance(val, str) else val d['description'] = p.get('description', '') or p.get('input_text', '') or '' except: d['description'] = '' elif attr == 'created_at': d[attr] = str(val)[:16] if val else '' elif attr == 'current_version': d[attr] = str(val) if val is not None else '1' else: d[attr] = str(val) if val else '' if not d.get('title'): continue task_list.append(d) return json.dumps({ "project_name": pname, "project_id": pid, "tasks": task_list }, ensure_ascii=False)