use std::sync::Arc; use crate::{ api, app, component::{ diff_view::{DiffViewContent, DiffViewState, diff_view}, text::text, }, query::{self, QueryStatus, observe_query, read_query, use_query}, }; use gpui::{ParentElement, Styled, div}; pub(crate) struct PullRequestDiffView { selected_file_path: Option>, pr_query: query::Entity, file_tree_query: query::Entity, content_diff_query: Option>, diff_view_state: DiffViewState, diff_view_content: Option, } pub(crate) fn new( pr_id: api::issues::Id, cx: &mut gpui::Context, ) -> PullRequestDiffView { let mut view = PullRequestDiffView { selected_file_path: None, pr_query: use_query(api::issues::FetchPullRequest { id: pr_id.clone() }, cx), file_tree_query: use_query( api::issues::FetchPullRequestFileTree { id: pr_id, first: 100, }, cx, ), content_diff_query: None, diff_view_state: DiffViewState::new(), diff_view_content: None, }; view.on_create(cx); view } impl PullRequestDiffView { fn on_create(&mut self, cx: &mut gpui::Context) { _ = cx .observe(&self.pr_query, |this, _, cx| { this.start_content_queries(cx); }) .detach(); _ = cx .observe(&self.file_tree_query, |this, _, cx| { this.start_content_queries(cx); }) .detach(); // if pr is already loaded, start content queries self.start_content_queries(cx); } fn start_content_queries(&mut self, cx: &mut gpui::Context) { if self.content_diff_query.is_some() { return; } if self.selected_file_path.is_none() && let QueryStatus::Loaded(files) = read_query(&self.file_tree_query, cx) { self.selected_file_path = files.first().map(|file| Arc::clone(&file.path)); } let Some(selected_file_path) = self.selected_file_path.as_deref() else { return; }; let Some((old_file_ref, new_file_ref)) = ({ if let QueryStatus::Loaded(pr) = read_query(&self.pr_query, cx) { Some(( api::repo::FileRef { repo_slug: pr.base_repo_slug.clone(), path: Arc::from(selected_file_path), reff: Some(pr.base_ref.clone()), }, api::repo::FileRef { repo_slug: pr.head_repo_slug.clone(), path: Arc::from(selected_file_path), reff: Some(pr.head_ref.clone()), }, )) } else { None } }) else { return; }; let content_diff_query = use_query( api::repo::FetchFileDiff { base: old_file_ref, head: new_file_ref, }, cx, ); _ = observe_query( &content_diff_query, |this, query, cx| { if let QueryStatus::Loaded(diff) = read_query(query, cx) { println!("diff len {}", diff.len()); this.diff_view_state.reset(diff.len()); this.diff_view_content = Some(Arc::clone(diff).into()); } cx.notify(); }, cx, ) .detach(); self.content_diff_query = Some(content_diff_query); } } impl gpui::Render for PullRequestDiffView { fn render( &mut self, _window: &mut gpui::Window, cx: &mut gpui::Context, ) -> impl gpui::IntoElement { let theme = app::current_theme(cx); let content_diff = self .content_diff_query .as_ref() .map(|q| read_query(q, cx)) .unwrap_or(QueryStatus::Loading); match content_diff { | QueryStatus::Err(_) | QueryStatus::Loading => div() .size_full() .bg(theme.colors.surface) .p_4() .child(text("asd")), | QueryStatus::Loaded(_) => match &self.diff_view_content { | Some(content) => div() .size_full() .child(diff_view(self.diff_view_state.clone(), content.clone())), | None => div(), }, } } }