update send patch panel
This commit is contained in:
@@ -1,13 +1,14 @@
|
||||
use assets::CustomIconName;
|
||||
use dock::{BasePanel, DockArea, DockPlacement, Panel, PanelEvent, panel_handle};
|
||||
use gpui::prelude::*;
|
||||
use gpui::{
|
||||
AnyElement, App, Context, Entity, EventEmitter, FocusHandle, Focusable, Render, SharedString,
|
||||
Subscription, WeakEntity, Window, div, px,
|
||||
};
|
||||
use gpui_component::button::{Button, ButtonVariants};
|
||||
use gpui_base::{Button as BaseButton, StyledExt};
|
||||
use gpui_component::input::{Input, InputEvent, InputState, Textarea, TextareaState};
|
||||
use gpui_component::{ActiveTheme, Disableable, Icon, IconName, Sizable, h_flex, v_flex};
|
||||
use gpui_component::scroll::ScrollableElement;
|
||||
use gpui_component::spinner::Spinner;
|
||||
use gpui_component::{ActiveTheme, Icon, IconName, Sizable, h_flex, v_flex};
|
||||
use signed_state::RepoStore;
|
||||
|
||||
pub struct SendPatchView {
|
||||
@@ -43,7 +44,7 @@ impl SendPatchView {
|
||||
let description = cx
|
||||
.new(|cx| TextareaState::new(window, cx).placeholder("Describe the change (optional)"));
|
||||
let patch = cx.new(|cx| {
|
||||
TextareaState::new(window, cx).placeholder("Paste `git format-patch` output here...")
|
||||
TextareaState::new(window, cx).placeholder("diff --git a/file.txt b/file.txt\nindex 1234567..abcdefg 100644\n--- a/file.txt\n+++ b/file.txt")
|
||||
});
|
||||
|
||||
// Re-evaluate the Send button's enabled state as the inputs change.
|
||||
@@ -130,44 +131,40 @@ impl SendPatchView {
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
/// Top bar: a short caption and the Send button.
|
||||
fn render_header(&self, cx: &mut Context<Self>) -> AnyElement {
|
||||
fn render_footer(&self, cx: &mut Context<Self>) -> AnyElement {
|
||||
let can_submit = !self.submitting
|
||||
&& !self.subject.read(cx).value().is_empty()
|
||||
&& !self.patch.read(cx).value().is_empty();
|
||||
|
||||
h_flex()
|
||||
.px_4()
|
||||
.h_12()
|
||||
.h_16()
|
||||
.w_full()
|
||||
.gap_2()
|
||||
.items_center()
|
||||
.border_b_1()
|
||||
.border_t_1()
|
||||
.border_color(cx.theme().border)
|
||||
.child(div().flex_1())
|
||||
.child(
|
||||
h_flex()
|
||||
.flex_1()
|
||||
.min_w_0()
|
||||
.gap_2()
|
||||
.items_center()
|
||||
BaseButton::new("send-patch")
|
||||
.h_flex()
|
||||
.h_8()
|
||||
.px_2()
|
||||
.gap_1()
|
||||
.text_sm()
|
||||
.text_color(cx.theme().muted_foreground)
|
||||
.child(Icon::new(IconName::FileText).small().flex_shrink_0())
|
||||
.child(
|
||||
div()
|
||||
.min_w_0()
|
||||
.overflow_hidden()
|
||||
.text_ellipsis()
|
||||
.whitespace_nowrap()
|
||||
.child("Send a patch from `git format-patch` output"),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
Button::new("send-patch")
|
||||
.icon(CustomIconName::CirclePlus)
|
||||
.label("Send patch")
|
||||
.primary()
|
||||
.loading(self.submitting)
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.bg(cx.theme().primary)
|
||||
.text_color(cx.theme().primary_foreground)
|
||||
.hover(|this| this.bg(cx.theme().primary_hover))
|
||||
.active(|this| this.bg(cx.theme().primary_active))
|
||||
.map(|this| {
|
||||
if self.submitting {
|
||||
this.child(Spinner::new().small())
|
||||
} else {
|
||||
this.child(Icon::new(IconName::ArrowUp)).child("Send patch")
|
||||
}
|
||||
})
|
||||
.disabled(!can_submit)
|
||||
.on_click(cx.listener(|this, _event, window, cx| {
|
||||
this.submit(window, cx);
|
||||
@@ -176,22 +173,20 @@ impl SendPatchView {
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// Title and description inputs.
|
||||
fn render_inputs(&self, cx: &mut Context<Self>) -> AnyElement {
|
||||
fn render_inputs(&self, _cx: &mut Context<Self>) -> AnyElement {
|
||||
v_flex()
|
||||
.px_4()
|
||||
.py_2()
|
||||
.w_full()
|
||||
.gap_2()
|
||||
.border_b_1()
|
||||
.border_color(cx.theme().border)
|
||||
.child(Input::new(&self.subject))
|
||||
.child(Textarea::new(&self.description).h(px(64.)))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// The patch textarea, the main content of the panel.
|
||||
fn render_patch(&self, cx: &mut Context<Self>) -> AnyElement {
|
||||
const MSG: &str = "You can paste a git diff or a git format-patch patch series here.";
|
||||
|
||||
v_flex()
|
||||
.px_4()
|
||||
.py_2()
|
||||
@@ -201,14 +196,13 @@ impl SendPatchView {
|
||||
div()
|
||||
.text_xs()
|
||||
.text_color(cx.theme().muted_foreground)
|
||||
.child("Patch — `git format-patch` output"),
|
||||
.child(MSG),
|
||||
)
|
||||
.child(Textarea::new(&self.patch).h(px(240.)))
|
||||
.child(Textarea::new(&self.patch).h_56())
|
||||
.into_any_element()
|
||||
}
|
||||
}
|
||||
|
||||
/// Open the "send patch" panel for `store` in the center dock.
|
||||
pub(super) fn open_send_patch_panel(
|
||||
dock_area: WeakEntity<DockArea>,
|
||||
store: Entity<RepoStore>,
|
||||
@@ -247,19 +241,25 @@ impl Render for SendPatchView {
|
||||
v_flex()
|
||||
.id("send-patch")
|
||||
.size_full()
|
||||
.child(self.render_header(cx))
|
||||
.child(self.render_inputs(cx))
|
||||
.when_some(self.error.clone(), |this, error| {
|
||||
this.child(
|
||||
h_flex()
|
||||
.px_4()
|
||||
.py_1()
|
||||
.w_full()
|
||||
.text_xs()
|
||||
.text_color(cx.theme().danger)
|
||||
.child(error),
|
||||
)
|
||||
})
|
||||
.child(self.render_patch(cx))
|
||||
.child(
|
||||
v_flex()
|
||||
.overflow_y_scrollbar()
|
||||
.flex_1()
|
||||
.w_full()
|
||||
.child(self.render_inputs(cx))
|
||||
.when_some(self.error.clone(), |this, error| {
|
||||
this.child(
|
||||
h_flex()
|
||||
.px_4()
|
||||
.py_1()
|
||||
.w_full()
|
||||
.text_xs()
|
||||
.text_color(cx.theme().danger)
|
||||
.child(error),
|
||||
)
|
||||
})
|
||||
.child(self.render_patch(cx)),
|
||||
)
|
||||
.child(self.render_footer(cx))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
- [ ] GRASP-06 `/prs/<npub>/<id>.git` contributor endpoints + kind-10317 user grasp-list fallback.
|
||||
- [ ] Merge button in the PR detail view (`merge_pull_request` is store-only today), then fetch-and-merge (`merge-commit`) when the push backend is guaranteed.
|
||||
- [ ] Local-checkout generation for the update-PR dialog (currently paste-only).
|
||||
- [ ] Fork-aware compare in the New PR panel: today both branch selectors come from the user-picked local checkout, so a cross-fork PR (GitHub's "compare across forks") requires the fork's branch to exist locally. Add picking the fork repository from announced repos (its 30617 may point at this repo via the `u` tag, or share the EUC) + a branch, fetch it into the `GitCache` mirror, and run the `merge-base`/diff/`format-patch` flow against the base repo's mirror — like `choose_checkout` today but repo-driven.
|
||||
|
||||
## Performance: render path
|
||||
|
||||
|
||||
Reference in New Issue
Block a user