feat: notifications system, webhook retry, issue assign endpoint, CLI milestones/notifications/overdue commands
This commit is contained in:
70
cli.py
70
cli.py
@@ -145,6 +145,54 @@ def cmd_stats(args):
|
||||
print(f" {t}: {c}")
|
||||
|
||||
|
||||
|
||||
|
||||
def cmd_milestones(args):
|
||||
params = f"?project_id={args.project}" if args.project else ""
|
||||
milestones = _request("GET", f"/milestones{params}")
|
||||
if not milestones:
|
||||
print(" No milestones found.")
|
||||
return
|
||||
for m in milestones:
|
||||
status_icon = "🟢" if m["status"] == "open" else "⚫"
|
||||
due = f" (due: {m['due_date'][:10]})" if m.get("due_date") else ""
|
||||
print(f" {status_icon} #{m['id']} {m['title']}{due}")
|
||||
|
||||
|
||||
def cmd_milestone_progress(args):
|
||||
result = _request("GET", f"/milestones/{args.milestone_id}/progress")
|
||||
bar_len = 20
|
||||
filled = int(bar_len * result["progress_pct"] / 100)
|
||||
bar = "█" * filled + "░" * (bar_len - filled)
|
||||
print(f" {result['title']}")
|
||||
print(f" [{bar}] {result['progress_pct']}% ({result['completed']}/{result['total_issues']})")
|
||||
|
||||
|
||||
def cmd_notifications(args):
|
||||
params = [f"user_id={args.user}"]
|
||||
if args.unread:
|
||||
params.append("unread_only=true")
|
||||
qs = "&".join(params)
|
||||
notifs = _request("GET", f"/notifications?{qs}")
|
||||
if not notifs:
|
||||
print(" No notifications.")
|
||||
return
|
||||
for n in notifs:
|
||||
icon = "🔴" if not n["is_read"] else "⚪"
|
||||
print(f" {icon} [{n['type']}] {n['title']}")
|
||||
|
||||
|
||||
def cmd_overdue(args):
|
||||
params = f"?project_id={args.project}" if args.project else ""
|
||||
issues = _request("GET", f"/issues/overdue{params}")
|
||||
if not issues:
|
||||
print(" No overdue issues! 🎉")
|
||||
return
|
||||
for i in issues:
|
||||
due = i.get("due_date", "?")[:10] if i.get("due_date") else "?"
|
||||
print(f" ⏰ #{i['id']} [{i['priority']}] {i['title']} (due: {due})")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="HarborForge CLI")
|
||||
sub = parser.add_subparsers(dest="command")
|
||||
@@ -201,6 +249,24 @@ def main():
|
||||
p_stats = sub.add_parser("stats", help="Dashboard stats")
|
||||
p_stats.add_argument("--project", "-p", type=int)
|
||||
|
||||
|
||||
# milestones
|
||||
p_ms = sub.add_parser("milestones", help="List milestones")
|
||||
p_ms.add_argument("--project", "-p", type=int)
|
||||
|
||||
# milestone progress
|
||||
p_msp = sub.add_parser("milestone-progress", help="Show milestone progress")
|
||||
p_msp.add_argument("milestone_id", type=int)
|
||||
|
||||
# notifications
|
||||
p_notif = sub.add_parser("notifications", help="List notifications")
|
||||
p_notif.add_argument("--user", "-u", type=int, required=True)
|
||||
p_notif.add_argument("--unread", action="store_true")
|
||||
|
||||
# overdue
|
||||
p_overdue = sub.add_parser("overdue", help="List overdue issues")
|
||||
p_overdue.add_argument("--project", "-p", type=int)
|
||||
|
||||
args = parser.parse_args()
|
||||
if not args.command:
|
||||
parser.print_help()
|
||||
@@ -217,6 +283,10 @@ def main():
|
||||
"search": cmd_search,
|
||||
"transition": cmd_transition,
|
||||
"stats": cmd_stats,
|
||||
"milestones": cmd_milestones,
|
||||
"milestone-progress": cmd_milestone_progress,
|
||||
"notifications": cmd_notifications,
|
||||
"overdue": cmd_overdue,
|
||||
}
|
||||
cmds[args.command](args)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user