From dc4b059934e8be1d33a89c04e42ec89a81fab244 Mon Sep 17 00:00:00 2001 From: Joao Eduardo Luis Date: Sun, 7 May 2023 10:48:46 +0000 Subject: [PATCH] ghd: add PR details offcanvas Signed-off-by: Joao Eduardo Luis --- src-tauri/src/errors.rs | 2 + src-tauri/src/gh.rs | 39 ++- src-tauri/src/gh/gql.rs | 229 ++++++++++++- src-tauri/src/gh/gql/custom_types.rs | 1 + src-tauri/src/gh/gql/queries.graphql | 63 ++++ src-tauri/src/gh/gql/queries.rs | 300 +++++++++++++++++- src-tauri/src/gh/prs.rs | 34 +- src-tauri/src/gh/types.rs | 48 ++- src-tauri/src/main.rs | 25 +- src/app/app.module.ts | 6 + .../pull-request-details.component.html | 80 +++++ .../pull-request-details.component.scss | 0 .../pull-request-details.component.spec.ts | 22 ++ .../pull-request-details.component.ts | 51 +++ .../pull-requests-table.component.html | 6 +- .../pull-requests-table.component.ts | 14 + src/app/shared/services/tauri.service.ts | 6 +- src/app/shared/types.ts | 42 +++ src/styles.scss | 4 + 19 files changed, 951 insertions(+), 21 deletions(-) create mode 100644 src/app/pages/dashboard/pull-request-details/pull-request-details.component.html create mode 100644 src/app/pages/dashboard/pull-request-details/pull-request-details.component.scss create mode 100644 src/app/pages/dashboard/pull-request-details/pull-request-details.component.spec.ts create mode 100644 src/app/pages/dashboard/pull-request-details/pull-request-details.component.ts diff --git a/src-tauri/src/errors.rs b/src-tauri/src/errors.rs index 91319a0..6187a67 100644 --- a/src-tauri/src/errors.rs +++ b/src-tauri/src/errors.rs @@ -23,4 +23,6 @@ pub enum GHDError { UnknownError, NotFoundError, DBVersionInTheFuture, + RepositoryNotFoundError, + PullRequestNotFoundError, } diff --git a/src-tauri/src/gh.rs b/src-tauri/src/gh.rs index 21d7039..d37e1f9 100644 --- a/src-tauri/src/gh.rs +++ b/src-tauri/src/gh.rs @@ -17,7 +17,7 @@ use sqlx::Row; use crate::{db::DB, errors::GHDError}; -use self::types::{GithubUser, PullRequestTableEntry}; +use self::types::{GithubUser, PullRequestInfo, PullRequestTableEntry}; pub mod api; pub mod gql; @@ -470,6 +470,43 @@ impl Github { prs::get_involved_prs(&db, &login).await } + /// Obtain a specific Pull Request's information. + /// + /// # Arguments + /// + /// * `db` - A GHD Database handle. + /// * `prid` - A Pull Request database ID. + /// + pub async fn get_pull_request_info( + self: &Self, + db: &DB, + prid: &i64, + ) -> Result { + let entry = match prs::get_issue_by_id(&db, &prid).await { + Err(err) => return Err(err), + Ok(res) => res, + }; + + let token = match self.get_token(&db).await { + Ok(t) => t.clone(), + Err(err) => return Err(err), + }; + + let res = match gql::get_pull_request_info( + &token, + &entry.repo_owner, + &entry.repo_name, + &entry.number, + ) + .await + { + Ok(r) => r, + Err(err) => return Err(err), + }; + + Ok(res) + } + /// Marks a specified Pull Request as having been viewed. /// /// # Arguments diff --git a/src-tauri/src/gh/gql.rs b/src-tauri/src/gh/gql.rs index 3f883a1..036bb29 100644 --- a/src-tauri/src/gh/gql.rs +++ b/src-tauri/src/gh/gql.rs @@ -18,20 +18,27 @@ mod queries; use graphql_client::GraphQLQuery; use queries::{user_info, UserInfo}; -use crate::errors::GHDError; +use crate::{ + errors::GHDError, + gh::types::{Label, UserReview}, +}; use self::queries::{ + get_pull_request_info::{ + self, GetPullRequestInfoRepositoryPullRequestAuthor, + }, search_issues::{ - self, IssueState, PullRequestReviewDecision, PullRequestState, - SearchIssuesSearchNodes, SearchIssuesSearchNodesOnIssue, - SearchIssuesSearchNodesOnIssueAuthor, + self, IssueState, PullRequestReviewDecision, SearchIssuesSearchNodes, + SearchIssuesSearchNodesOnIssue, SearchIssuesSearchNodesOnIssueAuthor, SearchIssuesSearchNodesOnPullRequest, SearchIssuesSearchNodesOnPullRequestAuthor, UserFragment, }, - SearchIssues, + GetPullRequestInfo, SearchIssues, }; -use super::types::{Issue, PullRequest, UserUpdate}; +use super::types::{ + GithubUser, Issue, Milestone, PullRequest, PullRequestInfo, UserUpdate, +}; #[derive(serde::Deserialize, Debug)] struct GQLResData { @@ -215,6 +222,43 @@ impl GithubGQLRequest { Ok(response_data) } + + /// Obtain a given Pull Request's information. + /// + /// # Arguments + /// + /// * `repo_owner` - String containing the Pull Request's repository owner. + /// * `repo_name` - String containing the Pull Request's repository name. + /// * `pr_number` - The Pull Request's number. + /// + async fn get_pull_request_info( + self: &Self, + repo_owner: &String, + repo_name: &String, + pr_number: &i64, + ) -> Result { + let vars = get_pull_request_info::Variables { + owner: repo_owner.clone(), + repo: repo_name.clone(), + prid: pr_number.clone(), + }; + let response_data: get_pull_request_info::ResponseData = match self + .execute::( + vars, + ) + .await + { + Ok(res) => res, + Err(GHDError::UnknownError) => { + panic!("error: unknown error"); + } + Err(err) => { + return Err(err); + } + }; + + Ok(response_data) + } } /// Obtain all open issues for the provided `login`. This includes Pull @@ -392,10 +436,10 @@ fn get_issue_from_pull_request( repo_name: node.repository.name.clone(), repo_owner: node.repository.owner.login.clone(), state: match &node.state { - PullRequestState::OPEN => String::from("open"), - PullRequestState::CLOSED => String::from("closed"), - PullRequestState::MERGED => String::from("merged"), - PullRequestState::Other(v) => v.clone(), + search_issues::PullRequestState::OPEN => String::from("open"), + search_issues::PullRequestState::CLOSED => String::from("closed"), + search_issues::PullRequestState::MERGED => String::from("merged"), + search_issues::PullRequestState::Other(v) => v.clone(), }, created_at: node.created_at, updated_at: node.updated_at, @@ -405,6 +449,171 @@ fn get_issue_from_pull_request( } } +/// Obtain a given Pull Request's information. +/// +pub async fn get_pull_request_info( + token: &String, + repo_owner: &String, + repo_name: &String, + pr_number: &i64, +) -> Result { + // helper types + type PRInfoAuthor = GetPullRequestInfoRepositoryPullRequestAuthor; + type PRState = get_pull_request_info::PullRequestState; + type PRMilestoneState = get_pull_request_info::MilestoneState; + type ReviewAuthor = get_pull_request_info::GetPullRequestInfoRepositoryPullRequestReviewsNodesAuthor; + type ReviewState = get_pull_request_info::PullRequestReviewState; + + let res = match GithubGQLRequest::new(&token) + .get_pull_request_info(&repo_owner, &repo_name, &pr_number) + .await + { + Ok(v) => v, + Err(err) => return Err(err), + }; + + let repo = match res.repository { + None => return Err(GHDError::RepositoryNotFoundError), + Some(v) => v, + }; + let pr = match repo.pull_request { + None => return Err(GHDError::PullRequestNotFoundError), + Some(v) => v, + }; + + let unknown_user = GithubUser { + id: -1, + login: String::from("unknown"), + name: String::from("unknown"), + avatar_url: String::new(), + }; + + let author: GithubUser = match pr.author { + None => unknown_user.clone(), + Some(v) => match v { + PRInfoAuthor::User(user) => GithubUser { + id: user.database_id.unwrap_or(-1), + login: user.login, + name: user.name.unwrap_or(String::from("unknown")), + avatar_url: user.avatar_url, + }, + _ => unknown_user.clone(), + }, + }; + + let mut labels: Vec