| ... | @@ -350,6 +350,20 @@ export default function GitActionsControl({ api, gitCwd }: GitActionsControlProp | ... | @@ -350,6 +350,20 @@ export default function GitActionsControl({ api, gitCwd }: GitActionsControlProp |
| 350 | }); | 350 | }); |
| 351 | }, [api, gitStatus?.openPr?.url]); | 351 | }, [api, gitStatus?.openPr?.url]); |
| 352 | | 352 | |
| | 353 | const openPrFromResult = useCallback(() => { |
| | 354 | if (!api) { |
| | 355 | setGitModalError("Link opening is unavailable."); |
| | 356 | return; |
| | 357 | } |
| | 358 | |
| | 359 | const prUrl = gitModalResult?.pr.url ?? null; |
| | 360 | if (!prUrl) return; |
| | 361 | |
| | 362 | void api.shell.openExternal(prUrl).catch((error) => { |
| | 363 | setGitModalError(error instanceof Error ? error.message : "Unable to open PR link."); |
| | 364 | }); |
| | 365 | }, [api, gitModalResult?.pr.url]); |
| | 366 | |
| 353 | const runGitAction = useCallback(async () => { | 367 | const runGitAction = useCallback(async () => { |
| 354 | if (!api || !gitCwd || !isGitModalOpen) return; | 368 | if (!api || !gitCwd || !isGitModalOpen) return; |
| 355 | if (!selectedGitModalActionOption || selectedGitModalActionOption.disabled) return; | 369 | if (!selectedGitModalActionOption || selectedGitModalActionOption.disabled) return; |
| ... | @@ -398,12 +412,12 @@ export default function GitActionsControl({ api, gitCwd }: GitActionsControlProp | ... | @@ -398,12 +412,12 @@ export default function GitActionsControl({ api, gitCwd }: GitActionsControlProp |
| 398 | | 412 | |
| 399 | if (includeGeneratedCommitMessage) { | 413 | if (includeGeneratedCommitMessage) { |
| 400 | if (commitRun.commit.status === "created") { | 414 | if (commitRun.commit.status === "created") { |
| | 415 | if (commitRun.commit.subject) { |
| | 416 | setGitModalCommitMessage(commitRun.commit.subject); |
| | 417 | } |
| 401 | updateStep( | 418 | updateStep( |
| 402 | "generate", | 419 | "generate", |
| 403 | "completed", | 420 | "completed", |
| 404 | commitRun.commit.subject | | |
| 405 | ? `Generated: ${commitRun.commit.subject}` | | |
| 406 | : "Generated commit message.", | | |
| 407 | ); | 421 | ); |
| 408 | } else { | 422 | } else { |
| 409 | updateStep("generate", "skipped", "No local changes to commit."); | 423 | updateStep("generate", "skipped", "No local changes to commit."); |
| ... | @@ -694,15 +708,20 @@ export default function GitActionsControl({ api, gitCwd }: GitActionsControlProp | ... | @@ -694,15 +708,20 @@ export default function GitActionsControl({ api, gitCwd }: GitActionsControlProp |
| 694 | const borderClass = | 708 | const borderClass = |
| 695 | index < gitModalActionOptions.length - 1 ? "border-b border-border/70" : ""; | 709 | index < gitModalActionOptions.length - 1 ? "border-b border-border/70" : ""; |
| 696 | const selected = option.action === gitModalSelectedAction && !option.disabled; | 710 | const selected = option.action === gitModalSelectedAction && !option.disabled; |
| | 711 | const disabled = option.disabled || isGitActionRunning; |
| 697 | | 712 | |
| 698 | return ( | 713 | return ( |
| 699 | <button | 714 | <button |
| 700 | key={option.action} | 715 | key={option.action} |
| 701 | type="button" | 716 | type="button" |
| 702 | className={`flex w-full items-start gap-3 px-4 py-3 text-left transition-colors duration-150 ${borderClass} ${ | 717 | className={`flex w-full items-start gap-3 px-4 py-3 text-left transition-colors duration-150 ${borderClass} ${ |
| 703 | selected ? "bg-accent/55" : "bg-card/45 hover:bg-accent/35" | 718 | selected |
| 704 | } disabled:cursor-not-allowed disabled:bg-card/45 disabled:text-muted-foreground/65`} | 719 | ? "bg-accent/55" |
| 705 | disabled={option.disabled || isGitActionRunning} | 720 | : disabled |
| | 721 | ? "bg-card/25" |
| | 722 | : "bg-card/45 hover:bg-accent/35" |
| | 723 | } disabled:cursor-not-allowed`} |
| | 724 | disabled={disabled} |
| 706 | onClick={() => { | 725 | onClick={() => { |
| 707 | setGitModalSelectedAction(option.action); | 726 | setGitModalSelectedAction(option.action); |
| 708 | }} | 727 | }} |
| ... | @@ -711,14 +730,20 @@ export default function GitActionsControl({ api, gitCwd }: GitActionsControlProp | ... | @@ -711,14 +730,20 @@ export default function GitActionsControl({ api, gitCwd }: GitActionsControlProp |
| 711 | <GitActionIcon icon={option.icon} disabled={option.disabled} /> | 730 | <GitActionIcon icon={option.icon} disabled={option.disabled} /> |
| 712 | </span> | 731 | </span> |
| 713 | <div className="min-w-0 flex-1"> | 732 | <div className="min-w-0 flex-1"> |
| 714 | <p className="text-sm text-foreground">{option.label}</p> | 733 | <p |
| | 734 | className={`text-sm ${disabled ? "text-muted-foreground/60" : "text-foreground"}`} |
| | 735 | > |
| | 736 | {option.label} |
| | 737 | </p> |
| 715 | {option.detail && ( | 738 | {option.detail && ( |
| 716 | <p className="mt-0.5 text-xs text-muted-foreground/70"> | 739 | <p |
| | 740 | className={`mt-0.5 text-xs ${disabled ? "text-muted-foreground/55" : "text-muted-foreground/70"}`} |
| | 741 | > |
| 717 | {option.detail} | 742 | {option.detail} |
| 718 | </p> | 743 | </p> |
| 719 | )} | 744 | )} |
| 720 | </div> | 745 | </div> |
| 721 | {selected ? ( | 746 | {selected && !disabled ? ( |
| 722 | <CheckIcon className="mt-0.5 h-4 w-4 shrink-0 text-foreground" /> | 747 | <CheckIcon className="mt-0.5 h-4 w-4 shrink-0 text-foreground" /> |
| 723 | ) : null} | 748 | ) : null} |
| 724 | </button> | 749 | </button> |
| ... | @@ -731,9 +756,7 @@ export default function GitActionsControl({ api, gitCwd }: GitActionsControlProp | ... | @@ -731,9 +756,7 @@ export default function GitActionsControl({ api, gitCwd }: GitActionsControlProp |
| 731 | const statusTextClass = | 756 | const statusTextClass = |
| 732 | step.status === "failed" | 757 | step.status === "failed" |
| 733 | ? "text-rose-500 dark:text-rose-300" | 758 | ? "text-rose-500 dark:text-rose-300" |
| 734 | : step.status === "completed" | 759 | : "text-muted-foreground/70"; |
| 735 | ? "text-emerald-600 dark:text-emerald-300" | | |
| 736 | : "text-muted-foreground/70"; | | |
| 737 | | 760 | |
| 738 | return ( | 761 | return ( |
| 739 | <div | 762 | <div |
| ... | @@ -783,6 +806,16 @@ export default function GitActionsControl({ api, gitCwd }: GitActionsControlProp | ... | @@ -783,6 +806,16 @@ export default function GitActionsControl({ api, gitCwd }: GitActionsControlProp |
| 783 | </div> | 806 | </div> |
| 784 | )} | 807 | )} |
| 785 | <div className="mt-6 flex justify-end gap-2"> | 808 | <div className="mt-6 flex justify-end gap-2"> |
| | 809 | {gitModalResult?.pr.url && ( |
| | 810 | <button |
| | 811 | type="button" |
| | 812 | className="rounded-xl border border-border px-4 py-2 text-sm text-foreground transition-colors duration-150 hover:bg-accent disabled:cursor-not-allowed disabled:opacity-60" |
| | 813 | onClick={openPrFromResult} |
| | 814 | disabled={isGitActionRunning} |
| | 815 | > |
| | 816 | Open PR |
| | 817 | </button> |
| | 818 | )} |
| 786 | <button | 819 | <button |
| 787 | type="button" | 820 | type="button" |
| 788 | className="rounded-xl border border-border px-4 py-2 text-sm text-foreground transition-colors duration-150 hover:bg-accent disabled:cursor-not-allowed disabled:opacity-60" | 821 | className="rounded-xl border border-border px-4 py-2 text-sm text-foreground transition-colors duration-150 hover:bg-accent disabled:cursor-not-allowed disabled:opacity-60" |