Skip to content

Commit 90f07b6

Browse files
committed
feat(team): show members and pending invites in 'team show' table
The table view rendered only id, name, and default_role; the member list and pending invites were visible only in --format json. Add a members_count row plus MEMBERS and PENDING_INVITES sections (EMAIL/NAME/ROLE/STATUS), omitted when empty.
1 parent 893cce9 commit 90f07b6

4 files changed

Lines changed: 111 additions & 1 deletion

File tree

src/commands/team.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,35 @@ impl Render for TeamDetailView {
266266
Cell::new("default_role"),
267267
opt_cell(&detail.default_role),
268268
]);
269-
write_table(w, &t)
269+
t.add_row(vec![
270+
Cell::new("members_count"),
271+
opt_cell(&detail.members_count),
272+
]);
273+
write_table(w, &t)?;
274+
275+
let member_section = |w: &mut dyn std::io::Write,
276+
title: &str,
277+
users: &[quicknode_sdk::admin::TeamUser]|
278+
-> std::io::Result<()> {
279+
if users.is_empty() {
280+
return Ok(());
281+
}
282+
writeln!(w)?;
283+
writeln!(w, "{} ({})", title, users.len())?;
284+
let mut t = new_table(ctx);
285+
set_header_bold(&mut t, ctx, vec!["EMAIL", "NAME", "ROLE", "STATUS"]);
286+
for u in users {
287+
t.add_row(vec![
288+
Cell::new(&u.email),
289+
opt_cell(&u.full_name),
290+
opt_cell(&u.role),
291+
opt_cell(&u.status),
292+
]);
293+
}
294+
write_table(w, &t)
295+
};
296+
member_section(w, "MEMBERS", &detail.users)?;
297+
member_section(w, "PENDING_INVITES", &detail.pending_invites)
270298
}
271299
}
272300

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
source: tests/table_snapshots.rs
3+
expression: out
4+
---
5+
FIELD VALUE
6+
id 7
7+
name core
8+
default_role viewer
9+
members_count 2
10+
11+
MEMBERS (2)
12+
EMAIL NAME ROLE STATUS
13+
alice@example.com Alice Example admin active
14+
bob@example.comviewer active
15+
16+
PENDING_INVITES (1)
17+
EMAIL NAME ROLE STATUS
18+
carol@example.comviewer pending
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
source: tests/table_snapshots.rs
3+
expression: out
4+
---
5+
FIELD VALUE
6+
id 7
7+
name core
8+
default_role
9+
members_count

tests/table_snapshots.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,61 @@ async fn endpoint_logs_table_includes_error_code() {
204204
insta::assert_snapshot!(out);
205205
}
206206

207+
#[tokio::test]
208+
async fn team_show_lists_members_and_pending_invites() {
209+
let body = serde_json::json!({
210+
"data": {
211+
"id": 7,
212+
"name": "core",
213+
"default_role": "viewer",
214+
"members_count": 2,
215+
"users": [
216+
{
217+
"id": 1,
218+
"full_name": "Alice Example",
219+
"email": "alice@example.com",
220+
"role": "admin",
221+
"status": "active",
222+
"created_at": "2026-01-01T00:00:00Z",
223+
"photo_url": null
224+
},
225+
{
226+
"id": 2,
227+
"full_name": null,
228+
"email": "bob@example.com",
229+
"role": "viewer",
230+
"status": "active",
231+
"created_at": null,
232+
"photo_url": null
233+
}
234+
],
235+
"pending_invites": [
236+
{
237+
"id": 3,
238+
"full_name": null,
239+
"email": "carol@example.com",
240+
"role": "viewer",
241+
"status": "pending",
242+
"created_at": null,
243+
"photo_url": null
244+
}
245+
]
246+
},
247+
"error": null
248+
});
249+
let out = table_stdout("/v0/teams/7", body, &["team", "show", "7"]).await;
250+
insta::assert_snapshot!(out);
251+
}
252+
253+
#[tokio::test]
254+
async fn team_show_without_members_renders_fields_only() {
255+
let body = serde_json::json!({
256+
"data": { "id": 7, "name": "core", "default_role": null }
257+
});
258+
let out = table_stdout("/v0/teams/7", body, &["team", "show", "7"]).await;
259+
insta::assert_snapshot!(out);
260+
}
261+
207262
#[tokio::test]
208263
async fn endpoint_show_minimal_table_omits_security_and_rate_limit_rows() {
209264
let body = serde_json::json!({

0 commit comments

Comments
 (0)