From 6168676ac0ca64901209e7107c7fa98176306e3b Mon Sep 17 00:00:00 2001 From: Kenneth Date: Tue, 12 May 2026 02:19:08 +0800 Subject: [PATCH] feat: show creation time next to pr title --- Cargo.toml | 1 + .../issues.pull_request.PR_kwDOAgent47.json | 1 + .../issues.pull_request.PR_kwDODesign31.json | 1 + .../issues.pull_request.PR_kwDOInfra19.json | 1 + .../issues.pull_request.PR_kwDONovem84.json | 1 + .../issues.pull_request.PR_kwDONovem85.json | 1 + .../issues.pull_request.PR_kwDOSprint62.json | 1 + src/api/graphql/fetch_pull_request.graphql | 1 + src/api/issues.rs | 36 ++++++++++++------- src/api/mock.rs | 24 +++++++++++++ src/screen/dashboard/pull_request_view.rs | 17 ++++++++- 11 files changed, 72 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c782d62..8803d00 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ edition = "2024" [dependencies] anyhow = "1" +chrono = { version = "0.4.44", features = ["serde"] } futures = "0.3.32" futures-lite = "2.6.1" gpui = { version = "*" } diff --git a/fixtures/github/issues.pull_request.PR_kwDOAgent47.json b/fixtures/github/issues.pull_request.PR_kwDOAgent47.json index 22f10f7..fa21b22 100644 --- a/fixtures/github/issues.pull_request.PR_kwDOAgent47.json +++ b/fixtures/github/issues.pull_request.PR_kwDOAgent47.json @@ -2,6 +2,7 @@ "title": "feat(prompts): split context loading from execution workers", "state": "OPEN", "is_draft": true, + "created_at": "2026-04-30T14:22:00Z", "author": { "login": "leaferiksen", "avatar_url": "https://avatars.githubusercontent.com/u/5151?v=4" diff --git a/fixtures/github/issues.pull_request.PR_kwDODesign31.json b/fixtures/github/issues.pull_request.PR_kwDODesign31.json index c05dc75..44c0d25 100644 --- a/fixtures/github/issues.pull_request.PR_kwDODesign31.json +++ b/fixtures/github/issues.pull_request.PR_kwDODesign31.json @@ -2,6 +2,7 @@ "title": "chore(tokens): tighten dashboard spacing scale", "state": "OPEN", "is_draft": false, + "created_at": "2026-05-02T11:05:00Z", "author": { "login": "mariahops", "avatar_url": "https://avatars.githubusercontent.com/u/6161?v=4" diff --git a/fixtures/github/issues.pull_request.PR_kwDOInfra19.json b/fixtures/github/issues.pull_request.PR_kwDOInfra19.json index 99e0773..9ebcc12 100644 --- a/fixtures/github/issues.pull_request.PR_kwDOInfra19.json +++ b/fixtures/github/issues.pull_request.PR_kwDOInfra19.json @@ -2,6 +2,7 @@ "title": "docs(deploy): document manual failover steps", "state": "CLOSED", "is_draft": false, + "created_at": "2026-04-24T06:40:00Z", "author": { "login": "kennethnym", "avatar_url": "https://avatars.githubusercontent.com/u/4242?v=4" diff --git a/fixtures/github/issues.pull_request.PR_kwDONovem84.json b/fixtures/github/issues.pull_request.PR_kwDONovem84.json index fc213ba..019ad0e 100644 --- a/fixtures/github/issues.pull_request.PR_kwDONovem84.json +++ b/fixtures/github/issues.pull_request.PR_kwDONovem84.json @@ -2,6 +2,7 @@ "title": "feat(dashboard): hydrate issue pane from cached query state", "state": "OPEN", "is_draft": false, + "created_at": "2026-05-01T09:12:00Z", "author": { "login": "kennethnym", "avatar_url": "https://avatars.githubusercontent.com/u/4242?v=4" diff --git a/fixtures/github/issues.pull_request.PR_kwDONovem85.json b/fixtures/github/issues.pull_request.PR_kwDONovem85.json index f492d15..965d5df 100644 --- a/fixtures/github/issues.pull_request.PR_kwDONovem85.json +++ b/fixtures/github/issues.pull_request.PR_kwDONovem85.json @@ -2,6 +2,7 @@ "title": "feat(repo): add cached repository query for titlebar picker", "state": "OPEN", "is_draft": false, + "created_at": "2026-05-03T07:40:00Z", "author": { "login": "kennethnym", "avatar_url": "https://avatars.githubusercontent.com/u/4242?v=4" diff --git a/fixtures/github/issues.pull_request.PR_kwDOSprint62.json b/fixtures/github/issues.pull_request.PR_kwDOSprint62.json index 80d690d..7a2f60e 100644 --- a/fixtures/github/issues.pull_request.PR_kwDOSprint62.json +++ b/fixtures/github/issues.pull_request.PR_kwDOSprint62.json @@ -2,6 +2,7 @@ "title": "feat(calendar): ship release handoff checklist in weekly planner", "state": "MERGED", "is_draft": false, + "created_at": "2026-04-28T10:20:00Z", "author": { "login": "rorycraft", "avatar_url": "https://avatars.githubusercontent.com/u/7171?v=4" diff --git a/src/api/graphql/fetch_pull_request.graphql b/src/api/graphql/fetch_pull_request.graphql index a41f758..5ff81fe 100644 --- a/src/api/graphql/fetch_pull_request.graphql +++ b/src/api/graphql/fetch_pull_request.graphql @@ -6,6 +6,7 @@ query PullRequestQuery($id: ID!) { body state isDraft + createdAt baseRef { name } diff --git a/src/api/issues.rs b/src/api/issues.rs index 1e5d48c..59a85c7 100644 --- a/src/api/issues.rs +++ b/src/api/issues.rs @@ -70,6 +70,7 @@ pub(crate) struct DetailedPullRequest { pub(crate) state: PullRequestState, pub(crate) is_draft: bool, pub(crate) body: String, + pub(crate) created_at: Option>, pub(crate) author: Option, pub(crate) base_branch_name: Option, pub(crate) head_branch_name: Option, @@ -368,18 +369,29 @@ impl query::QueryFn for FetchPullRequest { "missing 'node' field on PullRequestQuery response".into(), )) .and_then(|n| match n { - | PullRequestQueryNode::PullRequest(p) => Ok(DetailedPullRequest { - title: p.title, - state: p.state, - is_draft: p.is_draft, - body: p.body, - author: p.author.map(|it| api::user::Actor { - login: it.login, - avatar_url: it.avatar_url, - }), - base_branch_name: p.base_ref.map(|r| r.name), - head_branch_name: p.head_ref.map(|r| r.name), - }), + | PullRequestQueryNode::PullRequest(p) => { + let created_at = + chrono::DateTime::parse_from_rfc3339(&p.created_at).map_err(|err| { + api::Error::MalformedResponse(format!( + "invalid pull request createdAt {:?}: {err}", + p.created_at + )) + })?; + + Ok(DetailedPullRequest { + title: p.title, + state: p.state, + is_draft: p.is_draft, + body: p.body, + author: p.author.map(|it| api::user::Actor { + login: it.login, + avatar_url: it.avatar_url, + }), + base_branch_name: p.base_ref.map(|r| r.name), + head_branch_name: p.head_ref.map(|r| r.name), + created_at: Some(created_at), + }) + } | _ => Err(api::Error::MalformedResponse( "unexpected node type on PullRequestQuery".into(), )), diff --git a/src/api/mock.rs b/src/api/mock.rs index 5c83d25..7fd2d6e 100644 --- a/src/api/mock.rs +++ b/src/api/mock.rs @@ -151,6 +151,10 @@ mod tests { merged.head_branch_name.as_deref(), Some("feat/release-handoff-checklist") ); + assert_eq!( + merged.created_at, + Some(chrono::DateTime::parse_from_rfc3339("2026-04-28T10:20:00Z").unwrap()) + ); assert!( documented_failover .body @@ -168,12 +172,20 @@ mod tests { documented_failover.head_branch_name.as_deref(), Some("docs/manual-failover-steps") ); + assert_eq!( + documented_failover.created_at, + Some(chrono::DateTime::parse_from_rfc3339("2026-04-24T06:40:00Z").unwrap()) + ); assert!(dashboard_markdown.body.contains("```rust")); assert_eq!(dashboard_markdown.base_branch_name.as_deref(), Some("main")); assert_eq!( dashboard_markdown.head_branch_name.as_deref(), Some("feat/cached-issue-pane") ); + assert_eq!( + dashboard_markdown.created_at, + Some(chrono::DateTime::parse_from_rfc3339("2026-05-01T09:12:00Z").unwrap()) + ); assert_eq!( cached_repo_picker .author @@ -186,6 +198,10 @@ mod tests { cached_repo_picker.head_branch_name.as_deref(), Some("feat/cached-repo-picker") ); + assert_eq!( + cached_repo_picker.created_at, + Some(chrono::DateTime::parse_from_rfc3339("2026-05-03T07:40:00Z").unwrap()) + ); assert_eq!( worker_split.author.as_ref().map(|author| author.login.as_str()), Some("leaferiksen") @@ -195,6 +211,10 @@ mod tests { worker_split.head_branch_name.as_deref(), Some("feat/worker-context-envelope") ); + assert_eq!( + worker_split.created_at, + Some(chrono::DateTime::parse_from_rfc3339("2026-04-30T14:22:00Z").unwrap()) + ); assert_eq!( spacing_tokens .author @@ -207,6 +227,10 @@ mod tests { spacing_tokens.head_branch_name.as_deref(), Some("chore/dashboard-spacing-scale") ); + assert_eq!( + spacing_tokens.created_at, + Some(chrono::DateTime::parse_from_rfc3339("2026-05-02T11:05:00Z").unwrap()) + ); } #[test] diff --git a/src/screen/dashboard/pull_request_view.rs b/src/screen/dashboard/pull_request_view.rs index ea035e8..bc5fd7e 100644 --- a/src/screen/dashboard/pull_request_view.rs +++ b/src/screen/dashboard/pull_request_view.rs @@ -205,7 +205,22 @@ impl PullRequestView { .py_3() .border_b_1() .border_color(theme.colors.border) - .child(text(pr.title.clone()).w_full().text_xl().mb_1()) + .child( + div() + .w_full() + .flex() + .flex_row() + .justify_between() + .items_center() + .child(text(pr.title.clone()).w_full().text_xl().mb_1()) + .when_some(pr.created_at, |it, created_at| { + it.child( + text(created_at.format("%Y-%m-%d %H:%M").to_string()) + .opacity(0.5) + .text_xs(), + ) + }), + ) .child(metadata_line), ) .child(