New commit review flow in project diff view (#25229)
Closes #ISSUE Release Notes: - N/A --------- Co-authored-by: Nate Butler <iamnbutler@gmail.com>
This commit is contained in:
parent
6b9397c380
commit
4871d3c9e7
18 changed files with 982 additions and 480 deletions
244
crates/git_ui/src/commit_modal.rs
Normal file
244
crates/git_ui/src/commit_modal.rs
Normal file
|
@ -0,0 +1,244 @@
|
|||
#![allow(unused, dead_code)]
|
||||
|
||||
use crate::git_panel::{commit_message_editor, GitPanel};
|
||||
use crate::repository_selector::RepositorySelector;
|
||||
use anyhow::Result;
|
||||
use git::Commit;
|
||||
use language::Buffer;
|
||||
use panel::{panel_editor_container, panel_editor_style, panel_filled_button, panel_icon_button};
|
||||
use settings::Settings;
|
||||
use theme::ThemeSettings;
|
||||
use ui::{prelude::*, Tooltip};
|
||||
|
||||
use editor::{Editor, EditorElement, EditorMode, MultiBuffer};
|
||||
use gpui::*;
|
||||
use project::git::Repository;
|
||||
use project::{Fs, Project};
|
||||
use std::sync::Arc;
|
||||
use workspace::dock::{Dock, DockPosition, PanelHandle};
|
||||
use workspace::{ModalView, Workspace};
|
||||
|
||||
pub fn init(cx: &mut App) {
|
||||
cx.observe_new(|workspace: &mut Workspace, window, cx| {
|
||||
let Some(window) = window else {
|
||||
return;
|
||||
};
|
||||
CommitModal::register(workspace, window, cx)
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
pub struct CommitModal {
|
||||
git_panel: Entity<GitPanel>,
|
||||
commit_editor: Entity<Editor>,
|
||||
restore_dock: RestoreDock,
|
||||
}
|
||||
|
||||
impl Focusable for CommitModal {
|
||||
fn focus_handle(&self, cx: &App) -> gpui::FocusHandle {
|
||||
self.commit_editor.focus_handle(cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl EventEmitter<DismissEvent> for CommitModal {}
|
||||
impl ModalView for CommitModal {
|
||||
fn on_before_dismiss(
|
||||
&mut self,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> workspace::DismissDecision {
|
||||
self.git_panel.update(cx, |git_panel, cx| {
|
||||
git_panel.set_modal_open(false, cx);
|
||||
});
|
||||
self.restore_dock.dock.update(cx, |dock, cx| {
|
||||
if let Some(active_index) = self.restore_dock.active_index {
|
||||
dock.activate_panel(active_index, window, cx)
|
||||
}
|
||||
dock.set_open(self.restore_dock.is_open, window, cx)
|
||||
});
|
||||
workspace::DismissDecision::Dismiss(true)
|
||||
}
|
||||
}
|
||||
|
||||
struct RestoreDock {
|
||||
dock: WeakEntity<Dock>,
|
||||
is_open: bool,
|
||||
active_index: Option<usize>,
|
||||
}
|
||||
|
||||
impl CommitModal {
|
||||
pub fn register(workspace: &mut Workspace, _: &mut Window, cx: &mut Context<Workspace>) {
|
||||
workspace.register_action(|workspace, _: &Commit, window, cx| {
|
||||
let Some(git_panel) = workspace.panel::<GitPanel>(cx) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let (can_commit, conflict) = git_panel.update(cx, |git_panel, cx| {
|
||||
let can_commit = git_panel.can_commit();
|
||||
let conflict = git_panel.has_unstaged_conflicts();
|
||||
(can_commit, conflict)
|
||||
});
|
||||
if !can_commit {
|
||||
let message = if conflict {
|
||||
"There are still conflicts. You must stage these before committing."
|
||||
} else {
|
||||
"No changes to commit."
|
||||
};
|
||||
let prompt = window.prompt(PromptLevel::Warning, message, None, &["Ok"], cx);
|
||||
cx.spawn(|_, _| async move {
|
||||
prompt.await.ok();
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
let dock = workspace.dock_at_position(git_panel.position(window, cx));
|
||||
let is_open = dock.read(cx).is_open();
|
||||
let active_index = dock.read(cx).active_panel_index();
|
||||
let dock = dock.downgrade();
|
||||
let restore_dock_position = RestoreDock {
|
||||
dock,
|
||||
is_open,
|
||||
active_index,
|
||||
};
|
||||
workspace.open_panel::<GitPanel>(window, cx);
|
||||
workspace.toggle_modal(window, cx, move |window, cx| {
|
||||
CommitModal::new(git_panel, restore_dock_position, window, cx)
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn new(
|
||||
git_panel: Entity<GitPanel>,
|
||||
restore_dock: RestoreDock,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Self {
|
||||
let panel = git_panel.read(cx);
|
||||
|
||||
let commit_editor = git_panel.update(cx, |git_panel, cx| {
|
||||
git_panel.set_modal_open(true, cx);
|
||||
let buffer = git_panel.commit_message_buffer(cx).clone();
|
||||
let project = git_panel.project.clone();
|
||||
cx.new(|cx| commit_message_editor(buffer, project.clone(), false, window, cx))
|
||||
});
|
||||
|
||||
Self {
|
||||
git_panel,
|
||||
commit_editor,
|
||||
restore_dock,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_commit_editor(
|
||||
&self,
|
||||
name_and_email: Option<(SharedString, SharedString)>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> impl IntoElement {
|
||||
let editor = self.commit_editor.clone();
|
||||
|
||||
let panel_editor_style = panel_editor_style(true, window, cx);
|
||||
|
||||
let settings = ThemeSettings::get_global(cx);
|
||||
let line_height = relative(settings.buffer_line_height.value())
|
||||
.to_pixels(settings.buffer_font_size.into(), window.rem_size());
|
||||
|
||||
v_flex()
|
||||
.justify_between()
|
||||
.relative()
|
||||
.w_full()
|
||||
.h_full()
|
||||
.pt_2()
|
||||
.bg(cx.theme().colors().editor_background)
|
||||
.child(EditorElement::new(&self.commit_editor, panel_editor_style))
|
||||
.child(self.render_footer(window, cx))
|
||||
}
|
||||
|
||||
pub fn render_footer(&self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let (branch, tooltip, title, co_authors) = self.git_panel.update(cx, |git_panel, cx| {
|
||||
let branch = git_panel
|
||||
.active_repository
|
||||
.as_ref()
|
||||
.and_then(|repo| repo.read(cx).branch().map(|b| b.name.clone()))
|
||||
.unwrap_or_else(|| "<no branch>".into());
|
||||
let tooltip = if git_panel.has_staged_changes() {
|
||||
"Commit staged changes"
|
||||
} else {
|
||||
"Commit changes to tracked files"
|
||||
};
|
||||
let title = if git_panel.has_staged_changes() {
|
||||
"Commit"
|
||||
} else {
|
||||
"Commit All"
|
||||
};
|
||||
let co_authors = git_panel.render_co_authors(cx);
|
||||
(branch, tooltip, title, co_authors)
|
||||
});
|
||||
|
||||
let branch_selector = Button::new("branch-selector", branch)
|
||||
.color(Color::Muted)
|
||||
.style(ButtonStyle::Subtle)
|
||||
.icon(IconName::GitBranch)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.size(ButtonSize::Compact)
|
||||
.icon_position(IconPosition::Start)
|
||||
.tooltip(Tooltip::for_action_title(
|
||||
"Switch Branch",
|
||||
&zed_actions::git::Branch,
|
||||
))
|
||||
.on_click(cx.listener(|_, _, window, cx| {
|
||||
window.dispatch_action(zed_actions::git::Branch.boxed_clone(), cx);
|
||||
}))
|
||||
.style(ButtonStyle::Transparent);
|
||||
h_flex()
|
||||
.w_full()
|
||||
.justify_between()
|
||||
.child(branch_selector)
|
||||
.child(
|
||||
h_flex().children(co_authors).child(
|
||||
panel_filled_button(title)
|
||||
.tooltip(Tooltip::for_action_title(tooltip, &git::Commit))
|
||||
.on_click(cx.listener(|this, _, window, cx| {
|
||||
this.commit(&Default::default(), window, cx);
|
||||
})),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fn dismiss(&mut self, _: &menu::Cancel, _: &mut Window, cx: &mut Context<Self>) {
|
||||
cx.emit(DismissEvent);
|
||||
}
|
||||
fn commit(&mut self, _: &git::Commit, window: &mut Window, cx: &mut Context<Self>) {
|
||||
self.git_panel
|
||||
.update(cx, |git_panel, cx| git_panel.commit_changes(window, cx));
|
||||
cx.emit(DismissEvent);
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for CommitModal {
|
||||
fn render(&mut self, window: &mut Window, cx: &mut Context<'_, Self>) -> impl IntoElement {
|
||||
v_flex()
|
||||
.id("commit-modal")
|
||||
.key_context("GitCommit")
|
||||
.elevation_3(cx)
|
||||
.on_action(cx.listener(Self::dismiss))
|
||||
.on_action(cx.listener(Self::commit))
|
||||
.relative()
|
||||
.bg(cx.theme().colors().editor_background)
|
||||
.rounded(px(16.))
|
||||
.border_1()
|
||||
.border_color(cx.theme().colors().border)
|
||||
.py_2()
|
||||
.px_4()
|
||||
.w(px(480.))
|
||||
.min_h(rems(18.))
|
||||
.flex_1()
|
||||
.overflow_hidden()
|
||||
.child(
|
||||
v_flex()
|
||||
.flex_1()
|
||||
.child(self.render_commit_editor(None, window, cx)),
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue