authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-02-12 14:28:45-08:00
committergravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-02-12 14:28:45-08:00
log5a0f5e9f5e779f27ccfdcee316d06750d697672d
treea5923f3224f49f77ae1dc5761ec36b35c9beccec
parentc643de8ba70beab1f49d9176e8bb745cac807ed5

Improve Git action modal state and PR link handling

- Add an `Open PR` button in the result footer and handle link-open errors - Populate the commit message field with the generated subject when available - Refine disabled/selected action option styling while git actions are running

1 files changed, 45 insertions(+), 12 deletions(-)

apps/web/src/components/GitActionsControl.tsx+45-12
...@@ -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]);
352352
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
398412
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;
697712
698 return (713 return (
699 <button714 <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";
737760
738 return (761 return (
739 <div762 <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 <button819 <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"