From 7104a12fcff4703d1b7275f8edcdadef29a61594 Mon Sep 17 00:00:00 2001 From: Edward Shao <92406694+exzshao@users.noreply.github.com> Date: Tue, 28 Apr 2026 12:13:36 -0400 Subject: [PATCH] [APP-4261] Add tooltips to disabled git operation buttons (#9234) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Adds contextual tooltips to disabled git operation buttons so users understand why they can't click them. Tooltips are intentionally limited to **disabled states only** — enabled buttons don't get tooltips since their labels are self-explanatory. **Changes:** - Code review header: "No changes to commit" on the disabled Commit button; "No git actions available" on the disabled chevron - Commit dialog: "Enter a commit message" on the disabled Confirm button (only shown once file changes have loaded — silent during the async load window) - Bug fix: the PR #N button in the header was staying greyed out after transitioning from a disabled Commit mode, because `ViewPr` mode never called `set_disabled(false)` Linear: https://linear.app/warpdotdev/issue/APP-4261/git-buttons-should-all-have-tooltips Warp conversation: https://staging.warp.dev/conversation/27f5811f-22ea-4c4b-8d8f-47ff48a5b12b Loom: https://www.loom.com/share/932cfb22039c4566bcc7a7343b624d81 ## Testing Manually verified: - Commit button with no changes shows "No changes to commit" on hover - Chevron with no changes shows "No git actions available" on hover - Commit dialog Confirm button shows "Enter a commit message" once files load but message is empty; no tooltip shown during async load - PR #N button is no longer greyed out after committing all changes No new automated tests added — these are tooltip strings on existing button state logic that is already exercised by existing tests. ## Server API dependencies N/A — client-only change. ## Agent Mode - [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode ## Changelog Entries for Stable CHANGELOG-IMPROVEMENT: Git operation buttons now show tooltips explaining why they're disabled (e.g. "No changes to commit", "Enter a commit message"). Co-Authored-By: Oz --------- Co-authored-by: Oz --- app/src/code_review/code_review_view.rs | 9 ++++++--- app/src/code_review/git_dialog/commit.rs | 10 ++++++++++ app/src/code_review/git_dialog/mod.rs | 12 ++++++++---- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/app/src/code_review/code_review_view.rs b/app/src/code_review/code_review_view.rs index 70a035c9..93e4e193 100644 --- a/app/src/code_review/code_review_view.rs +++ b/app/src/code_review/code_review_view.rs @@ -6798,11 +6798,12 @@ impl CodeReviewView { match mode { PrimaryGitActionMode::Commit => { - let has_changes = self.has_uncommitted_changes(ctx); + let disabled = !self.has_uncommitted_changes(ctx); self.git_primary_action_button.update(ctx, |button, ctx| { button.set_label("Commit", ctx); button.set_icon(Some(Icon::GitCommit), ctx); - button.set_disabled(!has_changes, ctx); + button.set_disabled(disabled, ctx); + button.set_tooltip(disabled.then_some("No changes to commit"), ctx); button.set_on_click( |ctx| ctx.dispatch_typed_action(CodeReviewAction::OpenCommitDialog), ctx, @@ -6810,7 +6811,8 @@ impl CodeReviewView { button.set_adjoined_side(AdjoinedSide::Right, ctx); }); self.git_operations_chevron.update(ctx, |button, ctx| { - button.set_disabled(!has_changes, ctx); + button.set_disabled(disabled, ctx); + button.set_tooltip(disabled.then_some("No git actions available"), ctx); }); } PrimaryGitActionMode::Push => { @@ -6849,6 +6851,7 @@ impl CodeReviewView { self.git_primary_action_button.update(ctx, |button, ctx| { button.set_label(label, ctx); button.set_icon(Some(Icon::Github), ctx); + button.set_disabled(false, ctx); button.set_on_click( move |ctx| { ctx.dispatch_typed_action(CodeReviewAction::ViewPr(url.clone())) diff --git a/app/src/code_review/git_dialog/commit.rs b/app/src/code_review/git_dialog/commit.rs index b7592f53..7e0587b0 100644 --- a/app/src/code_review/git_dialog/commit.rs +++ b/app/src/code_review/git_dialog/commit.rs @@ -241,6 +241,16 @@ pub(super) fn is_ready_to_confirm(state: &CommitState, app: &AppContext) -> bool !state.file_changes.is_empty() && commit_message(state, app).is_some() } +/// Returns a tooltip to show on the disabled Confirm button when the +/// user needs to take action, or `None` when no tooltip is needed. +pub(super) fn confirm_tooltip(state: &CommitState, app: &AppContext) -> Option<&'static str> { + if !state.file_changes.is_empty() && commit_message(state, app).is_none() { + Some("Enter a commit message") + } else { + None + } +} + /// Kicks off an open-time AI commit-message generation. On success, writes /// the result into the message editor (unless the user has already typed /// something). On failure, silently swaps the placeholder to the manual diff --git a/app/src/code_review/git_dialog/mod.rs b/app/src/code_review/git_dialog/mod.rs index 5ebe1a91..fbf41506 100644 --- a/app/src/code_review/git_dialog/mod.rs +++ b/app/src/code_review/git_dialog/mod.rs @@ -644,13 +644,17 @@ impl GitDialog { if self.loading { return; } - let disabled = match &self.mode { - GitDialogMode::Commit(state) => !commit::is_ready_to_confirm(state, ctx), - GitDialogMode::Push(_) => false, - GitDialogMode::CreatePr(state) => !pr::is_ready_to_confirm(state), + let (disabled, tooltip) = match &self.mode { + GitDialogMode::Commit(state) => ( + !commit::is_ready_to_confirm(state, ctx), + commit::confirm_tooltip(state, ctx), + ), + GitDialogMode::Push(_) => (false, None), + GitDialogMode::CreatePr(state) => (!pr::is_ready_to_confirm(state), None), }; self.confirm_button.update(ctx, |b, ctx| { b.set_disabled(disabled, ctx); + b.set_tooltip(tooltip, ctx); }); }