# cockpit_stats.dspy - compact stat cards for cockpit (cheight:4) dbname = get_module_dbname('pipeline-sdlc') async with DBPools().sqlorContext(dbname) as sor: proj = await sor.sqlExe("SELECT COUNT(*) as active FROM sd_projects WHERE status='active'", {}) active_projects = proj[0].active if proj else 0 iters = await sor.sqlExe("SELECT COUNT(*) as cnt FROM sd_iterations WHERE status='in_progress'", {}) active_iters = iters[0].cnt if iters else 0 bugs = await sor.sqlExe("SELECT COUNT(*) as cnt FROM sd_bugs WHERE status NOT IN ('closed','resolved')", {}) open_bugs = bugs[0].cnt if bugs else 0 reviews = await sor.sqlExe("SELECT COUNT(*) as cnt FROM pipeline_human_tasks WHERE status='pending'", {}) pending_reviews = reviews[0].cnt if reviews else 0 def card(n, label, color, url): return { "widgettype": "HBox", "options": { "css": "card", "cwidth": 23, "cheight": 4, "padding": "8px 14px", "bgcolor": "#fff", "borderRadius": "8px", "border": "1px solid #e2e8f0", "alignItems": "center", "gap": "10px", "cursor": "pointer" }, "binds": [{ "wid": "self", "event": "click", "actiontype": "urlwidget", "target": "app.main_content", "options": {"url": entire_url(url)}, "mode": "replace" }], "subwidgets": [ {"widgettype": "Text", "options": { "text": str(n), "cfontsize": 1.5, "color": color, "fontWeight": "bold" }}, {"widgettype": "Text", "options": { "text": label, "cfontsize": 0.85, "color": "#64748b" }} ] } return { "widgettype": "ResponsableBox", "options": {"gap": "12px", "minWidth": "160px", "width": "100%"}, "subwidgets": [ card(active_projects, "活跃项目", "#3b82f6", "/pipeline-sdlc/sd_projects/"), card(active_iters, "进行中迭代", "#22c55e", "/pipeline-sdlc/sd_iterations/"), card(open_bugs, "待处理Bug", "#f59e0b", "/pipeline-sdlc/sd_bugs/"), card(pending_reviews, "待审批", "#8b5cf6", ""), ] }