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
350350 });
351351 }, [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
353367 const runGitAction = useCallback(async () => {
354368 if (!api || !gitCwd || !isGitModalOpen) return;
355369 if (!selectedGitModalActionOption || selectedGitModalActionOption.disabled) return;
......@@ -398,12 +412,12 @@ export default function GitActionsControl({ api, gitCwd }: GitActionsControlProp
398412
399413 if (includeGeneratedCommitMessage) {
400414 if (commitRun.commit.status === "created") {
415 if (commitRun.commit.subject) {
416 setGitModalCommitMessage(commitRun.commit.subject);
417 }
401418 updateStep(
402419 "generate",
403420 "completed",
404 commitRun.commit.subject
405 ? `Generated: ${commitRun.commit.subject}`
406 : "Generated commit message.",
407421 );
408422 } else {
409423 updateStep("generate", "skipped", "No local changes to commit.");
......@@ -694,15 +708,20 @@ export default function GitActionsControl({ api, gitCwd }: GitActionsControlProp
694708 const borderClass =
695709 index < gitModalActionOptions.length - 1 ? "border-b border-border/70" : "";
696710 const selected = option.action === gitModalSelectedAction && !option.disabled;
711 const disabled = option.disabled || isGitActionRunning;
697712
698713 return (
699714 <button
700715 key={option.action}
701716 type="button"
702717 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"
704 } disabled:cursor-not-allowed disabled:bg-card/45 disabled:text-muted-foreground/65`}
705 disabled={option.disabled || isGitActionRunning}
718 selected
719 ? "bg-accent/55"
720 : disabled
721 ? "bg-card/25"
722 : "bg-card/45 hover:bg-accent/35"
723 } disabled:cursor-not-allowed`}
724 disabled={disabled}
706725 onClick={() => {
707726 setGitModalSelectedAction(option.action);
708727 }}
......@@ -711,14 +730,20 @@ export default function GitActionsControl({ api, gitCwd }: GitActionsControlProp
711730 <GitActionIcon icon={option.icon} disabled={option.disabled} />
712731 </span>
713732 <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>
715738 {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 >
717742 {option.detail}
718743 </p>
719744 )}
720745 </div>
721 {selected ? (
746 {selected && !disabled ? (
722747 <CheckIcon className="mt-0.5 h-4 w-4 shrink-0 text-foreground" />
723748 ) : null}
724749 </button>
......@@ -731,9 +756,7 @@ export default function GitActionsControl({ api, gitCwd }: GitActionsControlProp
731756 const statusTextClass =
732757 step.status === "failed"
733758 ? "text-rose-500 dark:text-rose-300"
734 : step.status === "completed"
735 ? "text-emerald-600 dark:text-emerald-300"
736 : "text-muted-foreground/70";
759 : "text-muted-foreground/70";
737760
738761 return (
739762 <div
......@@ -783,6 +806,16 @@ export default function GitActionsControl({ api, gitCwd }: GitActionsControlProp
783806 </div>
784807 )}
785808 <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 )}
786819 <button
787820 type="button"
788821 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"