authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-02-11 18:02:32-08:00
committergravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-02-11 18:02:32-08:00
log3697765f4d3402a760a03d0538eac4335daaca8c
tree687cafcc5f89610696e7d180534ac6d652583c94
parent533dbdfbdacc82edf06cbe8bf0ff12d4c04edfd4

Disable git actions without changes


1 files changed, 84 insertions(+), 14 deletions(-)

apps/web/src/components/ChatView.tsx+84-14
...@@ -57,14 +57,12 @@ function editorLabel(editor: (typeof EDITORS)[number]): string {...@@ -57,14 +57,12 @@ function editorLabel(editor: (typeof EDITORS)[number]): string {
5757
58const LAST_EDITOR_KEY = "t3code:last-editor";58const LAST_EDITOR_KEY = "t3code:last-editor";
59const MAX_VISIBLE_WORK_LOG_ENTRIES = 6;59const MAX_VISIBLE_WORK_LOG_ENTRIES = 6;
60const GIT_ACTION_ITEMS: Array<{60
61interface GitActionMenuItem {
61 id: GitStackedAction;62 id: GitStackedAction;
62 label: string;63 label: string;
63}> = [64 disabled: boolean;
64 { id: "commit", label: "Commit" },65}
65 { id: "commit_push", label: "Commit & Push" },
66 { id: "commit_push_pr", label: "Commit, Push & Create PR" },
67];
6866
69function workToneClass(tone: "thinking" | "tool" | "info" | "error"): string {67function workToneClass(tone: "thinking" | "tool" | "info" | "error"): string {
70 if (tone === "error") return "text-rose-300/50 dark:text-rose-300/50";68 if (tone === "error") return "text-rose-300/50 dark:text-rose-300/50";
...@@ -299,9 +297,74 @@ export default function ChatView() {...@@ -299,9 +297,74 @@ export default function ChatView() {
299 sandboxMode: "workspace-write",297 sandboxMode: "workspace-write",
300 } as const);298 } as const);
301 const gitCwd = activeThread?.worktreePath ?? activeProject?.cwd ?? null;299 const gitCwd = activeThread?.worktreePath ?? activeProject?.cwd ?? null;
302 const gitActionsDisabled =300 const gitBaseDisabled =
303 !api || !gitCwd || !gitStatus || isGitActionRunning;301 !api || !gitCwd || !gitStatus || isGitActionRunning;
304 const pushActionDisabled = gitActionsDisabled || gitStatus.branch === null;302 const gitActionMenuItems = useMemo<GitActionMenuItem[]>(() => {
303 if (!gitStatus) return [];
304
305 const hasBranch = gitStatus.branch !== null;
306 const canCommit = !gitBaseDisabled && gitStatus.hasWorkingTreeChanges;
307 const canPushOrPr = !gitBaseDisabled && hasBranch;
308
309 if (!hasBranch) {
310 return [
311 {
312 id: "commit",
313 label: "Commit",
314 disabled: !canCommit,
315 },
316 ];
317 }
318
319 if (gitStatus.hasWorkingTreeChanges) {
320 return [
321 {
322 id: "commit",
323 label: "Commit",
324 disabled: !canCommit,
325 },
326 {
327 id: "commit_push",
328 label: "Commit & Push",
329 disabled: !canPushOrPr,
330 },
331 {
332 id: "commit_push_pr",
333 label: "Commit, Push & Create PR",
334 disabled: !canPushOrPr,
335 },
336 ];
337 }
338
339 if (gitStatus.aheadCount > 0) {
340 return [
341 {
342 id: "commit",
343 label: "Commit",
344 disabled: true,
345 },
346 {
347 id: "commit_push",
348 label: "Commit & Push",
349 disabled: !canPushOrPr,
350 },
351 {
352 id: "commit_push_pr",
353 label: "Commit, Push & Create PR",
354 disabled: !canPushOrPr,
355 },
356 ];
357 }
358
359 const openPrDisabled = !canPushOrPr || gitStatus.behindCount > 0;
360 return [
361 {
362 id: "commit_push_pr",
363 label: "Open PR",
364 disabled: openPrDisabled,
365 },
366 ];
367 }, [gitBaseDisabled, gitStatus]);
305368
306 useEffect(() => {369 useEffect(() => {
307 latestGitCwdRef.current = gitCwd;370 latestGitCwdRef.current = gitCwd;
...@@ -809,15 +872,13 @@ export default function ChatView() {...@@ -809,15 +872,13 @@ export default function ChatView() {
809 <p className="px-2 pb-1 text-[10px] uppercase tracking-[0.1em] text-muted-foreground/60">872 <p className="px-2 pb-1 text-[10px] uppercase tracking-[0.1em] text-muted-foreground/60">
810 Git actions873 Git actions
811 </p>874 </p>
812 {GIT_ACTION_ITEMS.map((item) => {875 {gitActionMenuItems.map((item) => {
813 const disabled =
814 item.id === "commit" ? gitActionsDisabled : pushActionDisabled;
815 return (876 return (
816 <button877 <button
817 key={item.id}878 key={item.id}
818 type="button"879 type="button"
819 className="mb-1 flex w-full items-center rounded-lg px-2 py-2 text-left text-[11px] text-foreground transition-colors duration-150 hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50"880 className="mb-1 flex w-full items-center rounded-lg px-2 py-2 text-left text-[11px] text-foreground transition-colors duration-150 hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50"
820 disabled={disabled}881 disabled={item.disabled}
821 onClick={() => {882 onClick={() => {
822 void runGitAction(item.id);883 void runGitAction(item.id);
823 }}884 }}
...@@ -831,6 +892,15 @@ export default function ChatView() {...@@ -831,6 +892,15 @@ export default function ChatView() {
831 Detached HEAD: push and PR actions are unavailable.892 Detached HEAD: push and PR actions are unavailable.
832 </p>893 </p>
833 )}894 )}
895 {gitStatus &&
896 gitStatus.branch !== null &&
897 !gitStatus.hasWorkingTreeChanges &&
898 gitStatus.aheadCount === 0 &&
899 gitStatus.behindCount > 0 && (
900 <p className="px-2 pt-1 text-[10px] text-amber-500 dark:text-amber-300">
901 Branch is behind upstream. Pull/rebase before opening a PR.
902 </p>
903 )}
834 </div>904 </div>
835 )}905 )}
836 </div>906 </div>
...@@ -858,13 +928,13 @@ export default function ChatView() {...@@ -858,13 +928,13 @@ export default function ChatView() {
858 )}928 )}
859929
860 {gitActionError && (930 {gitActionError && (
861 <div className="mx-4 mt-3 rounded-lg border border-rose-400/20 bg-rose-900/20 px-3 py-2 text-xs text-rose-200">931 <div className="mx-4 mt-3 rounded-lg border border-rose-200 bg-rose-50 px-3 py-2 text-xs text-rose-800 dark:border-rose-400/20 dark:bg-rose-900/20 dark:text-rose-200">
862 {gitActionError}932 {gitActionError}
863 </div>933 </div>
864 )}934 )}
865935
866 {gitActionNotice && (936 {gitActionNotice && (
867 <div className="mx-4 mt-3 rounded-lg border border-emerald-400/20 bg-emerald-500/[0.08] px-3 py-2 text-xs text-emerald-100">937 <div className="mx-4 mt-3 rounded-lg border border-emerald-200 bg-emerald-50 px-3 py-2 text-xs text-emerald-800 dark:border-emerald-400/20 dark:bg-emerald-500/[0.08] dark:text-emerald-100">
868 {gitActionNotice}938 {gitActionNotice}
869 </div>939 </div>
870 )}940 )}