- replace generic success text with action-specific toast titles/descriptions - include short SHA/branch details for push and commit outcomes - add tests for PR/commit/push summaries and description truncation
Unified · Split
| @@ -4,6 +4,7 @@ import { · 3 unmodified lines | ||
| 4 | 4 | buildMenuItems, |
| 5 | 5 | requiresDefaultBranchConfirmation, |
| 6 | 6 | resolveQuickAction, |
| 7 | + summarizeGitResult, | |
| 7 | 8 | } from "./GitActionsControl.logic"; |
| 8 | 9 | |
| 9 | 10 | function status(overrides: Partial<GitStatusResult> = {}): GitStatusResult { |
| @@ -577,3 +578,93 @@ describe("requiresDefaultBranchConfirmation", () => { · 567 unmodified lines | ||
| 577 | 578 | assert.isFalse(requiresDefaultBranchConfirmation("commit_push", false)); |
| 578 | 579 | }); |
| 579 | 580 | }); |
| 581 | + | |
| 582 | +describe("summarizeGitResult", () => { | |
| 583 | + it("returns commit-focused toast for commit action", () => { | |
| 584 | + const result = summarizeGitResult({ | |
| 585 | + action: "commit", | |
| 586 | + commit: { | |
| 587 | + status: "created", | |
| 588 | + commitSha: "0123456789abcdef", | |
| 589 | + subject: "feat: add optimistic UI for git action button", | |
| 590 | + }, | |
| 591 | + push: { status: "skipped_not_requested" }, | |
| 592 | + pr: { status: "skipped_not_requested" }, | |
| 593 | + }); | |
| 594 | + | |
| 595 | + assert.deepEqual(result, { | |
| 596 | + title: "Committed 0123456", | |
| 597 | + description: "feat: add optimistic UI for git action button", | |
| 598 | + }); | |
| 599 | + }); | |
| 600 | + | |
| 601 | + it("returns push-focused toast for push action", () => { | |
| 602 | + const result = summarizeGitResult({ | |
| 603 | + action: "commit_push", | |
| 604 | + commit: { | |
| 605 | + status: "created", | |
| 606 | + commitSha: "abcdef0123456789", | |
| 607 | + subject: "fix: tighten quick action tooltip hover handling", | |
| 608 | + }, | |
| 609 | + push: { | |
| 610 | + status: "pushed", | |
| 611 | + branch: "foo", | |
| 612 | + upstreamBranch: "origin/foo", | |
| 613 | + }, | |
| 614 | + pr: { status: "skipped_not_requested" }, | |
| 615 | + }); | |
| 616 | + | |
| 617 | + assert.deepEqual(result, { | |
| 618 | + title: "Pushed abcdef0 to foo", | |
| 619 | + description: "fix: tighten quick action tooltip hover handling", | |
| 620 | + }); | |
| 621 | + }); | |
| 622 | + | |
| 623 | + it("returns PR-focused toast for created PR action", () => { | |
| 624 | + const result = summarizeGitResult({ | |
| 625 | + action: "commit_push_pr", | |
| 626 | + commit: { | |
| 627 | + status: "created", | |
| 628 | + commitSha: "89abcdef01234567", | |
| 629 | + subject: "feat: ship github shortcuts", | |
| 630 | + }, | |
| 631 | + push: { | |
| 632 | + status: "pushed", | |
| 633 | + branch: "foo", | |
| 634 | + }, | |
| 635 | + pr: { | |
| 636 | + status: "created", | |
| 637 | + number: 42, | |
| 638 | + title: "feat: ship github shortcuts and improve PR CTA in success toast", | |
| 639 | + }, | |
| 640 | + }); | |
| 641 | + | |
| 642 | + assert.deepEqual(result, { | |
| 643 | + title: "Created PR #42", | |
| 644 | + description: "feat: ship github shortcuts and improve PR CTA in success toast", | |
| 645 | + }); | |
| 646 | + }); | |
| 647 | + | |
| 648 | + it("truncates long description text", () => { | |
| 649 | + const result = summarizeGitResult({ | |
| 650 | + action: "commit_push_pr", | |
| 651 | + commit: { | |
| 652 | + status: "created", | |
| 653 | + commitSha: "89abcdef01234567", | |
| 654 | + subject: "short subject", | |
| 655 | + }, | |
| 656 | + push: { status: "pushed", branch: "foo" }, | |
| 657 | + pr: { | |
| 658 | + status: "created", | |
| 659 | + number: 99, | |
| 660 | + title: | |
| 661 | + "feat: this title is intentionally extremely long so we can validate that toast descriptions are truncated with an ellipsis suffix", | |
| 662 | + }, | |
| 663 | + }); | |
| 664 | + | |
| 665 | + assert.deepEqual(result, { | |
| 666 | + title: "Created PR #99", | |
| 667 | + description: "feat: this title is intentionally extremely long so we can validate t...", | |
| 668 | + }); | |
| 669 | + }); | |
| 670 | +}); | |
| @@ -21,28 +21,51 @@ export interface GitQuickAction { · 20 unmodified lines | ||
| 21 | 21 | hint?: string; |
| 22 | 22 | } |
| 23 | 23 | |
| 24 | −export function describeGitResult(result: GitRunStackedActionResult): string { | |
| 25 | − const parts: string[] = []; | |
| 24 | +const SHORT_SHA_LENGTH = 7; | |
| 25 | +const TOAST_DESCRIPTION_MAX = 72; | |
| 26 | 26 | |
| 27 | − if (result.commit.status === "created") { | |
| 28 | − parts.push(result.commit.subject ?? "Committed changes"); | |
| 27 | +function shortenSha(sha: string | undefined): string | null { | |
| 28 | + if (!sha) return null; | |
| 29 | + return sha.slice(0, SHORT_SHA_LENGTH); | |
| 30 | +} | |
| 31 | + | |
| 32 | +function truncateText(value: string | undefined, maxLength = TOAST_DESCRIPTION_MAX): string | undefined { | |
| 33 | + if (!value) return undefined; | |
| 34 | + if (value.length <= maxLength) return value; | |
| 35 | + if (maxLength <= 3) return "...".slice(0, maxLength); | |
| 36 | + return `${value.slice(0, Math.max(0, maxLength - 3)).trimEnd()}...`; | |
| 37 | +} | |
| 38 | + | |
| 39 | +export function summarizeGitResult( | |
| 40 | + result: GitRunStackedActionResult, | |
| 41 | +): { title: string; description?: string } { | |
| 42 | + const withDescription = (title: string, description: string | undefined) => | |
| 43 | + description ? { title, description } : { title }; | |
| 44 | + | |
| 45 | + if (result.pr.status === "created" || result.pr.status === "opened_existing") { | |
| 46 | + const prNumber = result.pr.number ? ` #${result.pr.number}` : ""; | |
| 47 | + const title = `${result.pr.status === "created" ? "Created PR" : "Opened PR"}${prNumber}`; | |
| 48 | + return withDescription(title, truncateText(result.pr.title)); | |
| 29 | 49 | } |
| 30 | 50 | |
| 31 | 51 | if (result.push.status === "pushed") { |
| 32 | − parts.push( | |
| 33 | − result.push.upstreamBranch | |
| 34 | − ? `Pushed to ${result.push.upstreamBranch}` | |
| 35 | − : "Pushed", | |
| 52 | + const shortSha = shortenSha(result.commit.commitSha); | |
| 53 | + const branch = result.push.branch ?? result.push.upstreamBranch; | |
| 54 | + const pushedCommitPart = shortSha ? ` ${shortSha}` : ""; | |
| 55 | + const branchPart = branch ? ` to ${branch}` : ""; | |
| 56 | + return withDescription( | |
| 57 | + `Pushed${pushedCommitPart}${branchPart}`, | |
| 58 | + truncateText(result.commit.subject), | |
| 36 | 59 | ); |
| 37 | 60 | } |
| 38 | 61 | |
| 39 | − if (result.pr.status === "created") { | |
| 40 | − parts.push(result.pr.number ? `Created PR #${result.pr.number}` : "Created PR"); | |
| 41 | − } else if (result.pr.status === "opened_existing") { | |
| 42 | − parts.push(result.pr.number ? `PR #${result.pr.number}` : "Opened existing PR"); | |
| 62 | + if (result.commit.status === "created") { | |
| 63 | + const shortSha = shortenSha(result.commit.commitSha); | |
| 64 | + const title = shortSha ? `Committed ${shortSha}` : "Committed changes"; | |
| 65 | + return withDescription(title, truncateText(result.commit.subject)); | |
| 43 | 66 | } |
| 44 | 67 | |
| 45 | − return parts.join(" · ") || "No changes needed."; | |
| 68 | + return { title: "Done" }; | |
| 46 | 69 | } |
| 47 | 70 | |
| 48 | 71 | export function buildMenuItems( |
| @@ -13,9 +13,9 @@ import { · 12 unmodified lines | ||
| 13 | 13 | type GitActionMenuItem, |
| 14 | 14 | type GitDialogAction, |
| 15 | 15 | type GitQuickAction, |
| 16 | − describeGitResult, | |
| 17 | 16 | requiresDefaultBranchConfirmation, |
| 18 | 17 | resolveQuickAction, |
| 18 | + summarizeGitResult, | |
| 19 | 19 | } from "./GitActionsControl.logic"; |
| 20 | 20 | import { Badge } from "~/components/ui/badge"; |
| 21 | 21 | import { Button } from "~/components/ui/button"; |
| @@ -282,6 +282,7 @@ export default function GitActionsControl({ api, gitCwd }: GitActionsControlProp · 260 unmodified lines | ||
| 282 | 282 | try { |
| 283 | 283 | const result = await promise; |
| 284 | 284 | stopProgressUpdates(); |
| 285 | + const resultToast = summarizeGitResult(result); | |
| 285 | 286 | |
| 286 | 287 | const prUrl = result.pr.url ?? gitStatus?.openPr?.url; |
| 287 | 288 | const shouldOfferPushCta = action === "commit" && result.commit.status === "created"; |
| @@ -292,8 +293,8 @@ export default function GitActionsControl({ api, gitCwd }: GitActionsControlProp · 4 unmodified lines | ||
| 292 | 293 | |
| 293 | 294 | toastManager.update(progressToastId, { |
| 294 | 295 | type: "success", |
| 295 | − title: "Done", | |
| 296 | − description: describeGitResult(result), | |
| 296 | + title: resultToast.title, | |
| 297 | + description: resultToast.description, | |
| 297 | 298 | timeout: 10_000, |
| 298 | 299 | ...(shouldOfferPushCta |
| 299 | 300 | ? { |