Skip to content

Commit 7cf69f6

Browse files
authored
feat: add filters and improved table to team requests (#4)
* feat: add filters and improved table to `team requests` - Add -n flag to limit results (default: 10) - Add --status flag (repeatable) to filter by status - Add --all flag to bypass status filtering - Dynamic column widths based on content length - Status legend printed below the table - Change ended icon to ☑️ Signed-off-by: Nicolò Ciraci <nicolo.ciraci@docplanner.com> * fix: default to all statuses Signed-off-by: Nicolò Ciraci <nicolo.ciraci@docplanner.com> --------- Signed-off-by: Nicolò Ciraci <nicolo.ciraci@docplanner.com>
1 parent 0517f3e commit 7cf69f6

2 files changed

Lines changed: 79 additions & 30 deletions

File tree

team_cli/cli.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,17 @@ def cmd_requests(args):
464464
with with_spinner("Fetching requests..."):
465465
reqs = get_requests_by_email(user["email"], tokens)
466466

467-
print(format_request_table(reqs))
467+
if args.status:
468+
statuses = {s.lower() for s in args.status}
469+
reqs = [r for r in reqs if r.get("status", "").lower() in statuses]
470+
471+
limit = args.n
472+
truncated = len(reqs) > limit
473+
reqs = reqs[:limit]
474+
475+
print(format_request_table(reqs, show_legend=True))
476+
if truncated:
477+
print(f"\n(showing {limit} most recent — use -n to change limit)")
468478

469479

470480
def cmd_status(args):
@@ -843,8 +853,13 @@ def build_parser() -> argparse.ArgumentParser:
843853
help="Max seconds to wait (default: 600)")
844854

845855
# requests
846-
sub.add_parser("requests", help="List my requests",
847-
description="Show all your elevation requests with status, account, role, and timestamps.")
856+
requests_parser = sub.add_parser("requests", help="List my requests",
857+
description="Show your elevation requests with status, account, role, and timestamps.")
858+
requests_parser.add_argument("-n", type=int, default=10, metavar="N",
859+
help="Max number of requests to show (default: 10)")
860+
requests_parser.add_argument("--status", action="append", metavar="STATUS",
861+
help="Filter by status; can be repeated. "
862+
"Allowed: pending, approved, rejected, revoked, cancelled, in progress, scheduled, ended, expired")
848863

849864
# status
850865
status_parser = sub.add_parser("status", help="Check request status",

team_cli/interactive.py

Lines changed: 61 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -182,38 +182,72 @@ def _prompt_justification_and_ticket_basic(account_name: str, prev_j: str | None
182182
return justification, ticket
183183

184184

185-
def format_request_table(requests_list: list[dict]) -> str:
186-
"""Format requests as a readable table."""
185+
_STATUS_LEGEND = [
186+
("⏳", "pending", "Waiting for approver action"),
187+
("📅", "scheduled", "Approved, session not yet started"),
188+
("⏩", "in progress", "Session currently active"),
189+
("✅", "approved", "Approved (session may have started)"),
190+
("☑️", "ended", "Session completed normally"),
191+
("❌", "rejected", "Rejected by approver"),
192+
("🔄", "revoked", "Revoked after approval"),
193+
("🚫", "cancelled", "Cancelled by requester"),
194+
("💤", "expired", "Expired without action"),
195+
]
196+
197+
_STATUS_ICON = {s: icon for icon, s, _ in _STATUS_LEGEND}
198+
199+
200+
def format_request_table(requests_list: list[dict], show_legend: bool = False) -> str:
201+
"""Format requests as a readable table with dynamic column widths."""
187202
if not requests_list:
188203
return "No requests found."
189204

190-
# Status icons
191-
status_icon = {
192-
"pending": "⏳",
193-
"approved": "✅",
194-
"rejected": "❌",
195-
"revoked": "🔄",
196-
"cancelled": "🚫",
197-
"in progress": "⏩",
198-
"scheduled": "📅",
199-
"ended": "⏹",
200-
"expired": "💤",
201-
}
202-
203-
lines = []
204-
lines.append(f"{'ID':<38} {'Account':<22} {'Role':<30} {'Duration':>4}h {'Status':<12} {'Created'}")
205-
lines.append("─" * 130)
206-
205+
rows = []
207206
for r in sorted(requests_list, key=lambda x: x.get("createdAt", ""), reverse=True):
208-
rid = r.get("id", "")[:36]
209-
account = r.get("accountName", "")[:20]
210-
role = r.get("role", "")[:28]
211-
duration = r.get("duration", "")
212207
status = r.get("status", "unknown")
213-
icon = status_icon.get(status.lower(), "?")
214-
created = r.get("createdAt", "")[:19]
215-
216-
lines.append(f"{rid:<38} {account:<22} {role:<30} {str(duration):>4}h {icon} {status:<10} {created}")
208+
rows.append({
209+
"id": r.get("id", "")[:36],
210+
"account": r.get("accountName", ""),
211+
"role": r.get("role", ""),
212+
"duration": str(r.get("duration", "")),
213+
"status": status,
214+
"icon": _STATUS_ICON.get(status.lower(), "?"),
215+
"created": r.get("createdAt", "")[:19],
216+
})
217+
218+
w_id = max(len("ID"), max(len(r["id"]) for r in rows))
219+
w_account = max(len("Account"), max(len(r["account"]) for r in rows))
220+
w_role = max(len("Role"), max(len(r["role"]) for r in rows))
221+
w_duration = max(len("Dur"), max(len(r["duration"]) for r in rows))
222+
w_status = max(len("Status"), max(len(r["status"]) for r in rows))
223+
w_created = len("Created") # always 19 chars
224+
225+
header = (
226+
f"{'ID':<{w_id}} "
227+
f"{'Account':<{w_account}} "
228+
f"{'Role':<{w_role}} "
229+
f"{'Dur':>{w_duration}}h "
230+
f" {'Status':<{w_status}} "
231+
f"{'Created'}"
232+
)
233+
total = len(header)
234+
235+
lines = [header, "─" * total]
236+
for r in rows:
237+
lines.append(
238+
f"{r['id']:<{w_id}} "
239+
f"{r['account']:<{w_account}} "
240+
f"{r['role']:<{w_role}} "
241+
f"{r['duration']:>{w_duration}}h "
242+
f"{r['icon']} {r['status']:<{w_status}} "
243+
f"{r['created']}"
244+
)
245+
246+
if show_legend:
247+
lines.append("")
248+
lines.append("Status legend:")
249+
for icon, name, description in _STATUS_LEGEND:
250+
lines.append(f" {icon} {name:<12} {description}")
217251

218252
return "\n".join(lines)
219253

0 commit comments

Comments
 (0)